aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Garnes <matt@cyngn.com>2015-03-23 17:52:59 -0700
committerMatt Garnes <matt@cyngn.com>2015-03-26 17:26:33 +0000
commit6e039982eb0d6f8bc39d8690f67b2622ec1efcb0 (patch)
tree38ffa8a94ca22bdc860fe7ed8f904f675d7ddd23
parent1288edb9bc0b752d157af7f17d00de52bcf61652 (diff)
downloadandroid_packages_apps_CMFileManager-6e039982eb0d6f8bc39d8690f67b2622ec1efcb0.tar.gz
android_packages_apps_CMFileManager-6e039982eb0d6f8bc39d8690f67b2622ec1efcb0.tar.bz2
android_packages_apps_CMFileManager-6e039982eb0d6f8bc39d8690f67b2622ec1efcb0.zip
Support ambigous file extension mimetypes.
Previously, CMFileManager operated under the assumption that file extensions map to exactly one mimetype. This is not true in some cases, such as .3gp files, which can have an audio or video mimetype. Add support so that in mime_types.properties we can specify a comma separated list of mimetype info that are matched with a given extension. If an AmbiguousExtensionHelper subclass implementation is provided for one of these extensions, this is used to determine the correct mimetype for the file. Change-Id: Ie73d6ad646692dfeac112ac50c1c6436e6b5559b
-rw-r--r--res/raw/mime_types.properties14
-rw-r--r--src/com/cyanogenmod/filemanager/activities/SearchActivity.java7
-rw-r--r--src/com/cyanogenmod/filemanager/commands/java/FolderUsageCommand.java7
-rw-r--r--src/com/cyanogenmod/filemanager/commands/secure/FolderUsageCommand.java9
-rw-r--r--src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommand.java6
-rw-r--r--src/com/cyanogenmod/filemanager/util/AmbiguousExtensionHelper.java86
-rw-r--r--src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java127
7 files changed, 226 insertions, 30 deletions
diff --git a/res/raw/mime_types.properties b/res/raw/mime_types.properties
index 98e4924e..446918a7 100644
--- a/res/raw/mime_types.properties
+++ b/res/raw/mime_types.properties
@@ -274,10 +274,6 @@ qcp = AUDIO | audio/qcelp | fso_type_audio_drawable
xmf = AUDIO | audio/xmf | fso_type_audio_drawable
# Video
-3gp = VIDEO | video/3gpp | fso_type_video_drawable
-3gpp = VIDEO | video/3gpp | fso_type_video_drawable
-3g2 = VIDEO | video/3gpp2 | fso_type_video_drawable
-3gpp2 = VIDEO | video/3gpp2 | fso_type_video_drawable
h261 = VIDEO | video/h261 | fso_type_video_drawable
h263 = VIDEO | video/h263 | fso_type_video_drawable
h264 = VIDEO | video/h264 | fso_type_video_drawable
@@ -322,6 +318,16 @@ m4v = VIDEO | video/x-m4v | fso_type_video_drawable
divx = VIDEO | video/divx | fso_type_video_drawable
ts = VIDEO | video/MP2T | fso_type_video_drawable
+# Audio and Video
+3gp = VIDEO | video/3gpp | fso_type_video_drawable,\
+ AUDIO | audio/3gpp | fso_type_audio_drawable
+3gpp = VIDEO | video/3gpp | fso_type_video_drawable,\
+ AUDIO | audio/3gpp | fso_type_audio_drawable
+3g2 = VIDEO | video/3gpp2 | fso_type_video_drawable,\
+ AUDIO | audio/3gpp2 | fso_type_audio_drawable
+3gpp2 = VIDEO | video/3gpp2 | fso_type_video_drawable,\
+ AUDIO | audio/3gpp2 | fso_type_audio_drawable
+
# Security
asc = SECURITY | application/pgp-signature | fso_type_security_drawable
cer = SECURITY | application/pkix-cert | fso_type_security_drawable
diff --git a/src/com/cyanogenmod/filemanager/activities/SearchActivity.java b/src/com/cyanogenmod/filemanager/activities/SearchActivity.java
index 615e6cee..f89c2ee4 100644
--- a/src/com/cyanogenmod/filemanager/activities/SearchActivity.java
+++ b/src/com/cyanogenmod/filemanager/activities/SearchActivity.java
@@ -1025,7 +1025,7 @@ public class SearchActivity extends Activity
// all of the video files in the current search will also be sent as an extra in the
// intent along with the item that was clicked
MimeTypeCategory fileCategory = MimeTypeHelper.getCategoryFromExt(this,
- FileHelper.getExtension(fso));
+ FileHelper.getExtension(fso), fso.getFullPath());
if (fileCategory == MimeTypeCategory.VIDEO) {
ArrayList<FileSystemObject> filteredList = filterSearchResults(fileCategory);
@@ -1075,8 +1075,9 @@ public class SearchActivity extends Activity
if (mAdapter.getCount() < 1) return filteredList;
for (FileSystemObject fso : mAdapter.getFiles()) {
- if (MimeTypeHelper.getCategoryFromExt(this, FileHelper.getExtension(fso))
- == category) {
+ if (MimeTypeHelper.getCategoryFromExt(this,
+ FileHelper.getExtension(fso),
+ fso.getFullPath()) == category) {
filteredList.add(fso);
}
}
diff --git a/src/com/cyanogenmod/filemanager/commands/java/FolderUsageCommand.java b/src/com/cyanogenmod/filemanager/commands/java/FolderUsageCommand.java
index c201dfbd..d15c5dcd 100644
--- a/src/com/cyanogenmod/filemanager/commands/java/FolderUsageCommand.java
+++ b/src/com/cyanogenmod/filemanager/commands/java/FolderUsageCommand.java
@@ -24,6 +24,7 @@ import com.cyanogenmod.filemanager.console.ExecutionException;
import com.cyanogenmod.filemanager.console.InsufficientPermissionsException;
import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory;
import com.cyanogenmod.filemanager.model.FolderUsage;
+import com.cyanogenmod.filemanager.util.FileHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory;
@@ -149,8 +150,12 @@ public class FolderUsageCommand extends Program implements FolderUsageExecutable
} else {
this.mFolderUsage.addFile();
// Compute statistics and size
+ File file = files[i];
+ String ext = FileHelper.getExtension(file.getName());
MimeTypeCategory category =
- MimeTypeHelper.getCategory(null, files[i]);
+ MimeTypeHelper.getCategoryFromExt(null,
+ ext,
+ file.getAbsolutePath());
this.mFolderUsage.addFileToCategory(category);
this.mFolderUsage.addSize(files[i].length());
}
diff --git a/src/com/cyanogenmod/filemanager/commands/secure/FolderUsageCommand.java b/src/com/cyanogenmod/filemanager/commands/secure/FolderUsageCommand.java
index 5049a01a..ad5412ed 100644
--- a/src/com/cyanogenmod/filemanager/commands/secure/FolderUsageCommand.java
+++ b/src/com/cyanogenmod/filemanager/commands/secure/FolderUsageCommand.java
@@ -24,11 +24,14 @@ import com.cyanogenmod.filemanager.console.ExecutionException;
import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory;
import com.cyanogenmod.filemanager.console.secure.SecureConsole;
import com.cyanogenmod.filemanager.model.FolderUsage;
+import com.cyanogenmod.filemanager.util.FileHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory;
import de.schlichtherle.truezip.file.TFile;
+import java.io.File;
+
/**
* A class for retrieve the disk usage of a folder.
*/
@@ -149,8 +152,12 @@ public class FolderUsageCommand extends Program implements FolderUsageExecutable
} else {
this.mFolderUsage.addFile();
// Compute statistics and size
+ File file = files[i];
+ String ext = FileHelper.getExtension(file.getName());
MimeTypeCategory category =
- MimeTypeHelper.getCategory(null, files[i]);
+ MimeTypeHelper.getCategoryFromExt(null,
+ ext,
+ file.getAbsolutePath());
this.mFolderUsage.addFileToCategory(category);
this.mFolderUsage.addSize(files[i].length());
}
diff --git a/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommand.java
index 6555381e..134a3e34 100644
--- a/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommand.java
+++ b/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommand.java
@@ -36,6 +36,7 @@ import com.cyanogenmod.filemanager.util.MimeTypeHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory;
import java.io.BufferedReader;
+import java.io.File;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
@@ -174,8 +175,11 @@ public class FolderUsageCommand extends AsyncResultProgram implements FolderUsag
long size = Long.parseLong(fields[4]);
String name = fields[fields.length-1];// We only need the extension
String ext = FileHelper.getExtension(name);
+ File file = new File(mDirectory, name);
MimeTypeCategory category =
- MimeTypeHelper.getCategoryFromExt(null, ext);
+ MimeTypeHelper.getCategoryFromExt(null,
+ ext,
+ file.getAbsolutePath());
this.mFolderUsage.addFile();
this.mFolderUsage.addFileToCategory(category);
this.mFolderUsage.addSize(size);
diff --git a/src/com/cyanogenmod/filemanager/util/AmbiguousExtensionHelper.java b/src/com/cyanogenmod/filemanager/util/AmbiguousExtensionHelper.java
new file mode 100644
index 00000000..567ae5de
--- /dev/null
+++ b/src/com/cyanogenmod/filemanager/util/AmbiguousExtensionHelper.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 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.media.MediaMetadataRetriever;
+import java.util.HashMap;
+
+/**
+ * Provides the ability to determine the mimetype of a known file extension that can support
+ * multiple mimetypes.
+ */
+public abstract class AmbiguousExtensionHelper {
+ /**
+ * All available ambiguous extension helpers.
+ */
+ public static final HashMap<String, AmbiguousExtensionHelper> AMBIGUOUS_EXTENSIONS_MAP = new
+ HashMap<String, AmbiguousExtensionHelper>();
+
+ static {
+ addAmbiguousHelperToMap(new ThreeGPExtensionHelper());
+ }
+
+ public abstract String getMimeType(String absolutePath, String extension);
+ public abstract String[] getSupportedExtensions();
+
+ private static void addAmbiguousHelperToMap(AmbiguousExtensionHelper instance) {
+ for(String extension : instance.getSupportedExtensions()) {
+ AmbiguousExtensionHelper.AMBIGUOUS_EXTENSIONS_MAP.put(extension, instance);
+ }
+ }
+
+ /**
+ * An AmbiguousExtensionHelper subclass that can distinguish the mimetype of a given
+ * .g3p, .g3pp, .3g2 or .3gpp2 file. The 3GP and 3G2 file formats support both audio and
+ * video, and a file with that extension has the possibility of multiple mimetypes, depending
+ * on the content of the file.
+ */
+ public static class ThreeGPExtensionHelper extends AmbiguousExtensionHelper {
+ private static final String[] sSupportedExtensions = {"3gp", "3gpp", "3g2", "3gpp2"};
+ public static final String VIDEO_3GPP_MIME_TYPE = "video/3gpp";
+ public static final String AUDIO_3GPP_MIME_TYPE = "audio/3gpp";
+ public static final String VIDEO_3GPP2_MIME_TYPE = "video/3gpp2";
+ public static final String AUDIO_3GPP2_MIME_TYPE = "audio/3gpp2";
+
+ @Override
+ public String getMimeType(String absolutePath, String extension) {
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ retriever.setDataSource(absolutePath);
+ boolean hasVideo =
+ retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO) != null;
+ if (is3GPP(extension)) {
+ return hasVideo ? VIDEO_3GPP_MIME_TYPE : AUDIO_3GPP_MIME_TYPE;
+ } else if (is3GPP2(extension)) {
+ return hasVideo ? VIDEO_3GPP2_MIME_TYPE : AUDIO_3GPP2_MIME_TYPE;
+ }
+ return null;
+ }
+
+ @Override
+ public String[] getSupportedExtensions() {
+ return sSupportedExtensions;
+ }
+
+ private boolean is3GPP(String ext) {
+ return "3gp".equals(ext) || "3gpp".equals(ext);
+ }
+
+ private boolean is3GPP2(String ext) {
+ return "3g2".equals(ext) || "3gpp2".equals(ext);
+ }
+ }
+}
diff --git a/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java b/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java
index 34563db1..36874626 100644
--- a/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java
+++ b/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java
@@ -33,6 +33,7 @@ import com.cyanogenmod.filemanager.model.Symlink;
import com.cyanogenmod.filemanager.model.SystemFile;
import java.io.File;
+import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
@@ -212,7 +213,11 @@ public final class MimeTypeHelper {
*/
public static final String ALL_MIME_TYPES = "*/*"; //$NON-NLS-1$
- private static Map<String, MimeTypeInfo> sMimeTypes;
+ private static Map<String, ArrayList<MimeTypeInfo>> sMimeTypes;
+ /**
+ * Maps from a combination key of <extension> + <mimetype> to MimeTypeInfo objects.
+ */
+ private static HashMap<String, MimeTypeInfo> sExtensionMimeTypes;
/**
* Constructor of <code>MimeTypeHelper</code>.
@@ -239,10 +244,12 @@ public final class MimeTypeHelper {
return false;
}
- for (MimeTypeInfo info : sMimeTypes.values()) {
- String mimeTypeRegExp = convertToRegExp(mimeType);
- if (info.mMimeType.matches(mimeTypeRegExp)) {
- return true;
+ for (ArrayList<MimeTypeInfo> mimeTypeInfoList : sMimeTypes.values()) {
+ for (MimeTypeInfo info : mimeTypeInfoList) {
+ String mimeTypeRegExp = convertToRegExp(mimeType);
+ if (info.mMimeType.matches(mimeTypeRegExp)) {
+ return true;
+ }
}
}
@@ -281,7 +288,8 @@ public final class MimeTypeHelper {
//Get the extension and delivery
String ext = FileHelper.getExtension(fso);
if (ext != null) {
- MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase(Locale.ROOT));
+ MimeTypeInfo mimeTypeInfo = getMimeTypeInternal(fso, ext);
+
if (mimeTypeInfo != null) {
// Create a new drawable
if (!TextUtils.isEmpty(mimeTypeInfo.mDrawable)) {
@@ -398,14 +406,74 @@ public final class MimeTypeHelper {
return res.getString(R.string.mime_unknown);
}
+ /**
+ * Gets the mimetype of a file, if there are multiple possibilities given it's extension.
+ * @param absolutePath The absolute path of the file for which to find the mimetype.
+ * @param ext The extension of the file.
+ * @return The correct mimetype for this file, or null if the mimetype cannot be determined
+ * or is not ambiguous.
+ */
+ private static final String getAmbiguousExtensionMimeType(String absolutePath, String ext) {
+ if (AmbiguousExtensionHelper.AMBIGUOUS_EXTENSIONS_MAP.containsKey(ext)) {
+ AmbiguousExtensionHelper helper =
+ AmbiguousExtensionHelper.AMBIGUOUS_EXTENSIONS_MAP.get(ext);
+ String mimeType = helper.getMimeType(absolutePath, ext);
+ if (!TextUtils.isEmpty(mimeType)) {
+ return mimeType;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the MimeTypeInfo that describes this file.
+ * @param fso The file.
+ * @param ext The extension of the file.
+ * @return The MimeTypeInfo object that describes this file, or null if it cannot be retrieved.
+ */
+ private static final MimeTypeInfo getMimeTypeInternal(FileSystemObject fso, String ext) {
+ return getMimeTypeInternal(fso.getFullPath(), ext);
+ }
+ /**
+ * Get the MimeTypeInfo that describes this file.
+ * @param absolutePath The absolute path of the file.
+ * @param ext The extension of the file.
+ * @return The MimeTypeInfo object that describes this file, or null if it cannot be retrieved.
+ */
+ private static final MimeTypeInfo getMimeTypeInternal(String absolutePath, String ext) {
+ MimeTypeInfo mimeTypeInfo = null;
+ ArrayList<MimeTypeInfo> mimeTypeInfoList = sMimeTypes.get(ext.toLowerCase(Locale.ROOT));
+ // Multiple mimetypes map to the same extension, try to resolve it.
+ if (mimeTypeInfoList != null && mimeTypeInfoList.size() > 1) {
+ if (absolutePath != null) {
+ String mimeType = getAmbiguousExtensionMimeType(absolutePath, ext);
+ mimeTypeInfo = sExtensionMimeTypes.get(ext + mimeType);
+ } else {
+ // We don't have the ability to read the file to resolve the ambiguity,
+ // so default to the first available mimetype.
+ mimeTypeInfo = mimeTypeInfoList.get(0);
+ }
+ } else if (mimeTypeInfoList != null && mimeTypeInfoList.size() == 1) {
+ // Only one possible mimetype, so pick that one.
+ mimeTypeInfo = mimeTypeInfoList.get(0);
+ }
+ return mimeTypeInfo;
+ }
+
private static final String getMimeTypeFromExtension(final FileSystemObject fso) {
String ext = FileHelper.getExtension(fso);
if (ext == null) {
return null;
}
+ // If this extension is ambiguous, attempt to resolve it.
+ String mimeType = getAmbiguousExtensionMimeType(fso.getFullPath(), ext);
+ if (mimeType != null) {
+ return mimeType;
+ }
+
//Load from the database of mime types
- MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase(Locale.ROOT));
+ MimeTypeInfo mimeTypeInfo = getMimeTypeInternal(fso, ext);
if (mimeTypeInfo == null) {
return null;
}
@@ -418,9 +486,11 @@ public final class MimeTypeHelper {
*
* @param context The current context
* @param ext The extension of the file
+ * @param absolutePath The absolute path of the file. Can be null if not available.
* @return MimeTypeCategory The mime/type category
*/
- public static final MimeTypeCategory getCategoryFromExt(Context context, String ext) {
+ public static final MimeTypeCategory getCategoryFromExt(Context context, String ext,
+ String absolutePath) {
// Ensure that have a context
if (context == null && sMimeTypes == null) {
// No category
@@ -432,7 +502,7 @@ public final class MimeTypeHelper {
}
if (ext != null) {
//Load from the database of mime types
- MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase(Locale.ROOT));
+ MimeTypeInfo mimeTypeInfo = getMimeTypeInternal(absolutePath, ext);
if (mimeTypeInfo != null) {
return mimeTypeInfo.mCategory;
}
@@ -466,7 +536,9 @@ public final class MimeTypeHelper {
}
//Get the extension and delivery
- return getCategoryFromExt(context, FileHelper.getExtension(file.getName()));
+ return getCategoryFromExt(context,
+ FileHelper.getExtension(file.getName()),
+ file.getAbsolutePath());
}
/**
@@ -497,7 +569,7 @@ public final class MimeTypeHelper {
//Get the extension and delivery
final MimeTypeCategory category = getCategoryFromExt(context,
- FileHelper.getExtension(fso));
+ FileHelper.getExtension(fso), fso.getFullPath());
// Check system file
if (category == MimeTypeCategory.NONE && fso instanceof SystemFile) {
@@ -558,20 +630,35 @@ public final class MimeTypeHelper {
// Parse the properties to an in-memory structure
// Format: <extension> = <category> | <mime type> | <drawable>
- sMimeTypes = new HashMap<String, MimeTypeInfo>(mimeTypes.size());
+ sMimeTypes = new HashMap<String, ArrayList<MimeTypeInfo>>();
+ sExtensionMimeTypes = new HashMap<String, MimeTypeInfo>();
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);
+ String[] datas = data.split(",");
+ for (String theData : datas) {
+ String[] mimeData = theData.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();
+
+ // If no list exists yet for this mimetype, create one.
+ // Else, add it to the existing list.
+ if (sMimeTypes.get(extension) == null) {
+ ArrayList<MimeTypeInfo> infoList = new ArrayList<MimeTypeInfo>();
+ infoList.add(mimeTypeInfo);
+ sMimeTypes.put(extension, infoList);
+ } else {
+ sMimeTypes.get(extension).add(mimeTypeInfo);
+ }
+ sExtensionMimeTypes.put(extension + mimeTypeInfo.mMimeType,
+ mimeTypeInfo);
+ }
} catch (Exception e2) { /**NON BLOCK**/}
}