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