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