diff options
author | 2025-03-06 00:31:47 -0800 | |
---|---|---|
committer | 2025-03-06 00:31:47 -0800 | |
commit | 1127c069aeacd1d63c1a047791eaeb2aa682ad2b (patch) | |
tree | 1271d8994e1bffccd3cd58ad219bfc1952bb1562 /src | |
parent | 5e6a7ccd069497df4f3dfe2bfd6041f689cc28fc (diff) | |
parent | 4384797fe90b3f81c4a4bd51559356874d410e35 (diff) |
Merge "Fix MIME type to extension issue in Android 15" into main
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(); + } + } |