446 lines
17 KiB
Java
446 lines
17 KiB
Java
/*
|
|
* 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.compat.annotation.UnsupportedAppUsage;
|
|
import android.mtp.MtpConstants;
|
|
|
|
import libcore.content.type.MimeMap;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.Locale;
|
|
|
|
/**
|
|
* 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<>();
|
|
|
|
@UnsupportedAppUsage
|
|
public MediaFile() {
|
|
}
|
|
|
|
/** @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;
|
|
}
|
|
|
|
/**
|
|
* Check whether the mime type is document or not.
|
|
* @param mimeType the mime type to check
|
|
* @return true, if the mimeType is matched. Otherwise, false.
|
|
*/
|
|
public static boolean isDocumentMimeType(@Nullable String mimeType) {
|
|
if (mimeType == null) {
|
|
return false;
|
|
}
|
|
|
|
final String normalizedMimeType = normalizeMimeType(mimeType);
|
|
if (normalizedMimeType.startsWith("text/")) {
|
|
return true;
|
|
}
|
|
|
|
switch (normalizedMimeType.toLowerCase(Locale.ROOT)) {
|
|
case "application/epub+zip":
|
|
case "application/msword":
|
|
case "application/pdf":
|
|
case "application/rtf":
|
|
case "application/vnd.ms-excel":
|
|
case "application/vnd.ms-excel.addin.macroenabled.12":
|
|
case "application/vnd.ms-excel.sheet.binary.macroenabled.12":
|
|
case "application/vnd.ms-excel.sheet.macroenabled.12":
|
|
case "application/vnd.ms-excel.template.macroenabled.12":
|
|
case "application/vnd.ms-powerpoint":
|
|
case "application/vnd.ms-powerpoint.addin.macroenabled.12":
|
|
case "application/vnd.ms-powerpoint.presentation.macroenabled.12":
|
|
case "application/vnd.ms-powerpoint.slideshow.macroenabled.12":
|
|
case "application/vnd.ms-powerpoint.template.macroenabled.12":
|
|
case "application/vnd.ms-word.document.macroenabled.12":
|
|
case "application/vnd.ms-word.template.macroenabled.12":
|
|
case "application/vnd.oasis.opendocument.chart":
|
|
case "application/vnd.oasis.opendocument.database":
|
|
case "application/vnd.oasis.opendocument.formula":
|
|
case "application/vnd.oasis.opendocument.graphics":
|
|
case "application/vnd.oasis.opendocument.graphics-template":
|
|
case "application/vnd.oasis.opendocument.presentation":
|
|
case "application/vnd.oasis.opendocument.presentation-template":
|
|
case "application/vnd.oasis.opendocument.spreadsheet":
|
|
case "application/vnd.oasis.opendocument.spreadsheet-template":
|
|
case "application/vnd.oasis.opendocument.text":
|
|
case "application/vnd.oasis.opendocument.text-master":
|
|
case "application/vnd.oasis.opendocument.text-template":
|
|
case "application/vnd.oasis.opendocument.text-web":
|
|
case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
|
|
case "application/vnd.openxmlformats-officedocument.presentationml.slideshow":
|
|
case "application/vnd.openxmlformats-officedocument.presentationml.template":
|
|
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
|
case "application/vnd.openxmlformats-officedocument.spreadsheetml.template":
|
|
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
|
case "application/vnd.openxmlformats-officedocument.wordprocessingml.template":
|
|
case "application/vnd.stardivision.calc":
|
|
case "application/vnd.stardivision.chart":
|
|
case "application/vnd.stardivision.draw":
|
|
case "application/vnd.stardivision.impress":
|
|
case "application/vnd.stardivision.impress-packed":
|
|
case "application/vnd.stardivision.mail":
|
|
case "application/vnd.stardivision.math":
|
|
case "application/vnd.stardivision.writer":
|
|
case "application/vnd.stardivision.writer-global":
|
|
case "application/vnd.sun.xml.calc":
|
|
case "application/vnd.sun.xml.calc.template":
|
|
case "application/vnd.sun.xml.draw":
|
|
case "application/vnd.sun.xml.draw.template":
|
|
case "application/vnd.sun.xml.impress":
|
|
case "application/vnd.sun.xml.impress.template":
|
|
case "application/vnd.sun.xml.math":
|
|
case "application/vnd.sun.xml.writer":
|
|
case "application/vnd.sun.xml.writer.global":
|
|
case "application/vnd.sun.xml.writer.template":
|
|
case "application/x-mspublisher":
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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 "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;
|
|
}
|
|
}
|