1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media; 18 19 import static android.content.ContentResolver.MIME_TYPE_DEFAULT; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.UnsupportedAppUsage; 24 import android.mtp.MtpConstants; 25 26 import libcore.net.MimeUtils; 27 28 import java.util.HashMap; 29 30 /** 31 * MediaScanner helper class. 32 * <p> 33 * This heavily relies upon extension to MIME type mappings which are maintained 34 * in {@link MimeUtils}, to ensure consistency across the OS. 35 * <p> 36 * When adding a new file type, first add the MIME type mapping to 37 * {@link MimeUtils}, and then add the MTP format mapping here. 38 * 39 * @hide 40 */ 41 public class MediaFile { 42 43 /** @deprecated file types no longer exist */ 44 @Deprecated 45 @UnsupportedAppUsage 46 private static final int FIRST_AUDIO_FILE_TYPE = 1; 47 /** @deprecated file types no longer exist */ 48 @Deprecated 49 @UnsupportedAppUsage 50 private static final int LAST_AUDIO_FILE_TYPE = 10; 51 52 /** @deprecated file types no longer exist */ 53 @Deprecated 54 public static class MediaFileType { 55 @UnsupportedAppUsage 56 public final int fileType; 57 @UnsupportedAppUsage 58 public final String mimeType; 59 MediaFileType(int fileType, String mimeType)60 MediaFileType(int fileType, String mimeType) { 61 this.fileType = fileType; 62 this.mimeType = mimeType; 63 } 64 } 65 66 /** @deprecated file types no longer exist */ 67 @Deprecated 68 @UnsupportedAppUsage 69 private static final HashMap<String, MediaFileType> sFileTypeMap = new HashMap<>(); 70 /** @deprecated file types no longer exist */ 71 @Deprecated 72 @UnsupportedAppUsage 73 private static final HashMap<String, Integer> sFileTypeToFormatMap = new HashMap<>(); 74 75 // maps mime type to MTP format code 76 @UnsupportedAppUsage 77 private static final HashMap<String, Integer> sMimeTypeToFormatMap = new HashMap<>(); 78 // maps MTP format code to mime type 79 @UnsupportedAppUsage 80 private static final HashMap<Integer, String> sFormatToMimeTypeMap = new HashMap<>(); 81 82 /** @deprecated file types no longer exist */ 83 @Deprecated 84 @UnsupportedAppUsage addFileType(String extension, int fileType, String mimeType)85 static void addFileType(String extension, int fileType, String mimeType) { 86 } 87 addFileType(int mtpFormatCode, @NonNull String mimeType)88 private static void addFileType(int mtpFormatCode, @NonNull String mimeType) { 89 if (!sMimeTypeToFormatMap.containsKey(mimeType)) { 90 sMimeTypeToFormatMap.put(mimeType, Integer.valueOf(mtpFormatCode)); 91 } 92 if (!sFormatToMimeTypeMap.containsKey(mtpFormatCode)) { 93 sFormatToMimeTypeMap.put(mtpFormatCode, mimeType); 94 } 95 } 96 97 static { addFileType(MtpConstants.FORMAT_MP3, "audio/mpeg")98 addFileType(MtpConstants.FORMAT_MP3, "audio/mpeg"); addFileType(MtpConstants.FORMAT_WAV, "audio/x-wav")99 addFileType(MtpConstants.FORMAT_WAV, "audio/x-wav"); addFileType(MtpConstants.FORMAT_WMA, "audio/x-ms-wma")100 addFileType(MtpConstants.FORMAT_WMA, "audio/x-ms-wma"); addFileType(MtpConstants.FORMAT_OGG, "audio/ogg")101 addFileType(MtpConstants.FORMAT_OGG, "audio/ogg"); addFileType(MtpConstants.FORMAT_AAC, "audio/aac")102 addFileType(MtpConstants.FORMAT_AAC, "audio/aac"); addFileType(MtpConstants.FORMAT_FLAC, "audio/flac")103 addFileType(MtpConstants.FORMAT_FLAC, "audio/flac"); addFileType(MtpConstants.FORMAT_AIFF, "audio/x-aiff")104 addFileType(MtpConstants.FORMAT_AIFF, "audio/x-aiff"); addFileType(MtpConstants.FORMAT_MP2, "audio/mpeg")105 addFileType(MtpConstants.FORMAT_MP2, "audio/mpeg"); 106 addFileType(MtpConstants.FORMAT_MPEG, "video/mpeg")107 addFileType(MtpConstants.FORMAT_MPEG, "video/mpeg"); addFileType(MtpConstants.FORMAT_MP4_CONTAINER, "video/mp4")108 addFileType(MtpConstants.FORMAT_MP4_CONTAINER, "video/mp4"); addFileType(MtpConstants.FORMAT_3GP_CONTAINER, "video/3gpp")109 addFileType(MtpConstants.FORMAT_3GP_CONTAINER, "video/3gpp"); addFileType(MtpConstants.FORMAT_3GP_CONTAINER, "video/3gpp2")110 addFileType(MtpConstants.FORMAT_3GP_CONTAINER, "video/3gpp2"); addFileType(MtpConstants.FORMAT_AVI, "video/avi")111 addFileType(MtpConstants.FORMAT_AVI, "video/avi"); addFileType(MtpConstants.FORMAT_WMV, "video/x-ms-wmv")112 addFileType(MtpConstants.FORMAT_WMV, "video/x-ms-wmv"); addFileType(MtpConstants.FORMAT_ASF, "video/x-ms-asf")113 addFileType(MtpConstants.FORMAT_ASF, "video/x-ms-asf"); 114 addFileType(MtpConstants.FORMAT_EXIF_JPEG, "image/jpeg")115 addFileType(MtpConstants.FORMAT_EXIF_JPEG, "image/jpeg"); addFileType(MtpConstants.FORMAT_GIF, "image/gif")116 addFileType(MtpConstants.FORMAT_GIF, "image/gif"); addFileType(MtpConstants.FORMAT_PNG, "image/png")117 addFileType(MtpConstants.FORMAT_PNG, "image/png"); addFileType(MtpConstants.FORMAT_BMP, "image/x-ms-bmp")118 addFileType(MtpConstants.FORMAT_BMP, "image/x-ms-bmp"); addFileType(MtpConstants.FORMAT_HEIF, "image/heif")119 addFileType(MtpConstants.FORMAT_HEIF, "image/heif"); addFileType(MtpConstants.FORMAT_DNG, "image/x-adobe-dng")120 addFileType(MtpConstants.FORMAT_DNG, "image/x-adobe-dng"); addFileType(MtpConstants.FORMAT_TIFF, "image/tiff")121 addFileType(MtpConstants.FORMAT_TIFF, "image/tiff"); addFileType(MtpConstants.FORMAT_TIFF, "image/x-canon-cr2")122 addFileType(MtpConstants.FORMAT_TIFF, "image/x-canon-cr2"); addFileType(MtpConstants.FORMAT_TIFF, "image/x-nikon-nrw")123 addFileType(MtpConstants.FORMAT_TIFF, "image/x-nikon-nrw"); addFileType(MtpConstants.FORMAT_TIFF, "image/x-sony-arw")124 addFileType(MtpConstants.FORMAT_TIFF, "image/x-sony-arw"); addFileType(MtpConstants.FORMAT_TIFF, "image/x-panasonic-rw2")125 addFileType(MtpConstants.FORMAT_TIFF, "image/x-panasonic-rw2"); addFileType(MtpConstants.FORMAT_TIFF, "image/x-olympus-orf")126 addFileType(MtpConstants.FORMAT_TIFF, "image/x-olympus-orf"); addFileType(MtpConstants.FORMAT_TIFF, "image/x-pentax-pef")127 addFileType(MtpConstants.FORMAT_TIFF, "image/x-pentax-pef"); addFileType(MtpConstants.FORMAT_TIFF, "image/x-samsung-srw")128 addFileType(MtpConstants.FORMAT_TIFF, "image/x-samsung-srw"); addFileType(MtpConstants.FORMAT_TIFF_EP, "image/tiff")129 addFileType(MtpConstants.FORMAT_TIFF_EP, "image/tiff"); addFileType(MtpConstants.FORMAT_TIFF_EP, "image/x-nikon-nef")130 addFileType(MtpConstants.FORMAT_TIFF_EP, "image/x-nikon-nef"); addFileType(MtpConstants.FORMAT_JP2, "image/jp2")131 addFileType(MtpConstants.FORMAT_JP2, "image/jp2"); addFileType(MtpConstants.FORMAT_JPX, "image/jpx")132 addFileType(MtpConstants.FORMAT_JPX, "image/jpx"); 133 addFileType(MtpConstants.FORMAT_M3U_PLAYLIST, "audio/x-mpegurl")134 addFileType(MtpConstants.FORMAT_M3U_PLAYLIST, "audio/x-mpegurl"); addFileType(MtpConstants.FORMAT_PLS_PLAYLIST, "audio/x-scpls")135 addFileType(MtpConstants.FORMAT_PLS_PLAYLIST, "audio/x-scpls"); addFileType(MtpConstants.FORMAT_WPL_PLAYLIST, "application/vnd.ms-wpl")136 addFileType(MtpConstants.FORMAT_WPL_PLAYLIST, "application/vnd.ms-wpl"); addFileType(MtpConstants.FORMAT_ASX_PLAYLIST, "video/x-ms-asf")137 addFileType(MtpConstants.FORMAT_ASX_PLAYLIST, "video/x-ms-asf"); 138 addFileType(MtpConstants.FORMAT_TEXT, "text/plain")139 addFileType(MtpConstants.FORMAT_TEXT, "text/plain"); addFileType(MtpConstants.FORMAT_HTML, "text/html")140 addFileType(MtpConstants.FORMAT_HTML, "text/html"); addFileType(MtpConstants.FORMAT_XML_DOCUMENT, "text/xml")141 addFileType(MtpConstants.FORMAT_XML_DOCUMENT, "text/xml"); 142 addFileType(MtpConstants.FORMAT_MS_WORD_DOCUMENT, "application/msword")143 addFileType(MtpConstants.FORMAT_MS_WORD_DOCUMENT, 144 "application/msword"); addFileType(MtpConstants.FORMAT_MS_WORD_DOCUMENT, "application/vnd.openxmlformats-officedocument.wordprocessingml.document")145 addFileType(MtpConstants.FORMAT_MS_WORD_DOCUMENT, 146 "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); addFileType(MtpConstants.FORMAT_MS_EXCEL_SPREADSHEET, "application/vnd.ms-excel")147 addFileType(MtpConstants.FORMAT_MS_EXCEL_SPREADSHEET, 148 "application/vnd.ms-excel"); addFileType(MtpConstants.FORMAT_MS_EXCEL_SPREADSHEET, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")149 addFileType(MtpConstants.FORMAT_MS_EXCEL_SPREADSHEET, 150 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); addFileType(MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION, "application/vnd.ms-powerpoint")151 addFileType(MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION, 152 "application/vnd.ms-powerpoint"); addFileType(MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION, "application/vnd.openxmlformats-officedocument.presentationml.presentation")153 addFileType(MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION, 154 "application/vnd.openxmlformats-officedocument.presentationml.presentation"); 155 } 156 157 /** @deprecated file types no longer exist */ 158 @Deprecated 159 @UnsupportedAppUsage isAudioFileType(int fileType)160 public static boolean isAudioFileType(int fileType) { 161 return false; 162 } 163 164 /** @deprecated file types no longer exist */ 165 @Deprecated 166 @UnsupportedAppUsage isVideoFileType(int fileType)167 public static boolean isVideoFileType(int fileType) { 168 return false; 169 } 170 171 /** @deprecated file types no longer exist */ 172 @Deprecated 173 @UnsupportedAppUsage isImageFileType(int fileType)174 public static boolean isImageFileType(int fileType) { 175 return false; 176 } 177 178 /** @deprecated file types no longer exist */ 179 @Deprecated 180 @UnsupportedAppUsage isPlayListFileType(int fileType)181 public static boolean isPlayListFileType(int fileType) { 182 return false; 183 } 184 185 /** @deprecated file types no longer exist */ 186 @Deprecated 187 @UnsupportedAppUsage isDrmFileType(int fileType)188 public static boolean isDrmFileType(int fileType) { 189 return false; 190 } 191 192 /** @deprecated file types no longer exist */ 193 @Deprecated 194 @UnsupportedAppUsage getFileType(String path)195 public static MediaFileType getFileType(String path) { 196 return null; 197 } 198 isExifMimeType(@ullable String mimeType)199 public static boolean isExifMimeType(@Nullable String mimeType) { 200 // For simplicity, assume that all image files might have EXIF data 201 return isImageMimeType(mimeType); 202 } 203 isAudioMimeType(@ullable String mimeType)204 public static boolean isAudioMimeType(@Nullable String mimeType) { 205 return normalizeMimeType(mimeType).startsWith("audio/"); 206 } 207 isVideoMimeType(@ullable String mimeType)208 public static boolean isVideoMimeType(@Nullable String mimeType) { 209 return normalizeMimeType(mimeType).startsWith("video/"); 210 } 211 isImageMimeType(@ullable String mimeType)212 public static boolean isImageMimeType(@Nullable String mimeType) { 213 return normalizeMimeType(mimeType).startsWith("image/"); 214 } 215 isPlayListMimeType(@ullable String mimeType)216 public static boolean isPlayListMimeType(@Nullable String mimeType) { 217 switch (normalizeMimeType(mimeType)) { 218 case "application/vnd.ms-wpl": 219 case "audio/x-mpegurl": 220 case "audio/mpegurl": 221 case "application/x-mpegurl": 222 case "application/vnd.apple.mpegurl": 223 case "audio/x-scpls": 224 return true; 225 default: 226 return false; 227 } 228 } 229 isDrmMimeType(@ullable String mimeType)230 public static boolean isDrmMimeType(@Nullable String mimeType) { 231 return normalizeMimeType(mimeType).equals("application/x-android-drm-fl"); 232 } 233 234 // generates a title based on file name 235 @UnsupportedAppUsage getFileTitle(@onNull String path)236 public static @NonNull String getFileTitle(@NonNull String path) { 237 // extract file name after last slash 238 int lastSlash = path.lastIndexOf('/'); 239 if (lastSlash >= 0) { 240 lastSlash++; 241 if (lastSlash < path.length()) { 242 path = path.substring(lastSlash); 243 } 244 } 245 // truncate the file extension (if any) 246 int lastDot = path.lastIndexOf('.'); 247 if (lastDot > 0) { 248 path = path.substring(0, lastDot); 249 } 250 return path; 251 } 252 getFileExtension(@ullable String path)253 public static @Nullable String getFileExtension(@Nullable String path) { 254 if (path == null) { 255 return null; 256 } 257 int lastDot = path.lastIndexOf('.'); 258 if (lastDot >= 0) { 259 return path.substring(lastDot + 1); 260 } else { 261 return null; 262 } 263 } 264 265 /** @deprecated file types no longer exist */ 266 @Deprecated 267 @UnsupportedAppUsage getFileTypeForMimeType(String mimeType)268 public static int getFileTypeForMimeType(String mimeType) { 269 return 0; 270 } 271 272 /** 273 * Find the best MIME type for the given item. Prefers mappings from file 274 * extensions, since they're more accurate than format codes. 275 */ getMimeType(@ullable String path, int formatCode)276 public static @NonNull String getMimeType(@Nullable String path, int formatCode) { 277 // First look for extension mapping 278 String mimeType = getMimeTypeForFile(path); 279 if (!MIME_TYPE_DEFAULT.equals(mimeType)) { 280 return mimeType; 281 } 282 283 // Otherwise look for format mapping 284 return getMimeTypeForFormatCode(formatCode); 285 } 286 287 @UnsupportedAppUsage getMimeTypeForFile(@ullable String path)288 public static @NonNull String getMimeTypeForFile(@Nullable String path) { 289 final String mimeType = MimeUtils.guessMimeTypeFromExtension(getFileExtension(path)); 290 return (mimeType != null) ? mimeType : MIME_TYPE_DEFAULT; 291 } 292 getMimeTypeForFormatCode(int formatCode)293 public static @NonNull String getMimeTypeForFormatCode(int formatCode) { 294 final String mimeType = sFormatToMimeTypeMap.get(formatCode); 295 return (mimeType != null) ? mimeType : MIME_TYPE_DEFAULT; 296 } 297 298 /** 299 * Find the best MTP format code mapping for the given item. Prefers 300 * mappings from MIME types, since they're more accurate than file 301 * extensions. 302 */ getFormatCode(@ullable String path, @Nullable String mimeType)303 public static int getFormatCode(@Nullable String path, @Nullable String mimeType) { 304 // First look for MIME type mapping 305 int formatCode = getFormatCodeForMimeType(mimeType); 306 if (formatCode != MtpConstants.FORMAT_UNDEFINED) { 307 return formatCode; 308 } 309 310 // Otherwise look for extension mapping 311 return getFormatCodeForFile(path); 312 } 313 getFormatCodeForFile(@ullable String path)314 public static int getFormatCodeForFile(@Nullable String path) { 315 return getFormatCodeForMimeType(getMimeTypeForFile(path)); 316 } 317 getFormatCodeForMimeType(@ullable String mimeType)318 public static int getFormatCodeForMimeType(@Nullable String mimeType) { 319 if (mimeType == null) { 320 return MtpConstants.FORMAT_UNDEFINED; 321 } 322 323 // First look for direct mapping 324 Integer value = sMimeTypeToFormatMap.get(mimeType); 325 if (value != null) { 326 return value.intValue(); 327 } 328 329 // Otherwise look for indirect mapping 330 mimeType = normalizeMimeType(mimeType); 331 value = sMimeTypeToFormatMap.get(mimeType); 332 if (value != null) { 333 return value.intValue(); 334 } else if (mimeType.startsWith("audio/")) { 335 return MtpConstants.FORMAT_UNDEFINED_AUDIO; 336 } else if (mimeType.startsWith("video/")) { 337 return MtpConstants.FORMAT_UNDEFINED_VIDEO; 338 } else if (mimeType.startsWith("image/")) { 339 return MtpConstants.FORMAT_DEFINED; 340 } else { 341 return MtpConstants.FORMAT_UNDEFINED; 342 } 343 } 344 345 /** 346 * Normalize the given MIME type by bouncing through a default file 347 * extension, if defined. This handles cases like "application/x-flac" to 348 * ".flac" to "audio/flac". 349 */ normalizeMimeType(@ullable String mimeType)350 private static @NonNull String normalizeMimeType(@Nullable String mimeType) { 351 final String extension = MimeUtils.guessExtensionFromMimeType(mimeType); 352 if (extension != null) { 353 final String extensionMimeType = MimeUtils.guessMimeTypeFromExtension(extension); 354 if ( extensionMimeType != null) { 355 return extensionMimeType; 356 } 357 } 358 return (mimeType != null) ? mimeType : MIME_TYPE_DEFAULT; 359 } 360 } 361