1 /* 2 * Copyright (C) 2014 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 package android.media; 17 18 import android.annotation.NonNull; 19 import android.content.ContentResolver; 20 import android.graphics.Bitmap; 21 import android.graphics.BitmapFactory; 22 import android.media.browse.MediaBrowser; 23 import android.media.session.MediaController; 24 import android.net.Uri; 25 import android.os.Bundle; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.text.TextUtils; 29 import android.util.ArrayMap; 30 import android.util.Log; 31 import android.util.SparseArray; 32 33 import java.util.ArrayList; 34 import java.util.Set; 35 36 /** 37 * Contains metadata about an item, such as the title, artist, etc. 38 */ 39 public final class MediaMetadata implements Parcelable { 40 private static final String TAG = "MediaMetadata"; 41 42 /** 43 * The title of the media. 44 */ 45 public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE"; 46 47 /** 48 * The artist of the media. 49 */ 50 public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST"; 51 52 /** 53 * The duration of the media in ms. A negative duration indicates that the 54 * duration is unknown (or infinite). 55 */ 56 public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION"; 57 58 /** 59 * The album title for the media. 60 */ 61 public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM"; 62 63 /** 64 * The author of the media. 65 */ 66 public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR"; 67 68 /** 69 * The writer of the media. 70 */ 71 public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER"; 72 73 /** 74 * The composer of the media. 75 */ 76 public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER"; 77 78 /** 79 * The compilation status of the media. 80 */ 81 public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION"; 82 83 /** 84 * The date the media was created or published. The format is unspecified 85 * but RFC 3339 is recommended. 86 */ 87 public static final String METADATA_KEY_DATE = "android.media.metadata.DATE"; 88 89 /** 90 * The year the media was created or published as a long. 91 */ 92 public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR"; 93 94 /** 95 * The genre of the media. 96 */ 97 public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE"; 98 99 /** 100 * The track number for the media. 101 */ 102 public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER"; 103 104 /** 105 * The number of tracks in the media's original source. 106 */ 107 public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS"; 108 109 /** 110 * The disc number for the media's original source. 111 */ 112 public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER"; 113 114 /** 115 * The artist for the album of the media's original source. 116 */ 117 public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST"; 118 119 /** 120 * The artwork for the media as a {@link Bitmap}. 121 * <p> 122 * The artwork should be relatively small and may be scaled down by the 123 * system if it is too large. For higher resolution artwork 124 * {@link #METADATA_KEY_ART_URI} should be used instead. 125 */ 126 public static final String METADATA_KEY_ART = "android.media.metadata.ART"; 127 128 /** 129 * The artwork for the media as a Uri formatted String. The artwork can be 130 * loaded using a combination of {@link ContentResolver#openInputStream} and 131 * {@link BitmapFactory#decodeStream}. 132 * <p> 133 * For the best results, Uris should use the content:// style and support 134 * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through 135 * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}. 136 */ 137 public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI"; 138 139 /** 140 * The artwork for the album of the media's original source as a 141 * {@link Bitmap}. 142 * <p> 143 * The artwork should be relatively small and may be scaled down by the 144 * system if it is too large. For higher resolution artwork 145 * {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead. 146 */ 147 public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART"; 148 149 /** 150 * The artwork for the album of the media's original source as a Uri 151 * formatted String. The artwork can be loaded using a combination of 152 * {@link ContentResolver#openInputStream} and 153 * {@link BitmapFactory#decodeStream}. 154 * <p> 155 * For the best results, Uris should use the content:// style and support 156 * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through 157 * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}. 158 */ 159 public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI"; 160 161 /** 162 * The user's rating for the media. 163 * 164 * @see Rating 165 */ 166 public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING"; 167 168 /** 169 * The overall rating for the media. 170 * 171 * @see Rating 172 */ 173 public static final String METADATA_KEY_RATING = "android.media.metadata.RATING"; 174 175 /** 176 * A title that is suitable for display to the user. This will generally be 177 * the same as {@link #METADATA_KEY_TITLE} but may differ for some formats. 178 * When displaying media described by this metadata this should be preferred 179 * if present. 180 */ 181 public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE"; 182 183 /** 184 * A subtitle that is suitable for display to the user. When displaying a 185 * second line for media described by this metadata this should be preferred 186 * to other fields if present. 187 */ 188 public static final String METADATA_KEY_DISPLAY_SUBTITLE 189 = "android.media.metadata.DISPLAY_SUBTITLE"; 190 191 /** 192 * A description that is suitable for display to the user. When displaying 193 * more information for media described by this metadata this should be 194 * preferred to other fields if present. 195 */ 196 public static final String METADATA_KEY_DISPLAY_DESCRIPTION 197 = "android.media.metadata.DISPLAY_DESCRIPTION"; 198 199 /** 200 * An icon or thumbnail that is suitable for display to the user. When 201 * displaying an icon for media described by this metadata this should be 202 * preferred to other fields if present. This must be a {@link Bitmap}. 203 * <p> 204 * The icon should be relatively small and may be scaled down by the system 205 * if it is too large. For higher resolution artwork 206 * {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead. 207 */ 208 public static final String METADATA_KEY_DISPLAY_ICON 209 = "android.media.metadata.DISPLAY_ICON"; 210 211 /** 212 * A Uri formatted String for an icon or thumbnail that is suitable for 213 * display to the user. When displaying more information for media described 214 * by this metadata the display description should be preferred to other 215 * fields when present. The icon can be loaded using a combination of 216 * {@link ContentResolver#openInputStream} and 217 * {@link BitmapFactory#decodeStream}. 218 * <p> 219 * For the best results, Uris should use the content:// style and support 220 * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through 221 * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}. 222 */ 223 public static final String METADATA_KEY_DISPLAY_ICON_URI 224 = "android.media.metadata.DISPLAY_ICON_URI"; 225 226 /** 227 * A String key for identifying the content. This value is specific to the 228 * service providing the content. If used, this should be a persistent 229 * unique key for the underlying content. It may be used with 230 * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)} 231 * to initiate playback when provided by a {@link MediaBrowser} connected to 232 * the same app. 233 */ 234 public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID"; 235 236 private static final String[] PREFERRED_DESCRIPTION_ORDER = { 237 METADATA_KEY_TITLE, 238 METADATA_KEY_ARTIST, 239 METADATA_KEY_ALBUM, 240 METADATA_KEY_ALBUM_ARTIST, 241 METADATA_KEY_WRITER, 242 METADATA_KEY_AUTHOR, 243 METADATA_KEY_COMPOSER 244 }; 245 246 private static final String[] PREFERRED_BITMAP_ORDER = { 247 METADATA_KEY_DISPLAY_ICON, 248 METADATA_KEY_ART, 249 METADATA_KEY_ALBUM_ART 250 }; 251 252 private static final String[] PREFERRED_URI_ORDER = { 253 METADATA_KEY_DISPLAY_ICON_URI, 254 METADATA_KEY_ART_URI, 255 METADATA_KEY_ALBUM_ART_URI 256 }; 257 258 private static final int METADATA_TYPE_INVALID = -1; 259 private static final int METADATA_TYPE_LONG = 0; 260 private static final int METADATA_TYPE_TEXT = 1; 261 private static final int METADATA_TYPE_BITMAP = 2; 262 private static final int METADATA_TYPE_RATING = 3; 263 private static final ArrayMap<String, Integer> METADATA_KEYS_TYPE; 264 265 static { 266 METADATA_KEYS_TYPE = new ArrayMap<String, Integer>(); METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT)267 METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT)268 METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG)269 METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT)270 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT)271 METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT)272 METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT)273 METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT)274 METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT)275 METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG)276 METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT)277 METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG)278 METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG)279 METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG)280 METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT)281 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP)282 METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP); METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT)283 METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP)284 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP); METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT)285 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING)286 METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING); METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING)287 METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT)288 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT)289 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT)290 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP)291 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT)292 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT); 293 } 294 295 private static final SparseArray<String> EDITOR_KEY_MAPPING; 296 297 static { 298 EDITOR_KEY_MAPPING = new SparseArray<String>(); EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART)299 EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART); EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING)300 EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING); EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING)301 EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM)302 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, METADATA_KEY_ALBUM_ARTIST)303 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, 304 METADATA_KEY_ALBUM_ARTIST); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST)305 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR)306 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, METADATA_KEY_TRACK_NUMBER)307 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, 308 METADATA_KEY_TRACK_NUMBER); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER)309 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION, METADATA_KEY_COMPILATION)310 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION, 311 METADATA_KEY_COMPILATION); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE)312 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, METADATA_KEY_DISC_NUMBER)313 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, 314 METADATA_KEY_DISC_NUMBER); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION)315 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE)316 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS, METADATA_KEY_NUM_TRACKS)317 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS, 318 METADATA_KEY_NUM_TRACKS); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE)319 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER)320 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER); EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR)321 EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR); 322 } 323 324 private final Bundle mBundle; 325 private MediaDescription mDescription; 326 MediaMetadata(Bundle bundle)327 private MediaMetadata(Bundle bundle) { 328 mBundle = new Bundle(bundle); 329 } 330 MediaMetadata(Parcel in)331 private MediaMetadata(Parcel in) { 332 mBundle = in.readBundle(); 333 } 334 335 /** 336 * Returns true if the given key is contained in the metadata 337 * 338 * @param key a String key 339 * @return true if the key exists in this metadata, false otherwise 340 */ containsKey(String key)341 public boolean containsKey(String key) { 342 return mBundle.containsKey(key); 343 } 344 345 /** 346 * Returns the value associated with the given key, or null if no mapping of 347 * the desired type exists for the given key or a null value is explicitly 348 * associated with the key. 349 * 350 * @param key The key the value is stored under 351 * @return a CharSequence value, or null 352 */ getText(String key)353 public CharSequence getText(String key) { 354 return mBundle.getCharSequence(key); 355 } 356 357 /** 358 * Returns the text value associated with the given key as a String, or null 359 * if no mapping of the desired type exists for the given key or a null 360 * value is explicitly associated with the key. This is equivalent to 361 * calling {@link #getText getText().toString()} if the value is not null. 362 * 363 * @param key The key the value is stored under 364 * @return a String value, or null 365 */ getString(String key)366 public String getString(String key) { 367 CharSequence text = getText(key); 368 if (text != null) { 369 return text.toString(); 370 } 371 return null; 372 } 373 374 /** 375 * Returns the value associated with the given key, or 0L if no long exists 376 * for the given key. 377 * 378 * @param key The key the value is stored under 379 * @return a long value 380 */ getLong(String key)381 public long getLong(String key) { 382 return mBundle.getLong(key, 0); 383 } 384 385 /** 386 * Returns a {@link Rating} for the given key or null if no rating exists 387 * for the given key. 388 * 389 * @param key The key the value is stored under 390 * @return A {@link Rating} or null 391 */ getRating(String key)392 public Rating getRating(String key) { 393 Rating rating = null; 394 try { 395 rating = mBundle.getParcelable(key); 396 } catch (Exception e) { 397 // ignore, value was not a bitmap 398 Log.w(TAG, "Failed to retrieve a key as Rating.", e); 399 } 400 return rating; 401 } 402 403 /** 404 * Returns a {@link Bitmap} for the given key or null if no bitmap exists 405 * for the given key. 406 * 407 * @param key The key the value is stored under 408 * @return A {@link Bitmap} or null 409 */ getBitmap(String key)410 public Bitmap getBitmap(String key) { 411 Bitmap bmp = null; 412 try { 413 bmp = mBundle.getParcelable(key); 414 } catch (Exception e) { 415 // ignore, value was not a bitmap 416 Log.w(TAG, "Failed to retrieve a key as Bitmap.", e); 417 } 418 return bmp; 419 } 420 421 @Override describeContents()422 public int describeContents() { 423 return 0; 424 } 425 426 @Override writeToParcel(Parcel dest, int flags)427 public void writeToParcel(Parcel dest, int flags) { 428 dest.writeBundle(mBundle); 429 } 430 431 /** 432 * Returns the number of fields in this metadata. 433 * 434 * @return The number of fields in the metadata. 435 */ size()436 public int size() { 437 return mBundle.size(); 438 } 439 440 /** 441 * Returns a Set containing the Strings used as keys in this metadata. 442 * 443 * @return a Set of String keys 444 */ keySet()445 public Set<String> keySet() { 446 return mBundle.keySet(); 447 } 448 449 /** 450 * Returns a simple description of this metadata for display purposes. 451 * 452 * @return A simple description of this metadata. 453 */ getDescription()454 public @NonNull MediaDescription getDescription() { 455 if (mDescription != null) { 456 return mDescription; 457 } 458 459 String mediaId = getString(METADATA_KEY_MEDIA_ID); 460 461 CharSequence[] text = new CharSequence[3]; 462 Bitmap icon = null; 463 Uri iconUri = null; 464 465 // First handle the case where display data is set already 466 CharSequence displayText = getText(METADATA_KEY_DISPLAY_TITLE); 467 if (!TextUtils.isEmpty(displayText)) { 468 // If they have a display title use only display data, otherwise use 469 // our best bets 470 text[0] = displayText; 471 text[1] = getText(METADATA_KEY_DISPLAY_SUBTITLE); 472 text[2] = getText(METADATA_KEY_DISPLAY_DESCRIPTION); 473 } else { 474 // Use whatever fields we can 475 int textIndex = 0; 476 int keyIndex = 0; 477 while (textIndex < text.length && keyIndex < PREFERRED_DESCRIPTION_ORDER.length) { 478 CharSequence next = getText(PREFERRED_DESCRIPTION_ORDER[keyIndex++]); 479 if (!TextUtils.isEmpty(next)) { 480 // Fill in the next empty bit of text 481 text[textIndex++] = next; 482 } 483 } 484 } 485 486 // Get the best art bitmap we can find 487 for (int i = 0; i < PREFERRED_BITMAP_ORDER.length; i++) { 488 Bitmap next = getBitmap(PREFERRED_BITMAP_ORDER[i]); 489 if (next != null) { 490 icon = next; 491 break; 492 } 493 } 494 495 // Get the best Uri we can find 496 for (int i = 0; i < PREFERRED_URI_ORDER.length; i++) { 497 String next = getString(PREFERRED_URI_ORDER[i]); 498 if (!TextUtils.isEmpty(next)) { 499 iconUri = Uri.parse(next); 500 break; 501 } 502 } 503 504 MediaDescription.Builder bob = new MediaDescription.Builder(); 505 bob.setMediaId(mediaId); 506 bob.setTitle(text[0]); 507 bob.setSubtitle(text[1]); 508 bob.setDescription(text[2]); 509 bob.setIconBitmap(icon); 510 bob.setIconUri(iconUri); 511 mDescription = bob.build(); 512 513 return mDescription; 514 } 515 516 /** 517 * Helper for getting the String key used by {@link MediaMetadata} from the 518 * integer key that {@link MediaMetadataEditor} uses. 519 * 520 * @param editorKey The key used by the editor 521 * @return The key used by this class or null if no mapping exists 522 * @hide 523 */ getKeyFromMetadataEditorKey(int editorKey)524 public static String getKeyFromMetadataEditorKey(int editorKey) { 525 return EDITOR_KEY_MAPPING.get(editorKey, null); 526 } 527 528 public static final Parcelable.Creator<MediaMetadata> CREATOR = 529 new Parcelable.Creator<MediaMetadata>() { 530 @Override 531 public MediaMetadata createFromParcel(Parcel in) { 532 return new MediaMetadata(in); 533 } 534 535 @Override 536 public MediaMetadata[] newArray(int size) { 537 return new MediaMetadata[size]; 538 } 539 }; 540 541 /** 542 * Use to build MediaMetadata objects. The system defined metadata keys must 543 * use the appropriate data type. 544 */ 545 public static final class Builder { 546 private final Bundle mBundle; 547 548 /** 549 * Create an empty Builder. Any field that should be included in the 550 * {@link MediaMetadata} must be added. 551 */ Builder()552 public Builder() { 553 mBundle = new Bundle(); 554 } 555 556 /** 557 * Create a Builder using a {@link MediaMetadata} instance to set the 558 * initial values. All fields in the source metadata will be included in 559 * the new metadata. Fields can be overwritten by adding the same key. 560 * 561 * @param source 562 */ Builder(MediaMetadata source)563 public Builder(MediaMetadata source) { 564 mBundle = new Bundle(source.mBundle); 565 } 566 567 /** 568 * Create a Builder using a {@link MediaMetadata} instance to set 569 * initial values, but replace bitmaps with a scaled down copy if they 570 * are larger than maxBitmapSize. 571 * 572 * @param source The original metadata to copy. 573 * @param maxBitmapSize The maximum height/width for bitmaps contained 574 * in the metadata. 575 * @hide 576 */ Builder(MediaMetadata source, int maxBitmapSize)577 public Builder(MediaMetadata source, int maxBitmapSize) { 578 this(source); 579 for (String key : mBundle.keySet()) { 580 Object value = mBundle.get(key); 581 if (value != null && value instanceof Bitmap) { 582 Bitmap bmp = (Bitmap) value; 583 if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) { 584 putBitmap(key, scaleBitmap(bmp, maxBitmapSize)); 585 } 586 } 587 } 588 } 589 590 /** 591 * Put a CharSequence value into the metadata. Custom keys may be used, 592 * but if the METADATA_KEYs defined in this class are used they may only 593 * be one of the following: 594 * <ul> 595 * <li>{@link #METADATA_KEY_TITLE}</li> 596 * <li>{@link #METADATA_KEY_ARTIST}</li> 597 * <li>{@link #METADATA_KEY_ALBUM}</li> 598 * <li>{@link #METADATA_KEY_AUTHOR}</li> 599 * <li>{@link #METADATA_KEY_WRITER}</li> 600 * <li>{@link #METADATA_KEY_COMPOSER}</li> 601 * <li>{@link #METADATA_KEY_DATE}</li> 602 * <li>{@link #METADATA_KEY_GENRE}</li> 603 * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li> 604 * <li>{@link #METADATA_KEY_ART_URI}</li> 605 * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li> 606 * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li> 607 * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li> 608 * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li> 609 * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li> 610 * </ul> 611 * 612 * @param key The key for referencing this value 613 * @param value The CharSequence value to store 614 * @return The Builder to allow chaining 615 */ putText(String key, CharSequence value)616 public Builder putText(String key, CharSequence value) { 617 if (METADATA_KEYS_TYPE.containsKey(key)) { 618 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) { 619 throw new IllegalArgumentException("The " + key 620 + " key cannot be used to put a CharSequence"); 621 } 622 } 623 mBundle.putCharSequence(key, value); 624 return this; 625 } 626 627 /** 628 * Put a String value into the metadata. Custom keys may be used, but if 629 * the METADATA_KEYs defined in this class are used they may only be one 630 * of the following: 631 * <ul> 632 * <li>{@link #METADATA_KEY_TITLE}</li> 633 * <li>{@link #METADATA_KEY_ARTIST}</li> 634 * <li>{@link #METADATA_KEY_ALBUM}</li> 635 * <li>{@link #METADATA_KEY_AUTHOR}</li> 636 * <li>{@link #METADATA_KEY_WRITER}</li> 637 * <li>{@link #METADATA_KEY_COMPOSER}</li> 638 * <li>{@link #METADATA_KEY_DATE}</li> 639 * <li>{@link #METADATA_KEY_GENRE}</li> 640 * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li> 641 * <li>{@link #METADATA_KEY_ART_URI}</li> 642 * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li> 643 * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li> 644 * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li> 645 * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li> 646 * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li> 647 * </ul> 648 * <p> 649 * Uris for artwork should use the content:// style and support 650 * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork 651 * through {@link ContentResolver#openTypedAssetFileDescriptor(Uri, 652 * String, Bundle)}. 653 * 654 * @param key The key for referencing this value 655 * @param value The String value to store 656 * @return The Builder to allow chaining 657 */ putString(String key, String value)658 public Builder putString(String key, String value) { 659 if (METADATA_KEYS_TYPE.containsKey(key)) { 660 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) { 661 throw new IllegalArgumentException("The " + key 662 + " key cannot be used to put a String"); 663 } 664 } 665 mBundle.putCharSequence(key, value); 666 return this; 667 } 668 669 /** 670 * Put a long value into the metadata. Custom keys may be used, but if 671 * the METADATA_KEYs defined in this class are used they may only be one 672 * of the following: 673 * <ul> 674 * <li>{@link #METADATA_KEY_DURATION}</li> 675 * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li> 676 * <li>{@link #METADATA_KEY_NUM_TRACKS}</li> 677 * <li>{@link #METADATA_KEY_DISC_NUMBER}</li> 678 * <li>{@link #METADATA_KEY_YEAR}</li> 679 * </ul> 680 * 681 * @param key The key for referencing this value 682 * @param value The long value to store 683 * @return The Builder to allow chaining 684 */ putLong(String key, long value)685 public Builder putLong(String key, long value) { 686 if (METADATA_KEYS_TYPE.containsKey(key)) { 687 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) { 688 throw new IllegalArgumentException("The " + key 689 + " key cannot be used to put a long"); 690 } 691 } 692 mBundle.putLong(key, value); 693 return this; 694 } 695 696 /** 697 * Put a {@link Rating} into the metadata. Custom keys may be used, but 698 * if the METADATA_KEYs defined in this class are used they may only be 699 * one of the following: 700 * <ul> 701 * <li>{@link #METADATA_KEY_RATING}</li> 702 * <li>{@link #METADATA_KEY_USER_RATING}</li> 703 * </ul> 704 * 705 * @param key The key for referencing this value 706 * @param value The Rating value to store 707 * @return The Builder to allow chaining 708 */ putRating(String key, Rating value)709 public Builder putRating(String key, Rating value) { 710 if (METADATA_KEYS_TYPE.containsKey(key)) { 711 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) { 712 throw new IllegalArgumentException("The " + key 713 + " key cannot be used to put a Rating"); 714 } 715 } 716 mBundle.putParcelable(key, value); 717 return this; 718 } 719 720 /** 721 * Put a {@link Bitmap} into the metadata. Custom keys may be used, but 722 * if the METADATA_KEYs defined in this class are used they may only be 723 * one of the following: 724 * <ul> 725 * <li>{@link #METADATA_KEY_ART}</li> 726 * <li>{@link #METADATA_KEY_ALBUM_ART}</li> 727 * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li> 728 * </ul> 729 * <p> 730 * Large bitmaps may be scaled down by the system. To pass full 731 * resolution images {@link Uri Uris} should be used with 732 * {@link #putString}. 733 * 734 * @param key The key for referencing this value 735 * @param value The Bitmap to store 736 * @return The Builder to allow chaining 737 */ putBitmap(String key, Bitmap value)738 public Builder putBitmap(String key, Bitmap value) { 739 if (METADATA_KEYS_TYPE.containsKey(key)) { 740 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) { 741 throw new IllegalArgumentException("The " + key 742 + " key cannot be used to put a Bitmap"); 743 } 744 } 745 mBundle.putParcelable(key, value); 746 return this; 747 } 748 749 /** 750 * Creates a {@link MediaMetadata} instance with the specified fields. 751 * 752 * @return The new MediaMetadata instance 753 */ build()754 public MediaMetadata build() { 755 return new MediaMetadata(mBundle); 756 } 757 scaleBitmap(Bitmap bmp, int maxSize)758 private Bitmap scaleBitmap(Bitmap bmp, int maxSize) { 759 float maxSizeF = maxSize; 760 float widthScale = maxSizeF / bmp.getWidth(); 761 float heightScale = maxSizeF / bmp.getHeight(); 762 float scale = Math.min(widthScale, heightScale); 763 int height = (int) (bmp.getHeight() * scale); 764 int width = (int) (bmp.getWidth() * scale); 765 return Bitmap.createScaledBitmap(bmp, width, height, true); 766 } 767 } 768 } 769