/* * Copyright (C) 2012 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cyanogenmod.filemanager.util; import android.content.Context; import android.content.res.Resources; import android.text.TextUtils; import android.util.Log; import com.cyanogenmod.filemanager.R; import com.cyanogenmod.filemanager.model.BlockDevice; import com.cyanogenmod.filemanager.model.CharacterDevice; import com.cyanogenmod.filemanager.model.Directory; import com.cyanogenmod.filemanager.model.DomainSocket; import com.cyanogenmod.filemanager.model.FileSystemObject; import com.cyanogenmod.filemanager.model.NamedPipe; import com.cyanogenmod.filemanager.model.Symlink; import com.cyanogenmod.filemanager.model.SystemFile; import java.io.File; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; /** * A helper class with useful methods for deal with mime types. */ public final class MimeTypeHelper { /** * Enumeration of mime/type' categories */ public enum MimeTypeCategory { /** * No category */ NONE, /** * System file */ SYSTEM, /** * Application, Installer, ... */ APP, /** * Binary file */ BINARY, /** * Text file */ TEXT, /** * Document file (text, spreedsheet, presentation, pdf, ...) */ DOCUMENT, /** * e-Book file */ EBOOK, /** * Mail file (email, message, contact, calendar, ...) */ MAIL, /** * Compressed file */ COMPRESS, /** * Executable file */ EXEC, /** * Database file */ DATABASE, /** * Font file */ FONT, /** * Image file */ IMAGE, /** * Audio file */ AUDIO, /** * Video file */ VIDEO, /** * Security file (certificate, keys, ...) */ SECURITY } /** * An internal class for holding the mime/type database structure */ private static class MimeTypeInfo { MimeTypeInfo() {/**NON BLOCK**/} public MimeTypeCategory mCategory; public String mMimeType; public String mDrawable; /** * {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((this.mCategory == null) ? 0 : this.mCategory.hashCode()); result = prime * result + ((this.mDrawable == null) ? 0 : this.mDrawable.hashCode()); result = prime * result + ((this.mMimeType == null) ? 0 : this.mMimeType.hashCode()); return result; } /** * {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MimeTypeInfo other = (MimeTypeInfo) obj; if (this.mCategory != other.mCategory) return false; if (this.mDrawable == null) { if (other.mDrawable != null) return false; } else if (!this.mDrawable.equals(other.mDrawable)) return false; if (this.mMimeType == null) { if (other.mMimeType != null) return false; } else if (!this.mMimeType.equals(other.mMimeType)) return false; return true; } /** * {@inheritDoc} */ @Override public String toString() { return "MimeTypeInfo [mCategory=" + this.mCategory + //$NON-NLS-1$ ", mMimeType="+ this.mMimeType + //$NON-NLS-1$ ", mDrawable=" + this.mDrawable + "]"; //$NON-NLS-1$ //$NON-NLS-2$ } } private static final String TAG = "MimeTypeHelper"; //$NON-NLS-1$ /** * A constant that defines a string of all mime-types */ public static final String ALL_MIME_TYPES = "*/*"; //$NON-NLS-1$ private static Map<String, MimeTypeInfo> sMimeTypes; /** * Constructor of <code>MimeTypeHelper</code>. */ private MimeTypeHelper() { super(); } /** * Method that checks whether a certain mime type is known to * the application. * * @param context The current context * @param mimeType The mime type to be checked * @return true if mime type is known, false otherwise */ public static final boolean isMimeTypeKnown(Context context, String mimeType) { //Ensure that mime types are loaded if (sMimeTypes == null) { loadMimeTypes(context); } if (mimeType == null) { return false; } for (MimeTypeInfo info : sMimeTypes.values()) { String mimeTypeRegExp = convertToRegExp(mimeType); if (info.mMimeType.matches(mimeTypeRegExp)) { return true; } } return false; } /** * Method that returns the associated mime/type icon resource identifier of * the {@link FileSystemObject}. * * @param context The current context * @param fso The file system object * @return String The associated mime/type icon resource identifier */ public static final String getIcon(Context context, FileSystemObject fso) { //Ensure that mime types are loaded if (sMimeTypes == null) { loadMimeTypes(context); } // Return the symlink ref mime/type icon if (fso instanceof Symlink && ((Symlink) fso).getLinkRef() != null) { return getIcon(context, ((Symlink) fso).getLinkRef()); } //Check if the argument is a folder if (fso instanceof Directory) { return "ic_fso_folder_drawable"; //$NON-NLS-1$ } //Get the extension and delivery String ext = FileHelper.getExtension(fso); if (ext != null) { MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase()); if (mimeTypeInfo != null) { // Create a new drawable if (!TextUtils.isEmpty(mimeTypeInfo.mDrawable)) { return mimeTypeInfo.mDrawable; } // Something was wrong here. The resource should exist, but it's not present. // Audit the wrong mime/type resource and return the best fso drawable (probably // default) Log.w(TAG, String.format( "Something was wrong with the drawable of the fso:" + //$NON-NLS-1$ "%s, mime: %s", //$NON-NLS-1$ fso.toString(), mimeTypeInfo.toString())); } } // Check system file if (FileHelper.isSystemFile(fso)) { return "fso_type_system_drawable"; //$NON-NLS-1$ } // Check if the fso is executable (but not a symlink) if (fso.getPermissions() != null && !(fso instanceof Symlink)) { if (fso.getPermissions().getUser().isExecute() || fso.getPermissions().getGroup().isExecute() || fso.getPermissions().getOthers().isExecute()) { return "fso_type_executable_drawable"; //$NON-NLS-1$ } } return "ic_fso_default_drawable"; //$NON-NLS-1$ } /** * Method that returns the mime/type of the {@link FileSystemObject}. * * @param context The current context * @param fso The file system object * @return String The mime/type */ public static final String getMimeType(Context context, FileSystemObject fso) { //Ensure that mime types are loaded if (sMimeTypes == null) { loadMimeTypes(context); } //Get the extension and delivery String ext = FileHelper.getExtension(fso); if (ext != null) { //Load from the database of mime types MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase()); if (mimeTypeInfo != null) { return mimeTypeInfo.mMimeType; } } return null; } /** * Method that returns the mime/type description of the {@link FileSystemObject}. * * @param context The current context * @param fso The file system object * @return String The mime/type description */ public static final String getMimeTypeDescription(Context context, FileSystemObject fso) { Resources res = context.getResources(); //Ensure that mime types are loaded if (sMimeTypes == null) { loadMimeTypes(context); } //Check if the argument is a folder if (fso instanceof Directory) { return res.getString(R.string.mime_folder); } if (fso instanceof Symlink) { return res.getString(R.string.mime_symlink); } // System files if (fso instanceof BlockDevice || FileHelper.isSymlinkRefBlockDevice(fso)) { return context.getString(R.string.device_blockdevice); } if (fso instanceof CharacterDevice || FileHelper.isSymlinkRefCharacterDevice(fso)) { return context.getString(R.string.device_characterdevice); } if (fso instanceof NamedPipe || FileHelper.isSymlinkRefNamedPipe(fso)) { return context.getString(R.string.device_namedpipe); } if (fso instanceof DomainSocket || FileHelper.isSymlinkRefDomainSocket(fso)) { return context.getString(R.string.device_domainsocket); } //Get the extension and delivery String ext = FileHelper.getExtension(fso); if (ext != null) { //Load from the database of mime types MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase()); if (mimeTypeInfo != null) { return mimeTypeInfo.mMimeType; } } return res.getString(R.string.mime_unknown); } /** * Method that returns the mime/type category of the file. * * @param context The current context * @param ext The extension of the file * @return MimeTypeCategory The mime/type category */ public static final MimeTypeCategory getCategoryFromExt(Context context, String ext) { // Ensure that have a context if (context == null && sMimeTypes == null) { // No category return MimeTypeCategory.NONE; } //Ensure that mime types are loaded if (sMimeTypes == null) { loadMimeTypes(context); } if (ext != null) { //Load from the database of mime types MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase()); if (mimeTypeInfo != null) { return mimeTypeInfo.mCategory; } } // No category return MimeTypeCategory.NONE; } /** * Method that returns the mime/type category of the file. * * @param context The current context * @param file The file * @return MimeTypeCategory The mime/type category */ public static final MimeTypeCategory getCategory(Context context, File file) { // Ensure that have a context if (context == null && sMimeTypes == null) { // No category return MimeTypeCategory.NONE; } //Ensure that mime types are loaded if (sMimeTypes == null) { loadMimeTypes(context); } // Directory and Symlinks no computes as category if (file.isDirectory()) { return MimeTypeCategory.NONE; } //Get the extension and delivery String ext = FileHelper.getExtension(file.getName()); if (ext != null) { //Load from the database of mime types MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase()); if (mimeTypeInfo != null) { return mimeTypeInfo.mCategory; } } // No category return MimeTypeCategory.NONE; } /** * Method that returns the mime/type category of the file system object. * * @param context The current context * @param fso The file system object * @return MimeTypeCategory The mime/type category */ public static final MimeTypeCategory getCategory(Context context, FileSystemObject fso) { // Ensure that have a context if (context == null && sMimeTypes == null) { // No category return MimeTypeCategory.NONE; } //Ensure that mime types are loaded if (sMimeTypes == null) { loadMimeTypes(context); } // Directory and Symlinks no computes as category if (FileHelper.isDirectory(fso)) { return MimeTypeCategory.NONE; } if (fso instanceof Symlink) { return MimeTypeCategory.NONE; } //Get the extension and delivery String ext = FileHelper.getExtension(fso); if (ext != null) { //Load from the database of mime types MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase()); if (mimeTypeInfo != null) { return mimeTypeInfo.mCategory; } } // Check system file if (fso instanceof SystemFile) { return MimeTypeCategory.SYSTEM; } // No category return MimeTypeCategory.NONE; } /** * Method that returns the description of the category * * @param context The current context * @param category The category * @return String The description of the category */ public static final String getCategoryDescription( Context context, MimeTypeCategory category) { if (category == null || category.compareTo(MimeTypeCategory.NONE) == 0) { return "-"; //$NON-NLS-1$ } try { String id = "category_" + category.toString().toLowerCase(); //$NON-NLS-1$ int resid = ResourcesHelper.getIdentifier( context.getResources(), "string", id); //$NON-NLS-1$ return context.getString(resid); } catch (Throwable e) {/**NON BLOCK**/} return "-"; //$NON-NLS-1$ } /** * Method that returns if a file system object matches with a mime-type expression. * * @param ctx The current context * @param fso The file system object to check * @param mimeTypeExpression The mime-type expression (xe: */*, audio/*) * @return boolean If the file system object matches the mime-type expression */ public static final boolean matchesMimeType( Context ctx, FileSystemObject fso, String mimeTypeExpression) { String mimeType = getMimeType(ctx, fso); if (mimeType == null) return false; return mimeType.matches(convertToRegExp(mimeTypeExpression)); } /** * Method that loads the mime type information. * * @param context The current context */ //IMP! This must be invoked from the main activity creation public static synchronized void loadMimeTypes(Context context) { if (sMimeTypes == null) { try { // Load the mime/type database Properties mimeTypes = new Properties(); mimeTypes.load(context.getResources().openRawResource(R.raw.mime_types)); // Parse the properties to an in-memory structure // Format: <extension> = <category> | <mime type> | <drawable> sMimeTypes = new HashMap<String, MimeTypeInfo>(mimeTypes.size()); Enumeration<Object> e = mimeTypes.keys(); while (e.hasMoreElements()) { try { String extension = (String)e.nextElement(); String data = mimeTypes.getProperty(extension); String[] mimeData = data.split("\\|"); //$NON-NLS-1$ // Create a reference of MimeType MimeTypeInfo mimeTypeInfo = new MimeTypeInfo(); mimeTypeInfo.mCategory = MimeTypeCategory.valueOf(mimeData[0].trim()); mimeTypeInfo.mMimeType = mimeData[1].trim(); mimeTypeInfo.mDrawable = mimeData[2].trim(); sMimeTypes.put(extension, mimeTypeInfo); } catch (Exception e2) { /**NON BLOCK**/} } } catch (Exception e) { Log.e(TAG, "Fail to load mime types raw file.", e); //$NON-NLS-1$ } } } /** * Method that converts the mime-type expression to a regular expression * * @param mimeTypeExpression The mime-type expression * @return String The regular expression */ private static String convertToRegExp(String mimeTypeExpression) { return mimeTypeExpression.replaceAll("\\*", ".\\*"); //$NON-NLS-1$ //$NON-NLS-2$ } }