diff options
9 files changed, 472 insertions, 378 deletions
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 5867a9c8890e..3bfb1c55fed6 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -437,6 +437,12 @@ public abstract class ContentResolver { */ public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*"; + /** + * Default MIME type for files whose type is otherwise unknown. + * @hide + */ + public static final String MIME_TYPE_DEFAULT = "application/octet-stream"; + /** @hide */ @UnsupportedAppUsage public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1; diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 3a3d9ea0b44f..1c8029caab70 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -23,6 +23,7 @@ import static android.system.OsConstants.S_ISREG; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.ContentResolver; import android.provider.DocumentsContract.Document; import android.system.ErrnoException; import android.system.Os; @@ -1057,7 +1058,7 @@ public class FileUtils { } if (mimeTypeFromExt == null) { - mimeTypeFromExt = "application/octet-stream"; + mimeTypeFromExt = ContentResolver.MIME_TYPE_DEFAULT; } final String extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType( diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index 0c6f832ff33a..b33a5c4ffb7d 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -74,10 +74,6 @@ public abstract class FileSystemProvider extends DocumentsProvider { private Handler mHandler; - private static final String MIMETYPE_JPEG = "image/jpeg"; - private static final String MIMETYPE_JPG = "image/jpg"; - private static final String MIMETYPE_OCTET_STREAM = "application/octet-stream"; - protected abstract File getFileForDocId(String docId, boolean visible) throws FileNotFoundException; @@ -433,7 +429,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { return mime; } } - return MIMETYPE_OCTET_STREAM; + return ContentResolver.MIME_TYPE_DEFAULT; } } diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index 3b9b6dd6d889..710b503d97fd 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -16,115 +16,41 @@ package android.media; +import static android.content.ContentResolver.MIME_TYPE_DEFAULT; + +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; -import android.media.DecoderCapabilities; -import android.media.DecoderCapabilities.VideoDecoder; -import android.media.DecoderCapabilities.AudioDecoder; import android.mtp.MtpConstants; -import com.android.internal.util.Preconditions; + +import libcore.net.MimeUtils; + import java.util.HashMap; -import java.util.List; -import java.util.Locale; /** * MediaScanner helper class. + * <p> + * This heavily relies upon extension to MIME type mappings which are maintained + * in {@link MimeUtils}, to ensure consistency across the OS. + * <p> + * When adding a new file type, first add the MIME type mapping to + * {@link MimeUtils}, and then add the MTP format mapping here. * - * {@hide} + * @hide */ public class MediaFile { - // Audio file types - public static final int FILE_TYPE_MP3 = 1; - public static final int FILE_TYPE_M4A = 2; - public static final int FILE_TYPE_WAV = 3; - public static final int FILE_TYPE_AMR = 4; - public static final int FILE_TYPE_AWB = 5; - public static final int FILE_TYPE_WMA = 6; - public static final int FILE_TYPE_OGG = 7; - public static final int FILE_TYPE_AAC = 8; - public static final int FILE_TYPE_MKA = 9; - public static final int FILE_TYPE_FLAC = 10; + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage - private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3; + private static final int FIRST_AUDIO_FILE_TYPE = 1; + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage - private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_FLAC; - - // MIDI file types - public static final int FILE_TYPE_MID = 11; - public static final int FILE_TYPE_SMF = 12; - public static final int FILE_TYPE_IMY = 13; - private static final int FIRST_MIDI_FILE_TYPE = FILE_TYPE_MID; - private static final int LAST_MIDI_FILE_TYPE = FILE_TYPE_IMY; - - // Video file types - public static final int FILE_TYPE_MP4 = 21; - public static final int FILE_TYPE_M4V = 22; - public static final int FILE_TYPE_3GPP = 23; - public static final int FILE_TYPE_3GPP2 = 24; - public static final int FILE_TYPE_WMV = 25; - public static final int FILE_TYPE_ASF = 26; - public static final int FILE_TYPE_MKV = 27; - public static final int FILE_TYPE_MP2TS = 28; - public static final int FILE_TYPE_AVI = 29; - public static final int FILE_TYPE_WEBM = 30; - private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4; - private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WEBM; - - // More video file types - public static final int FILE_TYPE_MP2PS = 200; - public static final int FILE_TYPE_QT = 201; - private static final int FIRST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS; - private static final int LAST_VIDEO_FILE_TYPE2 = FILE_TYPE_QT; - - // Image file types - public static final int FILE_TYPE_JPEG = 31; - public static final int FILE_TYPE_GIF = 32; - public static final int FILE_TYPE_PNG = 33; - public static final int FILE_TYPE_BMP = 34; - public static final int FILE_TYPE_WBMP = 35; - public static final int FILE_TYPE_WEBP = 36; - public static final int FILE_TYPE_HEIF = 37; - private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG; - private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_HEIF; - - // Raw image file types - public static final int FILE_TYPE_DNG = 300; - public static final int FILE_TYPE_CR2 = 301; - public static final int FILE_TYPE_NEF = 302; - public static final int FILE_TYPE_NRW = 303; - public static final int FILE_TYPE_ARW = 304; - public static final int FILE_TYPE_RW2 = 305; - public static final int FILE_TYPE_ORF = 306; - public static final int FILE_TYPE_RAF = 307; - public static final int FILE_TYPE_PEF = 308; - public static final int FILE_TYPE_SRW = 309; - private static final int FIRST_RAW_IMAGE_FILE_TYPE = FILE_TYPE_DNG; - private static final int LAST_RAW_IMAGE_FILE_TYPE = FILE_TYPE_SRW; - - // Playlist file types - public static final int FILE_TYPE_M3U = 41; - public static final int FILE_TYPE_PLS = 42; - public static final int FILE_TYPE_WPL = 43; - public static final int FILE_TYPE_HTTPLIVE = 44; - - private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U; - private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_HTTPLIVE; - - // Drm file types - public static final int FILE_TYPE_FL = 51; - private static final int FIRST_DRM_FILE_TYPE = FILE_TYPE_FL; - private static final int LAST_DRM_FILE_TYPE = FILE_TYPE_FL; - - // Other popular file types - public static final int FILE_TYPE_TEXT = 100; - public static final int FILE_TYPE_HTML = 101; - public static final int FILE_TYPE_PDF = 102; - public static final int FILE_TYPE_XML = 103; - public static final int FILE_TYPE_MS_WORD = 104; - public static final int FILE_TYPE_MS_EXCEL = 105; - public static final int FILE_TYPE_MS_POWERPOINT = 106; - public static final int FILE_TYPE_ZIP = 107; + private static final int LAST_AUDIO_FILE_TYPE = 10; + /** @deprecated file types no longer exist */ + @Deprecated public static class MediaFileType { @UnsupportedAppUsage public final int fileType; @@ -137,214 +63,178 @@ public class MediaFile { } } + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage - private static final HashMap<String, MediaFileType> sFileTypeMap - = new HashMap<String, MediaFileType>(); - private static final HashMap<String, Integer> sMimeTypeMap - = new HashMap<String, Integer>(); - // maps file extension to MTP format code + private static final HashMap<String, MediaFileType> sFileTypeMap = new HashMap<>(); + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage - private static final HashMap<String, Integer> sFileTypeToFormatMap - = new HashMap<String, Integer>(); + private static final HashMap<String, Integer> sFileTypeToFormatMap = new HashMap<>(); + // maps mime type to MTP format code @UnsupportedAppUsage - private static final HashMap<String, Integer> sMimeTypeToFormatMap - = new HashMap<String, Integer>(); + private static final HashMap<String, Integer> sMimeTypeToFormatMap = new HashMap<>(); // maps MTP format code to mime type @UnsupportedAppUsage - private static final HashMap<Integer, String> sFormatToMimeTypeMap - = new HashMap<Integer, String>(); + private static final HashMap<Integer, String> sFormatToMimeTypeMap = new HashMap<>(); + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage static void addFileType(String extension, int fileType, String mimeType) { - sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType)); - sMimeTypeMap.put(mimeType, Integer.valueOf(fileType)); } - private static void addFileType(String extension, int fileType, String mimeType, - int mtpFormatCode, boolean primaryType) { - addFileType(extension, fileType, mimeType); - sFileTypeToFormatMap.put(extension, Integer.valueOf(mtpFormatCode)); - sMimeTypeToFormatMap.put(mimeType, Integer.valueOf(mtpFormatCode)); - if (primaryType) { - Preconditions.checkArgument(!sFormatToMimeTypeMap.containsKey(mtpFormatCode)); - sFormatToMimeTypeMap.put(mtpFormatCode, mimeType); + private static void addFileType(int mtpFormatCode, @NonNull String mimeType) { + if (!sMimeTypeToFormatMap.containsKey(mimeType)) { + sMimeTypeToFormatMap.put(mimeType, Integer.valueOf(mtpFormatCode)); } - } - - private static boolean isWMAEnabled() { - List<AudioDecoder> decoders = DecoderCapabilities.getAudioDecoders(); - int count = decoders.size(); - for (int i = 0; i < count; i++) { - AudioDecoder decoder = decoders.get(i); - if (decoder == AudioDecoder.AUDIO_DECODER_WMA) { - return true; - } - } - return false; - } - - private static boolean isWMVEnabled() { - List<VideoDecoder> decoders = DecoderCapabilities.getVideoDecoders(); - int count = decoders.size(); - for (int i = 0; i < count; i++) { - VideoDecoder decoder = decoders.get(i); - if (decoder == VideoDecoder.VIDEO_DECODER_WMV) { - return true; - } + if (!sFormatToMimeTypeMap.containsKey(mtpFormatCode)) { + sFormatToMimeTypeMap.put(mtpFormatCode, mimeType); } - return false; } static { - addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg", MtpConstants.FORMAT_MP3, true); - addFileType("MPGA", FILE_TYPE_MP3, "audio/mpeg", MtpConstants.FORMAT_MP3, false); - addFileType("M4A", FILE_TYPE_M4A, "audio/mp4", MtpConstants.FORMAT_MPEG, false); - addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav", MtpConstants.FORMAT_WAV, true); - addFileType("AMR", FILE_TYPE_AMR, "audio/amr"); - addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb"); - if (isWMAEnabled()) { - addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma", MtpConstants.FORMAT_WMA, true); - } - addFileType("OGG", FILE_TYPE_OGG, "audio/ogg", MtpConstants.FORMAT_OGG, false); - addFileType("OGG", FILE_TYPE_OGG, "application/ogg", MtpConstants.FORMAT_OGG, true); - addFileType("OGA", FILE_TYPE_OGG, "application/ogg", MtpConstants.FORMAT_OGG, false); - addFileType("AAC", FILE_TYPE_AAC, "audio/aac", MtpConstants.FORMAT_AAC, true); - addFileType("AAC", FILE_TYPE_AAC, "audio/aac-adts", MtpConstants.FORMAT_AAC, false); - addFileType("MKA", FILE_TYPE_MKA, "audio/x-matroska"); - - addFileType("MID", FILE_TYPE_MID, "audio/midi"); - addFileType("MIDI", FILE_TYPE_MID, "audio/midi"); - addFileType("XMF", FILE_TYPE_MID, "audio/midi"); - addFileType("RTTTL", FILE_TYPE_MID, "audio/midi"); - addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi"); - addFileType("IMY", FILE_TYPE_IMY, "audio/imelody"); - addFileType("RTX", FILE_TYPE_MID, "audio/midi"); - addFileType("OTA", FILE_TYPE_MID, "audio/midi"); - addFileType("MXMF", FILE_TYPE_MID, "audio/midi"); - - addFileType("MPEG", FILE_TYPE_MP4, "video/mpeg", MtpConstants.FORMAT_MPEG, true); - addFileType("MPG", FILE_TYPE_MP4, "video/mpeg", MtpConstants.FORMAT_MPEG, false); - addFileType("MP4", FILE_TYPE_MP4, "video/mp4", MtpConstants.FORMAT_MPEG, false); - addFileType("M4V", FILE_TYPE_M4V, "video/mp4", MtpConstants.FORMAT_MPEG, false); - addFileType("MOV", FILE_TYPE_QT, "video/quicktime", MtpConstants.FORMAT_MPEG, false); - - addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp", MtpConstants.FORMAT_3GP_CONTAINER, true); - addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp", MtpConstants.FORMAT_3GP_CONTAINER, false); - addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2", MtpConstants.FORMAT_3GP_CONTAINER, false); - addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2", MtpConstants.FORMAT_3GP_CONTAINER, false); - addFileType("MKV", FILE_TYPE_MKV, "video/x-matroska"); - addFileType("WEBM", FILE_TYPE_WEBM, "video/webm"); - addFileType("TS", FILE_TYPE_MP2TS, "video/mp2ts"); - addFileType("AVI", FILE_TYPE_AVI, "video/avi"); - - if (isWMVEnabled()) { - addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv", MtpConstants.FORMAT_WMV, true); - addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf"); - } - - addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg", MtpConstants.FORMAT_EXIF_JPEG, true); - addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg", MtpConstants.FORMAT_EXIF_JPEG, false); - addFileType("GIF", FILE_TYPE_GIF, "image/gif", MtpConstants.FORMAT_GIF, true); - addFileType("PNG", FILE_TYPE_PNG, "image/png", MtpConstants.FORMAT_PNG, true); - addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp", MtpConstants.FORMAT_BMP, true); - addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp", MtpConstants.FORMAT_DEFINED, false); - addFileType("WEBP", FILE_TYPE_WEBP, "image/webp", MtpConstants.FORMAT_DEFINED, false); - addFileType("HEIC", FILE_TYPE_HEIF, "image/heif", MtpConstants.FORMAT_HEIF, true); - addFileType("HEIF", FILE_TYPE_HEIF, "image/heif", MtpConstants.FORMAT_HEIF, false); - - addFileType("DNG", FILE_TYPE_DNG, "image/x-adobe-dng", MtpConstants.FORMAT_DNG, true); - addFileType("CR2", FILE_TYPE_CR2, "image/x-canon-cr2", MtpConstants.FORMAT_TIFF, false); - addFileType("NEF", FILE_TYPE_NEF, "image/x-nikon-nef", MtpConstants.FORMAT_TIFF_EP, false); - addFileType("NRW", FILE_TYPE_NRW, "image/x-nikon-nrw", MtpConstants.FORMAT_TIFF, false); - addFileType("ARW", FILE_TYPE_ARW, "image/x-sony-arw", MtpConstants.FORMAT_TIFF, false); - addFileType("RW2", FILE_TYPE_RW2, "image/x-panasonic-rw2", MtpConstants.FORMAT_TIFF, false); - addFileType("ORF", FILE_TYPE_ORF, "image/x-olympus-orf", MtpConstants.FORMAT_TIFF, false); - addFileType("RAF", FILE_TYPE_RAF, "image/x-fuji-raf", MtpConstants.FORMAT_DEFINED, false); - addFileType("PEF", FILE_TYPE_PEF, "image/x-pentax-pef", MtpConstants.FORMAT_TIFF, false); - addFileType("SRW", FILE_TYPE_SRW, "image/x-samsung-srw", MtpConstants.FORMAT_TIFF, false); - - addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST, true); - addFileType("M3U", FILE_TYPE_M3U, "application/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST, false); - addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls", MtpConstants.FORMAT_PLS_PLAYLIST, true); - addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl", MtpConstants.FORMAT_WPL_PLAYLIST, true); - addFileType("M3U8", FILE_TYPE_HTTPLIVE, "application/vnd.apple.mpegurl"); - addFileType("M3U8", FILE_TYPE_HTTPLIVE, "audio/mpegurl"); - addFileType("M3U8", FILE_TYPE_HTTPLIVE, "audio/x-mpegurl"); - - addFileType("FL", FILE_TYPE_FL, "application/x-android-drm-fl"); - - addFileType("TXT", FILE_TYPE_TEXT, "text/plain", MtpConstants.FORMAT_TEXT, true); - addFileType("HTM", FILE_TYPE_HTML, "text/html", MtpConstants.FORMAT_HTML, true); - addFileType("HTML", FILE_TYPE_HTML, "text/html", MtpConstants.FORMAT_HTML, false); - addFileType("PDF", FILE_TYPE_PDF, "application/pdf"); - addFileType("DOC", FILE_TYPE_MS_WORD, "application/msword", MtpConstants.FORMAT_MS_WORD_DOCUMENT, true); - addFileType("XLS", FILE_TYPE_MS_EXCEL, "application/vnd.ms-excel", MtpConstants.FORMAT_MS_EXCEL_SPREADSHEET, true); - addFileType("PPT", FILE_TYPE_MS_POWERPOINT, "application/vnd.ms-powerpoint", MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION, true); - addFileType("FLAC", FILE_TYPE_FLAC, "audio/flac", MtpConstants.FORMAT_FLAC, true); - addFileType("ZIP", FILE_TYPE_ZIP, "application/zip"); - addFileType("MPG", FILE_TYPE_MP2PS, "video/mp2p"); - addFileType("MPEG", FILE_TYPE_MP2PS, "video/mp2p"); + addFileType(MtpConstants.FORMAT_MP3, "audio/mpeg"); + addFileType(MtpConstants.FORMAT_WAV, "audio/x-wav"); + addFileType(MtpConstants.FORMAT_WMA, "audio/x-ms-wma"); + addFileType(MtpConstants.FORMAT_OGG, "audio/ogg"); + addFileType(MtpConstants.FORMAT_AAC, "audio/aac"); + addFileType(MtpConstants.FORMAT_FLAC, "audio/flac"); + addFileType(MtpConstants.FORMAT_AIFF, "audio/x-aiff"); + addFileType(MtpConstants.FORMAT_MP2, "audio/mpeg"); + + addFileType(MtpConstants.FORMAT_MPEG, "video/mpeg"); + addFileType(MtpConstants.FORMAT_MP4_CONTAINER, "video/mp4"); + addFileType(MtpConstants.FORMAT_3GP_CONTAINER, "video/3gpp"); + addFileType(MtpConstants.FORMAT_3GP_CONTAINER, "video/3gpp2"); + addFileType(MtpConstants.FORMAT_AVI, "video/avi"); + addFileType(MtpConstants.FORMAT_WMV, "video/x-ms-wmv"); + addFileType(MtpConstants.FORMAT_ASF, "video/x-ms-asf"); + + addFileType(MtpConstants.FORMAT_EXIF_JPEG, "image/jpeg"); + addFileType(MtpConstants.FORMAT_GIF, "image/gif"); + addFileType(MtpConstants.FORMAT_PNG, "image/png"); + addFileType(MtpConstants.FORMAT_BMP, "image/x-ms-bmp"); + addFileType(MtpConstants.FORMAT_HEIF, "image/heif"); + addFileType(MtpConstants.FORMAT_DNG, "image/x-adobe-dng"); + addFileType(MtpConstants.FORMAT_TIFF, "image/tiff"); + addFileType(MtpConstants.FORMAT_TIFF, "image/x-canon-cr2"); + addFileType(MtpConstants.FORMAT_TIFF, "image/x-nikon-nrw"); + addFileType(MtpConstants.FORMAT_TIFF, "image/x-sony-arw"); + addFileType(MtpConstants.FORMAT_TIFF, "image/x-panasonic-rw2"); + addFileType(MtpConstants.FORMAT_TIFF, "image/x-olympus-orf"); + addFileType(MtpConstants.FORMAT_TIFF, "image/x-pentax-pef"); + addFileType(MtpConstants.FORMAT_TIFF, "image/x-samsung-srw"); + addFileType(MtpConstants.FORMAT_TIFF_EP, "image/tiff"); + addFileType(MtpConstants.FORMAT_TIFF_EP, "image/x-nikon-nef"); + addFileType(MtpConstants.FORMAT_JP2, "image/jp2"); + addFileType(MtpConstants.FORMAT_JPX, "image/jpx"); + + addFileType(MtpConstants.FORMAT_M3U_PLAYLIST, "audio/x-mpegurl"); + addFileType(MtpConstants.FORMAT_PLS_PLAYLIST, "audio/x-scpls"); + addFileType(MtpConstants.FORMAT_WPL_PLAYLIST, "application/vnd.ms-wpl"); + addFileType(MtpConstants.FORMAT_ASX_PLAYLIST, "video/x-ms-asf"); + + addFileType(MtpConstants.FORMAT_TEXT, "text/plain"); + addFileType(MtpConstants.FORMAT_HTML, "text/html"); + addFileType(MtpConstants.FORMAT_XML_DOCUMENT, "text/xml"); + + addFileType(MtpConstants.FORMAT_MS_WORD_DOCUMENT, + "application/msword"); + addFileType(MtpConstants.FORMAT_MS_WORD_DOCUMENT, + "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); + addFileType(MtpConstants.FORMAT_MS_EXCEL_SPREADSHEET, + "application/vnd.ms-excel"); + addFileType(MtpConstants.FORMAT_MS_EXCEL_SPREADSHEET, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + addFileType(MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION, + "application/vnd.ms-powerpoint"); + addFileType(MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION, + "application/vnd.openxmlformats-officedocument.presentationml.presentation"); } + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage public static boolean isAudioFileType(int fileType) { - return ((fileType >= FIRST_AUDIO_FILE_TYPE && - fileType <= LAST_AUDIO_FILE_TYPE) || - (fileType >= FIRST_MIDI_FILE_TYPE && - fileType <= LAST_MIDI_FILE_TYPE)); + return false; } + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage public static boolean isVideoFileType(int fileType) { - return (fileType >= FIRST_VIDEO_FILE_TYPE && - fileType <= LAST_VIDEO_FILE_TYPE) - || (fileType >= FIRST_VIDEO_FILE_TYPE2 && - fileType <= LAST_VIDEO_FILE_TYPE2); + return false; } + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage public static boolean isImageFileType(int fileType) { - return (fileType >= FIRST_IMAGE_FILE_TYPE && - fileType <= LAST_IMAGE_FILE_TYPE) - || (fileType >= FIRST_RAW_IMAGE_FILE_TYPE && - fileType <= LAST_RAW_IMAGE_FILE_TYPE); - } - - public static boolean isRawImageFileType(int fileType) { - return (fileType >= FIRST_RAW_IMAGE_FILE_TYPE && - fileType <= LAST_RAW_IMAGE_FILE_TYPE); + return false; } + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage public static boolean isPlayListFileType(int fileType) { - return (fileType >= FIRST_PLAYLIST_FILE_TYPE && - fileType <= LAST_PLAYLIST_FILE_TYPE); + return false; } + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage public static boolean isDrmFileType(int fileType) { - return (fileType >= FIRST_DRM_FILE_TYPE && - fileType <= LAST_DRM_FILE_TYPE); + return false; } + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage public static MediaFileType getFileType(String path) { - int lastDot = path.lastIndexOf('.'); - if (lastDot < 0) - return null; - return sFileTypeMap.get(path.substring(lastDot + 1).toUpperCase(Locale.ROOT)); + return null; + } + + public static boolean isExifMimeType(@Nullable String mimeType) { + // For simplicity, assume that all image files might have EXIF data + return isImageMimeType(mimeType); + } + + public static boolean isAudioMimeType(@Nullable String mimeType) { + return normalizeMimeType(mimeType).startsWith("audio/"); + } + + public static boolean isVideoMimeType(@Nullable String mimeType) { + return normalizeMimeType(mimeType).startsWith("video/"); + } + + public static boolean isImageMimeType(@Nullable String mimeType) { + return normalizeMimeType(mimeType).startsWith("image/"); } - public static boolean isMimeTypeMedia(String mimeType) { - int fileType = getFileTypeForMimeType(mimeType); - return isAudioFileType(fileType) || isVideoFileType(fileType) - || isImageFileType(fileType) || isPlayListFileType(fileType); + public static boolean isPlayListMimeType(@Nullable String mimeType) { + switch (normalizeMimeType(mimeType)) { + case "application/vnd.ms-wpl": + case "audio/x-mpegurl": + case "audio/mpegurl": + case "application/x-mpegurl": + case "application/vnd.apple.mpegurl": + case "video/x-ms-asf": + case "audio/x-scpls": + return true; + default: + return false; + } + } + + public static boolean isDrmMimeType(@Nullable String mimeType) { + return normalizeMimeType(mimeType).equals("application/x-android-drm-fl"); } // generates a title based on file name @UnsupportedAppUsage - public static String getFileTitle(String path) { + public static @NonNull String getFileTitle(@NonNull String path) { // extract file name after last slash int lastSlash = path.lastIndexOf('/'); if (lastSlash >= 0) { @@ -361,37 +251,111 @@ public class MediaFile { return path; } + public static @Nullable String getFileExtension(@Nullable String path) { + if (path == null) { + return null; + } + int lastDot = path.lastIndexOf('.'); + if (lastDot >= 0) { + return path.substring(lastDot + 1); + } else { + return null; + } + } + + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage public static int getFileTypeForMimeType(String mimeType) { - Integer value = sMimeTypeMap.get(mimeType); - return (value == null ? 0 : value.intValue()); + return 0; + } + + /** + * Find the best MIME type for the given item. Prefers mappings from file + * extensions, since they're more accurate than format codes. + */ + public static @NonNull String getMimeType(@Nullable String path, int formatCode) { + // First look for extension mapping + String mimeType = getMimeTypeForFile(path); + if (!MIME_TYPE_DEFAULT.equals(mimeType)) { + return mimeType; + } + + // Otherwise look for format mapping + return getMimeTypeForFormatCode(formatCode); } @UnsupportedAppUsage - public static String getMimeTypeForFile(String path) { - MediaFileType mediaFileType = getFileType(path); - return (mediaFileType == null ? null : mediaFileType.mimeType); + public static @NonNull String getMimeTypeForFile(@Nullable String path) { + final String mimeType = MimeUtils.guessMimeTypeFromExtension(getFileExtension(path)); + return (mimeType != null) ? mimeType : MIME_TYPE_DEFAULT; } - public static int getFormatCode(String fileName, String mimeType) { - if (mimeType != null) { - Integer value = sMimeTypeToFormatMap.get(mimeType); - if (value != null) { - return value.intValue(); - } + public static @NonNull String getMimeTypeForFormatCode(int formatCode) { + final String mimeType = sFormatToMimeTypeMap.get(formatCode); + return (mimeType != null) ? mimeType : MIME_TYPE_DEFAULT; + } + + /** + * Find the best MTP format code mapping for the given item. Prefers + * mappings from MIME types, since they're more accurate than file + * extensions. + */ + public static int getFormatCode(@Nullable String path, @Nullable String mimeType) { + // First look for MIME type mapping + int formatCode = getFormatCodeForMimeType(mimeType); + if (formatCode != MtpConstants.FORMAT_UNDEFINED) { + return formatCode; } - int lastDot = fileName.lastIndexOf('.'); - if (lastDot > 0) { - String extension = fileName.substring(lastDot + 1).toUpperCase(Locale.ROOT); - Integer value = sFileTypeToFormatMap.get(extension); - if (value != null) { - return value.intValue(); - } + + // Otherwise look for extension mapping + return getFormatCodeForFile(path); + } + + public static int getFormatCodeForFile(@Nullable String path) { + return getFormatCodeForMimeType(getMimeTypeForFile(path)); + } + + public static int getFormatCodeForMimeType(@Nullable String mimeType) { + if (mimeType == null) { + return MtpConstants.FORMAT_UNDEFINED; + } + + // First look for direct mapping + Integer value = sMimeTypeToFormatMap.get(mimeType); + if (value != null) { + return value.intValue(); + } + + // Otherwise look for indirect mapping + mimeType = normalizeMimeType(mimeType); + value = sMimeTypeToFormatMap.get(mimeType); + if (value != null) { + return value.intValue(); + } else if (mimeType.startsWith("audio/")) { + return MtpConstants.FORMAT_UNDEFINED_AUDIO; + } else if (mimeType.startsWith("video/")) { + return MtpConstants.FORMAT_UNDEFINED_VIDEO; + } else if (mimeType.startsWith("image/")) { + return MtpConstants.FORMAT_DEFINED; + } else { + return MtpConstants.FORMAT_UNDEFINED; } - return MtpConstants.FORMAT_UNDEFINED; } - public static String getMimeTypeForFormatCode(int formatCode) { - return sFormatToMimeTypeMap.get(formatCode); + /** + * Normalize the given MIME type by bouncing through a default file + * extension, if defined. This handles cases like "application/x-flac" to + * ".flac" to "audio/flac". + */ + private static @NonNull String normalizeMimeType(@Nullable String mimeType) { + final String extension = MimeUtils.guessExtensionFromMimeType(mimeType); + if (extension != null) { + final String extensionMimeType = MimeUtils.guessMimeTypeFromExtension(extension); + if ( extensionMimeType != null) { + return extensionMimeType; + } + } + return (mimeType != null) ? mimeType : MIME_TYPE_DEFAULT; } } diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index dcacb925b25b..0ff2d8f6b6ec 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -502,6 +502,8 @@ public class MediaScanner implements AutoCloseable { private String mGenre; @UnsupportedAppUsage private String mMimeType; + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage private int mFileType; private int mTrack; @@ -531,7 +533,6 @@ public class MediaScanner implements AutoCloseable { public FileEntry beginFile(String path, String mimeType, long lastModified, long fileSize, boolean isDirectory, boolean noMedia) { mMimeType = mimeType; - mFileType = 0; mFileSize = fileSize; mIsDrm = false; mScanSuccess = true; @@ -542,24 +543,13 @@ public class MediaScanner implements AutoCloseable { } mNoMedia = noMedia; - // try mimeType first, if it is specified - if (mimeType != null) { - mFileType = MediaFile.getFileTypeForMimeType(mimeType); - } - // if mimeType was not specified, compute file type based on file extension. - if (mFileType == 0) { - MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); - if (mediaFileType != null) { - mFileType = mediaFileType.fileType; - if (mMimeType == null) { - mMimeType = mediaFileType.mimeType; - } - } + if (mMimeType == null) { + mMimeType = MediaFile.getMimeTypeForFile(path); } - if (isDrmEnabled() && MediaFile.isDrmFileType(mFileType)) { - mFileType = getFileTypeFromDrm(path); + if (isDrmEnabled() && MediaFile.isDrmMimeType(mMimeType)) { + getMimeTypeFromDrm(path); } } @@ -578,7 +568,7 @@ public class MediaScanner implements AutoCloseable { entry.mLastModifiedChanged = true; } - if (mProcessPlaylists && MediaFile.isPlayListFileType(mFileType)) { + if (mProcessPlaylists && MediaFile.isPlayListMimeType(mMimeType)) { mPlayLists.add(entry); // we don't process playlists in the main scan, so return null return null; @@ -659,9 +649,9 @@ public class MediaScanner implements AutoCloseable { if (noMedia) { result = endFile(entry, false, false, false, false, false); } else { - boolean isaudio = MediaFile.isAudioFileType(mFileType); - boolean isvideo = MediaFile.isVideoFileType(mFileType); - boolean isimage = MediaFile.isImageFileType(mFileType); + boolean isaudio = MediaFile.isAudioMimeType(mMimeType); + boolean isvideo = MediaFile.isVideoMimeType(mMimeType); + boolean isimage = MediaFile.isImageMimeType(mMimeType); if (isaudio || isvideo || isimage) { path = Environment.maybeTranslateEmulatedPathToInternal(new File(path)) @@ -878,7 +868,6 @@ public class MediaScanner implements AutoCloseable { return; } mMimeType = mimeType; - mFileType = MediaFile.getFileTypeForMimeType(mimeType); } /** @@ -906,7 +895,7 @@ public class MediaScanner implements AutoCloseable { } if (!mNoMedia) { - if (MediaFile.isVideoFileType(mFileType)) { + if (MediaFile.isVideoMimeType(mMimeType)) { map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING)); map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 @@ -918,9 +907,9 @@ public class MediaScanner implements AutoCloseable { if (mDate > 0) { map.put(Video.Media.DATE_TAKEN, mDate); } - } else if (MediaFile.isImageFileType(mFileType)) { + } else if (MediaFile.isImageMimeType(mMimeType)) { // FIXME - add DESCRIPTION - } else if (mScanSuccess && MediaFile.isAudioFileType(mFileType)) { + } else if (mScanSuccess && MediaFile.isAudioMimeType(mMimeType)) { map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ? mArtist : MediaStore.UNKNOWN_STRING); map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null && @@ -982,7 +971,7 @@ public class MediaScanner implements AutoCloseable { } } long rowId = entry.mRowId; - if (MediaFile.isAudioFileType(mFileType) && (rowId == 0 || mMtpObjectHandle != 0)) { + if (MediaFile.isAudioMimeType(mMimeType) && (rowId == 0 || mMtpObjectHandle != 0)) { // Only set these for new entries. For existing entries, they // may have been modified later, and we want to keep the current // values so that custom ringtones still show up in the ringtone @@ -992,9 +981,7 @@ public class MediaScanner implements AutoCloseable { values.put(Audio.Media.IS_ALARM, alarms); values.put(Audio.Media.IS_MUSIC, music); values.put(Audio.Media.IS_PODCAST, podcasts); - } else if ((mFileType == MediaFile.FILE_TYPE_JPEG - || mFileType == MediaFile.FILE_TYPE_HEIF - || MediaFile.isRawImageFileType(mFileType)) && !mNoMedia) { + } else if (MediaFile.isExifMimeType(mMimeType) && !mNoMedia) { ExifInterface exif = null; try { exif = new ExifInterface(entry.mPath); @@ -1050,16 +1037,16 @@ public class MediaScanner implements AutoCloseable { int mediaType = FileColumns.MEDIA_TYPE_NONE; MediaInserter inserter = mMediaInserter; if (mScanSuccess && !mNoMedia) { - if (MediaFile.isVideoFileType(mFileType)) { + if (MediaFile.isVideoMimeType(mMimeType)) { tableUri = mVideoUri; mediaType = FileColumns.MEDIA_TYPE_VIDEO; - } else if (MediaFile.isImageFileType(mFileType)) { + } else if (MediaFile.isImageMimeType(mMimeType)) { tableUri = mImagesUri; mediaType = FileColumns.MEDIA_TYPE_IMAGE; - } else if (MediaFile.isAudioFileType(mFileType)) { + } else if (MediaFile.isAudioMimeType(mMimeType)) { tableUri = mAudioUri; mediaType = FileColumns.MEDIA_TYPE_AUDIO; - } else if (MediaFile.isPlayListFileType(mFileType)) { + } else if (MediaFile.isPlayListMimeType(mMimeType)) { tableUri = mPlaylistsUri; mediaType = FileColumns.MEDIA_TYPE_PLAYLIST; } @@ -1176,13 +1163,15 @@ public class MediaScanner implements AutoCloseable { Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1); } + /** @deprecated file types no longer exist */ + @Deprecated @UnsupportedAppUsage private int getFileTypeFromDrm(String path) { - if (!isDrmEnabled()) { - return 0; - } + return 0; + } - int resultFileType = 0; + private void getMimeTypeFromDrm(String path) { + mMimeType = null; if (mDrmManagerClient == null) { mDrmManagerClient = new DrmManagerClient(mContext); @@ -1190,13 +1179,12 @@ public class MediaScanner implements AutoCloseable { if (mDrmManagerClient.canHandle(path, null)) { mIsDrm = true; - String drmMimetype = mDrmManagerClient.getOriginalMimeType(path); - if (drmMimetype != null) { - mMimeType = drmMimetype; - resultFileType = MediaFile.getFileTypeForMimeType(drmMimetype); - } + mMimeType = mDrmManagerClient.getOriginalMimeType(path); + } + + if (mMimeType == null) { + mMimeType = ContentResolver.MIME_TYPE_DEFAULT; } - return resultFileType; } }; // end of anonymous MediaScannerClient instance @@ -1305,10 +1293,8 @@ public class MediaScanner implements AutoCloseable { // modified by the user. // The user can delete them in the media player instead. // instead, clear the path and lastModified fields in the row - MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); - int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); - - if (!MediaFile.isPlayListFileType(fileType)) { + String mimeType = MediaFile.getMimeTypeForFile(path); + if (!MediaFile.isPlayListMimeType(mimeType)) { deleter.delete(rowId); if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) { deleter.flush(); @@ -1556,14 +1542,13 @@ public class MediaScanner implements AutoCloseable { } public void scanMtpFile(String path, int objectHandle, int format) { - MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); - int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); + String mimeType = MediaFile.getMimeType(path, format); File file = new File(path); long lastModifiedSeconds = file.lastModified() / 1000; - if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) && - !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType) && - !MediaFile.isDrmFileType(fileType)) { + if (!MediaFile.isAudioMimeType(mimeType) && !MediaFile.isVideoMimeType(mimeType) && + !MediaFile.isImageMimeType(mimeType) && !MediaFile.isPlayListMimeType(mimeType) && + !MediaFile.isDrmMimeType(mimeType)) { // no need to use the media scanner, but we need to update last modified and file size ContentValues values = new ContentValues(); @@ -1582,7 +1567,7 @@ public class MediaScanner implements AutoCloseable { mMtpObjectHandle = objectHandle; Cursor fileList = null; try { - if (MediaFile.isPlayListFileType(fileType)) { + if (MediaFile.isPlayListMimeType(mimeType)) { // build file cache so we can look up tracks in the playlist prescan(null, true); @@ -1597,7 +1582,7 @@ public class MediaScanner implements AutoCloseable { prescan(path, false); // always scan the file, so we can return the content://media Uri for existing files - mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(), + mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(), (format == MtpConstants.FORMAT_ASSOCIATION), true, isNoMediaPath(path)); } } catch (RemoteException e) { @@ -1911,15 +1896,17 @@ public class MediaScanner implements AutoCloseable { } String playListDirectory = path.substring(0, lastSlash + 1); - MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); - int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); - - if (fileType == MediaFile.FILE_TYPE_M3U) { - processM3uPlayList(path, playListDirectory, membersUri, values, fileList); - } else if (fileType == MediaFile.FILE_TYPE_PLS) { - processPlsPlayList(path, playListDirectory, membersUri, values, fileList); - } else if (fileType == MediaFile.FILE_TYPE_WPL) { - processWplPlayList(path, playListDirectory, membersUri, values, fileList); + String mimeType = MediaFile.getMimeTypeForFile(path); + switch (mimeType) { + case "application/vnd.ms-wpl": + processWplPlayList(path, playListDirectory, membersUri, values, fileList); + break; + case "audio/x-mpegurl": + processM3uPlayList(path, playListDirectory, membersUri, values, fileList); + break; + case "audio/x-scpls": + processPlsPlayList(path, playListDirectory, membersUri, values, fileList); + break; } } diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java index 07ab06934eb3..4cc86fdce2f2 100644 --- a/media/java/android/media/ThumbnailUtils.java +++ b/media/java/android/media/ThumbnailUtils.java @@ -23,15 +23,13 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Rect; -import android.media.MediaMetadataRetriever; -import android.media.MediaFile.MediaFileType; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.provider.MediaStore.Images; import android.util.Log; -import java.io.FileInputStream; import java.io.FileDescriptor; +import java.io.FileInputStream; import java.io.IOException; /** @@ -94,15 +92,15 @@ public class ThumbnailUtils { : MAX_NUM_PIXELS_MICRO_THUMBNAIL; SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap(); Bitmap bitmap = null; - MediaFileType fileType = MediaFile.getFileType(filePath); - if (fileType != null) { - if (fileType.fileType == MediaFile.FILE_TYPE_JPEG - || MediaFile.isRawImageFileType(fileType.fileType)) { - createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap); - bitmap = sizedThumbnailBitmap.mBitmap; - } else if (fileType.fileType == MediaFile.FILE_TYPE_HEIF) { - bitmap = createThumbnailFromMetadataRetriever(filePath, targetSize, maxPixels); - } + String mimeType = MediaFile.getMimeTypeForFile(filePath); + if (mimeType.equals("image/heif") + || mimeType.equals("image/heif-sequence") + || mimeType.equals("image/heic") + || mimeType.equals("image/heic-sequence")) { + bitmap = createThumbnailFromMetadataRetriever(filePath, targetSize, maxPixels); + } else if (MediaFile.isExifMimeType(mimeType)) { + createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap); + bitmap = sizedThumbnailBitmap.mBitmap; } if (bitmap == null) { diff --git a/media/tests/MediaFrameworkTest/AndroidTest.xml b/media/tests/MediaFrameworkTest/AndroidTest.xml new file mode 100644 index 000000000000..204959ff2749 --- /dev/null +++ b/media/tests/MediaFrameworkTest/AndroidTest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source 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. +--> +<configuration description="Runs Media Framework Tests"> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="mediaframeworktest.apk" /> + </target_preparer> + + <option name="test-tag" value="MediaFrameworkTest" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.mediaframeworktest" /> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration> diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java new file mode 100644 index 000000000000..feac63d40710 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2018 The Android Open Source 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.android.mediaframeworktest.unit; + +import static android.media.MediaFile.getFormatCode; +import static android.media.MediaFile.getMimeType; +import static android.media.MediaFile.isAudioMimeType; +import static android.media.MediaFile.isImageMimeType; +import static android.media.MediaFile.isPlayListMimeType; +import static android.media.MediaFile.isVideoMimeType; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.mtp.MtpConstants; +import android.support.test.runner.AndroidJUnit4; + +import libcore.net.MimeUtils; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class MediaFileTest { + @Test + public void testCommon() throws Exception { + assertConsistent("FOO.TXT", "text/plain", MtpConstants.FORMAT_TEXT); + assertConsistent("FOO.XML", "text/xml", MtpConstants.FORMAT_XML_DOCUMENT); + assertConsistent("FOO.HTML", "text/html", MtpConstants.FORMAT_HTML); + } + + @Test + public void testAudio() throws Exception { + assertTrue(isAudioMimeType("audio/flac")); + assertTrue(isAudioMimeType("application/x-flac")); + assertFalse(isAudioMimeType("video/mpeg")); + + assertConsistent("FOO.MP3", "audio/mpeg", MtpConstants.FORMAT_MP3); + assertConsistent("FOO.AAC", "audio/aac", MtpConstants.FORMAT_AAC); + assertConsistent("FOO.OGG", "audio/ogg", MtpConstants.FORMAT_OGG); + assertConsistent("FOO.FLAC", "audio/flac", MtpConstants.FORMAT_FLAC); + } + + @Test + public void testVideo() throws Exception { + assertTrue(isVideoMimeType("video/x-msvideo")); + assertFalse(isVideoMimeType("audio/mpeg")); + + assertConsistent("FOO.AVI", "video/avi", MtpConstants.FORMAT_AVI); + assertConsistent("FOO.MP4", "video/mp4", MtpConstants.FORMAT_MP4_CONTAINER); + assertConsistent("FOO.3GP", "video/3gpp", MtpConstants.FORMAT_3GP_CONTAINER); + } + + @Test + public void testImage() throws Exception { + assertTrue(isImageMimeType("image/jpeg")); + assertTrue(isImageMimeType("image/heif")); + assertTrue(isImageMimeType("image/webp")); + assertFalse(isImageMimeType("video/webm")); + + assertConsistent("FOO.JPG", "image/jpeg", MtpConstants.FORMAT_EXIF_JPEG); + assertConsistent("FOO.PNG", "image/png", MtpConstants.FORMAT_PNG); + assertConsistent("FOO.HEIF", "image/heif", MtpConstants.FORMAT_HEIF); + assertConsistent("FOO.DNG", "image/x-adobe-dng", MtpConstants.FORMAT_DNG); + assertConsistent("FOO.TIFF", "image/tiff", MtpConstants.FORMAT_TIFF); + } + + @Test + public void testPlayList() throws Exception { + assertTrue(isPlayListMimeType(MimeUtils.guessMimeTypeFromExtension("pls"))); + assertTrue(isPlayListMimeType(MimeUtils.guessMimeTypeFromExtension("wpl"))); + assertTrue(isPlayListMimeType(MimeUtils.guessMimeTypeFromExtension("m3u"))); + assertTrue(isPlayListMimeType(MimeUtils.guessMimeTypeFromExtension("m3u8"))); + assertTrue(isPlayListMimeType(MimeUtils.guessMimeTypeFromExtension("asf"))); + } + + @Test + public void testImageRaw() throws Exception { + // We trust MIME types before filenames + assertHexEquals(MtpConstants.FORMAT_TIFF, getFormatCode("FOO.CR2", "image/x-canon-cr2")); + // We trust filenames before format codes + assertEquals("image/x-canon-cr2", getMimeType("FOO.CR2", MtpConstants.FORMAT_TIFF)); + } + + @Test + public void testConfusing() throws Exception { + // We trust MIME types before filenames + assertHexEquals(MtpConstants.FORMAT_MP3, getFormatCode("foo.avi", "audio/mpeg")); + // We trust filenames before format codes + assertEquals("video/avi", getMimeType("foo.avi", MtpConstants.FORMAT_MP3)); + } + + @Test + public void testUnknown() throws Exception { + assertHexEquals(MtpConstants.FORMAT_UNDEFINED, + getFormatCode("foo.example", "application/x-example")); + assertHexEquals(MtpConstants.FORMAT_UNDEFINED_AUDIO, + getFormatCode("foo.example", "audio/x-example")); + assertHexEquals(MtpConstants.FORMAT_UNDEFINED_VIDEO, + getFormatCode("foo.example", "video/x-example")); + assertHexEquals(MtpConstants.FORMAT_DEFINED, + getFormatCode("foo.example", "image/x-example")); + } + + private static void assertConsistent(String path, String mimeType, int formatCode) { + assertHexEquals(formatCode, getFormatCode(path, null)); + assertHexEquals(formatCode, getFormatCode(null, mimeType)); + assertHexEquals(formatCode, getFormatCode(path, mimeType)); + + assertEquals(mimeType, getMimeType(path, MtpConstants.FORMAT_UNDEFINED)); + assertEquals(mimeType, getMimeType(null, formatCode)); + assertEquals(mimeType, getMimeType(path, formatCode)); + } + + private static void assertHexEquals(int expected, int actual) { + assertEquals(Integer.toHexString(expected), Integer.toHexString(actual)); + } +} diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java index f243b51d6769..59c205aebe18 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java @@ -851,25 +851,7 @@ class MtpDatabase { return DocumentsContract.Document.MIME_TYPE_DIR; } - final String formatCodeMimeType = MediaFile.getMimeTypeForFormatCode(info.getFormat()); - final String mediaFileMimeType = MediaFile.getMimeTypeForFile(info.getName()); - - // Format code can be mapped with multiple mime types, e.g. FORMAT_MPEG is mapped with - // audio/mp4 and video/mp4. - // As file extension contains more information than format code, returns mime type obtained - // from file extension if it is consistent with format code. - if (mediaFileMimeType != null && - MediaFile.getFormatCode("", mediaFileMimeType) == info.getFormat()) { - return mediaFileMimeType; - } - if (formatCodeMimeType != null) { - return formatCodeMimeType; - } - if (mediaFileMimeType != null) { - return mediaFileMimeType; - } - // We don't know the file type. - return "application/octet-stream"; + return MediaFile.getMimeType(info.getName(), info.getFormat()); } private static int getRootFlags(int[] operationsSupported) { |