summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author Himanshu Arora <hmarora@google.com> 2025-02-24 18:28:29 +0000
committer Himanshu Arora <hmarora@google.com> 2025-03-06 06:23:43 +0000
commit4384797fe90b3f81c4a4bd51559356874d410e35 (patch)
treea7ed82de10accb34c4757c4011371a8fe0c2659b /src
parente7bc086e385da29c1b73d6400177485909a43be0 (diff)
Fix MIME type to extension issue in Android 15
In Android 15, some unsupported MIME types were introduced, causing incorrect extension selection for unsupported MIME types. This fix ensures that the correct extensions are assigned to these MIME types. Test: atest MimeTypeFixHandlerTest Test: atest PhotoPickerTest Flag: com.android.providers.media.flags.enable_mime_type_fix_for_android_15 Bug: 376910932 Bug: 397897311 Change-Id: Ib6c969b8a0b9c719b628c71309afc5bd0a498af0
Diffstat (limited to 'src')
-rw-r--r--src/com/android/providers/media/util/MimeTypeFixHandler.java60
-rw-r--r--src/com/android/providers/media/util/MimeUtils.java29
2 files changed, 80 insertions, 9 deletions
diff --git a/src/com/android/providers/media/util/MimeTypeFixHandler.java b/src/com/android/providers/media/util/MimeTypeFixHandler.java
index bf0aa535e..3a58bdcc8 100644
--- a/src/com/android/providers/media/util/MimeTypeFixHandler.java
+++ b/src/com/android/providers/media/util/MimeTypeFixHandler.java
@@ -44,7 +44,10 @@ public final class MimeTypeFixHandler {
private static final String TAG = "MimeTypeFixHandler";
private static final Map<String, String> sExtToMimeType = new HashMap<>();
+ private static final Map<String, String> sMimeTypeToExt = new HashMap<>();
+
private static final Map<String, String> sCorruptedExtToMimeType = new HashMap<>();
+ private static final Map<String, String> sCorruptedMimeTypeToExt = new HashMap<>();
/**
* Loads MIME type mappings from the classpath resource if not already loaded.
@@ -58,13 +61,14 @@ public final class MimeTypeFixHandler {
}
if (sExtToMimeType.isEmpty()) {
- parseTypes(context, R.raw.mime_types, sExtToMimeType);
+ parseTypes(context, R.raw.mime_types, sExtToMimeType, sMimeTypeToExt);
// this will add or override the extension to mime type mapping
- parseTypes(context, R.raw.android_mime_types, sExtToMimeType);
+ parseTypes(context, R.raw.android_mime_types, sExtToMimeType, sMimeTypeToExt);
Log.v(TAG, "MIME types loaded");
}
if (sCorruptedExtToMimeType.isEmpty()) {
- parseTypes(context, R.raw.corrupted_mime_types, sCorruptedExtToMimeType);
+ parseTypes(context, R.raw.corrupted_mime_types, sCorruptedExtToMimeType,
+ sCorruptedMimeTypeToExt);
Log.v(TAG, "Corrupted MIME types loaded");
}
@@ -77,7 +81,8 @@ public final class MimeTypeFixHandler {
* @param resource the mime.type resource
* @param mapping the map to populate with file extension (key) to MIME type (value) mappings
*/
- private static void parseTypes(Context context, int resource, Map<String, String> mapping) {
+ private static void parseTypes(Context context, int resource, Map<String, String> extToMimeType,
+ Map<String, String> mimeTypeToExt) {
try (InputStream inputStream = context.getResources().openRawResource(resource)) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
@@ -92,10 +97,24 @@ public final class MimeTypeFixHandler {
if (tokens.length < 2) {
continue;
}
- String mimeType = tokens[0];
+ String mimeType = tokens[0].toLowerCase(Locale.ROOT);
+ String firstExt = tokens[1].toLowerCase(Locale.ROOT);
+ if (firstExt.startsWith("?")) {
+ firstExt = firstExt.substring(1);
+ if (firstExt.isEmpty()) {
+ continue;
+ }
+ }
+
// ?mime ext1 ?ext2 ext3
if (mimeType.toLowerCase(Locale.ROOT).startsWith("?")) {
mimeType = mimeType.substring(1); // Remove the "?"
+ if (mimeType.isEmpty()) {
+ continue;
+ }
+ mimeTypeToExt.putIfAbsent(mimeType, firstExt);
+ } else {
+ mimeTypeToExt.put(mimeType, firstExt);
}
for (int i = 1; i < tokens.length; i++) {
@@ -103,11 +122,9 @@ public final class MimeTypeFixHandler {
boolean putIfAbsent = extension.startsWith("?");
if (putIfAbsent) {
extension = extension.substring(1); // Remove the "?"
- if (!mapping.containsKey(extension)) {
- mapping.put(extension, mimeType);
- }
+ extToMimeType.putIfAbsent(extension, mimeType);
} else {
- mapping.put(extension, mimeType);
+ extToMimeType.put(extension, mimeType);
}
}
}
@@ -139,6 +156,31 @@ public final class MimeTypeFixHandler {
return Optional.empty();
}
+ /**
+ * Gets file extension from MIME type.
+ *
+ * @param mimeType The MIME type.
+ * @return Optional file extension, or empty.
+ */
+ static Optional<String> getExtFromMimeType(String mimeType) {
+ mimeType = mimeType.toLowerCase(Locale.ROOT);
+ return Optional.ofNullable(sMimeTypeToExt.get(mimeType));
+ }
+
+ /**
+ * Checks if a MIME type is corrupted.
+ *
+ * @param mimeType The MIME type.
+ * @return {@code true} if corrupted, {@code false} otherwise.
+ */
+ static boolean isCorruptedMimeType(String mimeType) {
+ if (sMimeTypeToExt.containsKey(mimeType)) {
+ return false;
+ }
+
+ return sCorruptedMimeTypeToExt.containsKey(mimeType);
+ }
+
/**
* Scans the database for files with unsupported or mismatched MIME types and updates them.
diff --git a/src/com/android/providers/media/util/MimeUtils.java b/src/com/android/providers/media/util/MimeUtils.java
index 354ceb193..5698a83aa 100644
--- a/src/com/android/providers/media/util/MimeUtils.java
+++ b/src/com/android/providers/media/util/MimeUtils.java
@@ -276,6 +276,11 @@ public class MimeUtils {
*/
@NonNull
public static String getExtensionFromMimeType(@Nullable String mimeType) {
+ Optional<String> android15Extension = getExtFromMimeTypeForAndroid15(mimeType);
+ if (android15Extension.isPresent()) {
+ return android15Extension.get();
+ }
+
final String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
if (extension != null) {
return "." + extension;
@@ -302,4 +307,28 @@ public class MimeUtils {
}
return Optional.empty();
}
+
+ /**
+ * Gets file extension from MIME type for Android 15.
+ * Handles Android 15 specific MIME type to extension mapping. If the mime-type is corrupted,
+ * then return the default one with respect to mime type.
+ *
+ * @param mimeType The MIME type.
+ * @return Optional file extension (with dot), or empty.
+ */
+ private static Optional<String> getExtFromMimeTypeForAndroid15(String mimeType) {
+ if (Flags.enableMimeTypeFixForAndroid15()
+ && Build.VERSION.SDK_INT == Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ Optional<String> value = MimeTypeFixHandler.getExtFromMimeType(mimeType);
+ if (value.isPresent()) {
+ return Optional.of("." + value.get());
+ } else if (MimeTypeFixHandler.isCorruptedMimeType(mimeType)) {
+ if (isImageMimeType(mimeType)) return Optional.of(DEFAULT_IMAGE_FILE_EXTENSION);
+ if (isVideoMimeType(mimeType)) return Optional.of(DEFAULT_VIDEO_FILE_EXTENSION);
+ return Optional.of("");
+ }
+ }
+ return Optional.empty();
+ }
+
}