diff options
author | 2025-02-24 18:28:29 +0000 | |
---|---|---|
committer | 2025-03-06 06:23:43 +0000 | |
commit | 4384797fe90b3f81c4a4bd51559356874d410e35 (patch) | |
tree | a7ed82de10accb34c4757c4011371a8fe0c2659b /src | |
parent | e7bc086e385da29c1b73d6400177485909a43be0 (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.java | 60 | ||||
-rw-r--r-- | src/com/android/providers/media/util/MimeUtils.java | 29 |
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(); + } + } |