| /* |
| * Copyright (C) 2007 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 android.media; |
| |
| import static android.content.ContentResolver.MIME_TYPE_DEFAULT; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.UnsupportedAppUsage; |
| import android.mtp.MtpConstants; |
| |
| import libcore.net.MimeMap; |
| |
| import java.util.HashMap; |
| |
| /** |
| * MediaScanner helper class. |
| * <p> |
| * This heavily relies upon extension to MIME type mappings which are maintained |
| * in {@link MimeMap}, to ensure consistency across the OS. |
| * <p> |
| * When adding a new file type, first add the MIME type mapping to |
| * {@link MimeMap}, and then add the MTP format mapping here. |
| * |
| * @hide |
| */ |
| public class MediaFile { |
| |
| /** @deprecated file types no longer exist */ |
| @Deprecated |
| @UnsupportedAppUsage |
| 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 = 10; |
| |
| /** @deprecated file types no longer exist */ |
| @Deprecated |
| public static class MediaFileType { |
| @UnsupportedAppUsage |
| public final int fileType; |
| @UnsupportedAppUsage |
| public final String mimeType; |
| |
| MediaFileType(int fileType, String mimeType) { |
| this.fileType = fileType; |
| this.mimeType = mimeType; |
| } |
| } |
| |
| /** @deprecated file types no longer exist */ |
| @Deprecated |
| @UnsupportedAppUsage |
| 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<>(); |
| |
| // maps mime type to MTP format code |
| @UnsupportedAppUsage |
| 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<>(); |
| |
| /** @deprecated file types no longer exist */ |
| @Deprecated |
| @UnsupportedAppUsage |
| static void addFileType(String extension, int fileType, String mimeType) { |
| } |
| |
| private static void addFileType(int mtpFormatCode, @NonNull String mimeType) { |
| if (!sMimeTypeToFormatMap.containsKey(mimeType)) { |
| sMimeTypeToFormatMap.put(mimeType, Integer.valueOf(mtpFormatCode)); |
| } |
| if (!sFormatToMimeTypeMap.containsKey(mtpFormatCode)) { |
| sFormatToMimeTypeMap.put(mtpFormatCode, mimeType); |
| } |
| } |
| |
| static { |
| 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 false; |
| } |
| |
| /** @deprecated file types no longer exist */ |
| @Deprecated |
| @UnsupportedAppUsage |
| public static boolean isVideoFileType(int fileType) { |
| return false; |
| } |
| |
| /** @deprecated file types no longer exist */ |
| @Deprecated |
| @UnsupportedAppUsage |
| public static boolean isImageFileType(int fileType) { |
| return false; |
| } |
| |
| /** @deprecated file types no longer exist */ |
| @Deprecated |
| @UnsupportedAppUsage |
| public static boolean isPlayListFileType(int fileType) { |
| return false; |
| } |
| |
| /** @deprecated file types no longer exist */ |
| @Deprecated |
| @UnsupportedAppUsage |
| public static boolean isDrmFileType(int fileType) { |
| return false; |
| } |
| |
| /** @deprecated file types no longer exist */ |
| @Deprecated |
| @UnsupportedAppUsage |
| public static MediaFileType getFileType(String path) { |
| 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 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 @NonNull String getFileTitle(@NonNull String path) { |
| // extract file name after last slash |
| int lastSlash = path.lastIndexOf('/'); |
| if (lastSlash >= 0) { |
| lastSlash++; |
| if (lastSlash < path.length()) { |
| path = path.substring(lastSlash); |
| } |
| } |
| // truncate the file extension (if any) |
| int lastDot = path.lastIndexOf('.'); |
| if (lastDot > 0) { |
| path = path.substring(0, lastDot); |
| } |
| 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) { |
| 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 @NonNull String getMimeTypeForFile(@Nullable String path) { |
| String ext = getFileExtension(path); |
| final String mimeType = MimeMap.getDefault().guessMimeTypeFromExtension(ext); |
| return (mimeType != null) ? mimeType : MIME_TYPE_DEFAULT; |
| } |
| |
| 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; |
| } |
| |
| // 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; |
| } |
| } |
| |
| /** |
| * 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) { |
| MimeMap mimeMap = MimeMap.getDefault(); |
| final String extension = mimeMap.guessExtensionFromMimeType(mimeType); |
| if (extension != null) { |
| final String extensionMimeType = mimeMap.guessMimeTypeFromExtension(extension); |
| if (extensionMimeType != null) { |
| return extensionMimeType; |
| } |
| } |
| return (mimeType != null) ? mimeType : MIME_TYPE_DEFAULT; |
| } |
| } |