MediaMetadataCompat.java revision 7792ab6765c39e38bf003c32f282ba5edfd6936d
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 * @hide 249 */ 250 @RestrictTo(LIBRARY_GROUP) 251 @StringDef({METADATA_KEY_TITLE, METADATA_KEY_ARTIST, METADATA_KEY_ALBUM, METADATA_KEY_AUTHOR, 252 METADATA_KEY_WRITER, METADATA_KEY_COMPOSER, METADATA_KEY_COMPILATION, 253 METADATA_KEY_DATE, METADATA_KEY_GENRE, METADATA_KEY_ALBUM_ARTIST, METADATA_KEY_ART_URI, 254 METADATA_KEY_ALBUM_ART_URI, METADATA_KEY_DISPLAY_TITLE, METADATA_KEY_DISPLAY_SUBTITLE, 255 METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_KEY_DISPLAY_ICON_URI, 256 METADATA_KEY_MEDIA_ID, METADATA_KEY_MEDIA_URI}) 257 @Retention(RetentionPolicy.SOURCE) 258 public @interface TextKey {} 259 260 /** 261 * @hide 262 */ 263 @RestrictTo(LIBRARY_GROUP) 264 @StringDef({METADATA_KEY_DURATION, METADATA_KEY_YEAR, METADATA_KEY_TRACK_NUMBER, 265 METADATA_KEY_NUM_TRACKS, METADATA_KEY_DISC_NUMBER, METADATA_KEY_BT_FOLDER_TYPE, 266 METADATA_KEY_ADVERTISEMENT}) 267 @Retention(RetentionPolicy.SOURCE) 268 public @interface LongKey {} 269 270 /** 271 * @hide 272 */ 273 @RestrictTo(LIBRARY_GROUP) 274 @StringDef({METADATA_KEY_ART, METADATA_KEY_ALBUM_ART, METADATA_KEY_DISPLAY_ICON}) 275 @Retention(RetentionPolicy.SOURCE) 276 public @interface BitmapKey {} 277 278 /** 279 * @hide 280 */ 281 @RestrictTo(LIBRARY_GROUP) 282 @StringDef({METADATA_KEY_USER_RATING, METADATA_KEY_RATING}) 283 @Retention(RetentionPolicy.SOURCE) 284 public @interface RatingKey {} 285 286 static final int METADATA_TYPE_LONG = 0; 287 static final int METADATA_TYPE_TEXT = 1; 288 static final int METADATA_TYPE_BITMAP = 2; 289 static final int METADATA_TYPE_RATING = 3; 290 static final ArrayMap<String, Integer> METADATA_KEYS_TYPE; 291 292 static { 293 METADATA_KEYS_TYPE = new ArrayMap<String, Integer>(); 294 METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT); 295 METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT); 296 METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG); 297 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT); 298 METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT); 299 METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT); 300 METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT); 301 METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT); 302 METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT); 303 METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG); 304 METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT); 305 METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG); 306 METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG); 307 METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG); 308 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT); 309 METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP); 310 METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT); 311 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP); 312 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT); 313 METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING); 314 METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING); 315 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT); 316 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT); 317 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT); 318 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP); 319 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT); 320 METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT); 321 METADATA_KEYS_TYPE.put(METADATA_KEY_BT_FOLDER_TYPE, METADATA_TYPE_LONG); 322 METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT); 323 METADATA_KEYS_TYPE.put(METADATA_KEY_ADVERTISEMENT, METADATA_TYPE_LONG); 324 } 325 326 private static final @TextKey String[] PREFERRED_DESCRIPTION_ORDER = { 327 METADATA_KEY_TITLE, 328 METADATA_KEY_ARTIST, 329 METADATA_KEY_ALBUM, 330 METADATA_KEY_ALBUM_ARTIST, 331 METADATA_KEY_WRITER, 332 METADATA_KEY_AUTHOR, 333 METADATA_KEY_COMPOSER 334 }; 335 336 private static final @BitmapKey String[] PREFERRED_BITMAP_ORDER = { 337 METADATA_KEY_DISPLAY_ICON, 338 METADATA_KEY_ART, 339 METADATA_KEY_ALBUM_ART 340 }; 341 342 private static final @TextKey String[] PREFERRED_URI_ORDER = { 343 METADATA_KEY_DISPLAY_ICON_URI, 344 METADATA_KEY_ART_URI, 345 METADATA_KEY_ALBUM_ART_URI 346 }; 347 348 final Bundle mBundle; 349 private Object mMetadataObj; 350 private MediaDescriptionCompat mDescription; 351 352 MediaMetadataCompat(Bundle bundle) { 353 mBundle = new Bundle(bundle); 354 } 355 356 MediaMetadataCompat(Parcel in) { 357 mBundle = in.readBundle(); 358 } 359 360 /** 361 * Returns true if the given key is contained in the metadata 362 * 363 * @param key a String key 364 * @return true if the key exists in this metadata, false otherwise 365 */ 366 public boolean containsKey(String key) { 367 return mBundle.containsKey(key); 368 } 369 370 /** 371 * Returns the value associated with the given key, or null if no mapping of 372 * the desired type exists for the given key or a null value is explicitly 373 * associated with the key. 374 * 375 * @param key The key the value is stored under 376 * @return a CharSequence value, or null 377 */ 378 public CharSequence getText(@TextKey String key) { 379 return mBundle.getCharSequence(key); 380 } 381 382 /** 383 * Returns the value associated with the given key, or null if no mapping of 384 * the desired type exists for the given key or a null value is explicitly 385 * associated with the key. 386 * 387 * @param key The key the value is stored under 388 * @return a String value, or null 389 */ 390 public String getString(@TextKey String key) { 391 CharSequence text = mBundle.getCharSequence(key); 392 if (text != null) { 393 return text.toString(); 394 } 395 return null; 396 } 397 398 /** 399 * Returns the value associated with the given key, or 0L if no long exists 400 * for the given key. 401 * 402 * @param key The key the value is stored under 403 * @return a long value 404 */ 405 public long getLong(@LongKey String key) { 406 return mBundle.getLong(key, 0); 407 } 408 409 /** 410 * Return a {@link RatingCompat} for the given key or null if no rating exists for 411 * the given key. 412 * 413 * @param key The key the value is stored under 414 * @return A {@link RatingCompat} or null 415 */ 416 public RatingCompat getRating(@RatingKey String key) { 417 RatingCompat rating = null; 418 try { 419 if (Build.VERSION.SDK_INT >= 19) { 420 // On platform version 19 or higher, mBundle stores a Rating object. Convert it to 421 // RatingCompat. 422 rating = RatingCompat.fromRating(mBundle.getParcelable(key)); 423 } else { 424 rating = mBundle.getParcelable(key); 425 } 426 } catch (Exception e) { 427 // ignore, value was not a bitmap 428 Log.w(TAG, "Failed to retrieve a key as Rating.", e); 429 } 430 return rating; 431 } 432 433 /** 434 * Return a {@link Bitmap} for the given key or null if no bitmap exists for 435 * the given key. 436 * 437 * @param key The key the value is stored under 438 * @return A {@link Bitmap} or null 439 */ 440 public Bitmap getBitmap(@BitmapKey String key) { 441 Bitmap bmp = null; 442 try { 443 bmp = mBundle.getParcelable(key); 444 } catch (Exception e) { 445 // ignore, value was not a bitmap 446 Log.w(TAG, "Failed to retrieve a key as Bitmap.", e); 447 } 448 return bmp; 449 } 450 451 /** 452 * Returns a simple description of this metadata for display purposes. 453 * 454 * @return A simple description of this metadata. 455 */ 456 public MediaDescriptionCompat getDescription() { 457 if (mDescription != null) { 458 return mDescription; 459 } 460 461 String mediaId = getString(METADATA_KEY_MEDIA_ID); 462 463 CharSequence[] text = new CharSequence[3]; 464 Bitmap icon = null; 465 Uri iconUri = null; 466 467 // First handle the case where display data is set already 468 CharSequence displayText = getText(METADATA_KEY_DISPLAY_TITLE); 469 if (!TextUtils.isEmpty(displayText)) { 470 // If they have a display title use only display data, otherwise use 471 // our best bets 472 text[0] = displayText; 473 text[1] = getText(METADATA_KEY_DISPLAY_SUBTITLE); 474 text[2] = getText(METADATA_KEY_DISPLAY_DESCRIPTION); 475 } else { 476 // Use whatever fields we can 477 int textIndex = 0; 478 int keyIndex = 0; 479 while (textIndex < text.length && keyIndex < PREFERRED_DESCRIPTION_ORDER.length) { 480 CharSequence next = getText(PREFERRED_DESCRIPTION_ORDER[keyIndex++]); 481 if (!TextUtils.isEmpty(next)) { 482 // Fill in the next empty bit of text 483 text[textIndex++] = next; 484 } 485 } 486 } 487 488 // Get the best art bitmap we can find 489 for (int i = 0; i < PREFERRED_BITMAP_ORDER.length; i++) { 490 Bitmap next = getBitmap(PREFERRED_BITMAP_ORDER[i]); 491 if (next != null) { 492 icon = next; 493 break; 494 } 495 } 496 497 // Get the best Uri we can find 498 for (int i = 0; i < PREFERRED_URI_ORDER.length; i++) { 499 String next = getString(PREFERRED_URI_ORDER[i]); 500 if (!TextUtils.isEmpty(next)) { 501 iconUri = Uri.parse(next); 502 break; 503 } 504 } 505 506 Uri mediaUri = null; 507 String mediaUriStr = getString(METADATA_KEY_MEDIA_URI); 508 if (!TextUtils.isEmpty(mediaUriStr)) { 509 mediaUri = Uri.parse(mediaUriStr); 510 } 511 512 MediaDescriptionCompat.Builder bob = new MediaDescriptionCompat.Builder(); 513 bob.setMediaId(mediaId); 514 bob.setTitle(text[0]); 515 bob.setSubtitle(text[1]); 516 bob.setDescription(text[2]); 517 bob.setIconBitmap(icon); 518 bob.setIconUri(iconUri); 519 bob.setMediaUri(mediaUri); 520 if (mBundle.containsKey(METADATA_KEY_BT_FOLDER_TYPE)) { 521 Bundle bundle = new Bundle(); 522 bundle.putLong(MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE, 523 getLong(METADATA_KEY_BT_FOLDER_TYPE)); 524 bob.setExtras(bundle); 525 } 526 mDescription = bob.build(); 527 528 return mDescription; 529 } 530 531 @Override 532 public int describeContents() { 533 return 0; 534 } 535 536 @Override 537 public void writeToParcel(Parcel dest, int flags) { 538 dest.writeBundle(mBundle); 539 } 540 541 /** 542 * Get the number of fields in this metadata. 543 * 544 * @return The number of fields in the metadata. 545 */ 546 public int size() { 547 return mBundle.size(); 548 } 549 550 /** 551 * Returns a Set containing the Strings used as keys in this metadata. 552 * 553 * @return a Set of String keys 554 */ 555 public Set<String> keySet() { 556 return mBundle.keySet(); 557 } 558 559 /** 560 * Gets the bundle backing the metadata object. This is available to support 561 * backwards compatibility. Apps should not modify the bundle directly. 562 * 563 * @return The Bundle backing this metadata. 564 */ 565 public Bundle getBundle() { 566 return mBundle; 567 } 568 569 /** 570 * Creates an instance from a framework {@link android.media.MediaMetadata} 571 * object. 572 * <p> 573 * This method is only supported on 574 * {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later. 575 * </p> 576 * 577 * @param metadataObj A {@link android.media.MediaMetadata} object, or null 578 * if none. 579 * @return An equivalent {@link MediaMetadataCompat} object, or null if 580 * none. 581 */ 582 public static MediaMetadataCompat fromMediaMetadata(Object metadataObj) { 583 if (metadataObj != null && Build.VERSION.SDK_INT >= 21) { 584 Parcel p = Parcel.obtain(); 585 MediaMetadataCompatApi21.writeToParcel(metadataObj, p, 0); 586 p.setDataPosition(0); 587 MediaMetadataCompat metadata = MediaMetadataCompat.CREATOR.createFromParcel(p); 588 p.recycle(); 589 metadata.mMetadataObj = metadataObj; 590 return metadata; 591 } else { 592 return null; 593 } 594 } 595 596 /** 597 * Gets the underlying framework {@link android.media.MediaMetadata} object. 598 * <p> 599 * This method is only supported on 600 * {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later. 601 * </p> 602 * 603 * @return An equivalent {@link android.media.MediaMetadata} object, or null 604 * if none. 605 */ 606 public Object getMediaMetadata() { 607 if (mMetadataObj == null && Build.VERSION.SDK_INT >= 21) { 608 Parcel p = Parcel.obtain(); 609 writeToParcel(p, 0); 610 p.setDataPosition(0); 611 mMetadataObj = MediaMetadataCompatApi21.createFromParcel(p); 612 p.recycle(); 613 } 614 return mMetadataObj; 615 } 616 617 public static final Parcelable.Creator<MediaMetadataCompat> CREATOR = 618 new Parcelable.Creator<MediaMetadataCompat>() { 619 @Override 620 public MediaMetadataCompat createFromParcel(Parcel in) { 621 return new MediaMetadataCompat(in); 622 } 623 624 @Override 625 public MediaMetadataCompat[] newArray(int size) { 626 return new MediaMetadataCompat[size]; 627 } 628 }; 629 630 /** 631 * Use to build MediaMetadata objects. The system defined metadata keys must 632 * use the appropriate data type. 633 */ 634 public static final class Builder { 635 private final Bundle mBundle; 636 637 /** 638 * Create an empty Builder. Any field that should be included in the 639 * {@link MediaMetadataCompat} must be added. 640 */ 641 public Builder() { 642 mBundle = new Bundle(); 643 } 644 645 /** 646 * Create a Builder using a {@link MediaMetadataCompat} instance to set the 647 * initial values. All fields in the source metadata will be included in 648 * the new metadata. Fields can be overwritten by adding the same key. 649 * 650 * @param source 651 */ 652 public Builder(MediaMetadataCompat source) { 653 mBundle = new Bundle(source.mBundle); 654 } 655 656 /** 657 * Create a Builder using a {@link MediaMetadataCompat} instance to set 658 * initial values, but replace bitmaps with a scaled down copy if they 659 * are larger than maxBitmapSize. 660 * 661 * @param source The original metadata to copy. 662 * @param maxBitmapSize The maximum height/width for bitmaps contained 663 * in the metadata. 664 * @hide 665 */ 666 @RestrictTo(LIBRARY_GROUP) 667 public Builder(MediaMetadataCompat source, int maxBitmapSize) { 668 this(source); 669 for (String key : mBundle.keySet()) { 670 Object value = mBundle.get(key); 671 if (value instanceof Bitmap) { 672 Bitmap bmp = (Bitmap) value; 673 if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) { 674 putBitmap(key, scaleBitmap(bmp, maxBitmapSize)); 675 } 676 } 677 } 678 } 679 680 /** 681 * Put a CharSequence value into the metadata. Custom keys may be used, 682 * but if the METADATA_KEYs defined in this class are used they may only 683 * be one of the following: 684 * <ul> 685 * <li>{@link #METADATA_KEY_TITLE}</li> 686 * <li>{@link #METADATA_KEY_ARTIST}</li> 687 * <li>{@link #METADATA_KEY_ALBUM}</li> 688 * <li>{@link #METADATA_KEY_AUTHOR}</li> 689 * <li>{@link #METADATA_KEY_WRITER}</li> 690 * <li>{@link #METADATA_KEY_COMPOSER}</li> 691 * <li>{@link #METADATA_KEY_DATE}</li> 692 * <li>{@link #METADATA_KEY_GENRE}</li> 693 * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li> 694 * <li>{@link #METADATA_KEY_ART_URI}</li> 695 * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li> 696 * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li> 697 * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li> 698 * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li> 699 * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li> 700 * </ul> 701 * 702 * @param key The key for referencing this value 703 * @param value The CharSequence value to store 704 * @return The Builder to allow chaining 705 */ 706 public Builder putText(@TextKey String key, CharSequence value) { 707 if (METADATA_KEYS_TYPE.containsKey(key)) { 708 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) { 709 throw new IllegalArgumentException("The " + key 710 + " key cannot be used to put a CharSequence"); 711 } 712 } 713 mBundle.putCharSequence(key, value); 714 return this; 715 } 716 717 /** 718 * Put a String value into the metadata. Custom keys may be used, but if 719 * the METADATA_KEYs defined in this class are used they may only be one 720 * of the following: 721 * <ul> 722 * <li>{@link #METADATA_KEY_TITLE}</li> 723 * <li>{@link #METADATA_KEY_ARTIST}</li> 724 * <li>{@link #METADATA_KEY_ALBUM}</li> 725 * <li>{@link #METADATA_KEY_AUTHOR}</li> 726 * <li>{@link #METADATA_KEY_WRITER}</li> 727 * <li>{@link #METADATA_KEY_COMPOSER}</li> 728 * <li>{@link #METADATA_KEY_DATE}</li> 729 * <li>{@link #METADATA_KEY_GENRE}</li> 730 * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li> 731 * <li>{@link #METADATA_KEY_ART_URI}</li> 732 * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li> 733 * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li> 734 * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li> 735 * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li> 736 * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li> 737 * </ul> 738 * 739 * @param key The key for referencing this value 740 * @param value The String value to store 741 * @return The Builder to allow chaining 742 */ 743 public Builder putString(@TextKey String key, String value) { 744 if (METADATA_KEYS_TYPE.containsKey(key)) { 745 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) { 746 throw new IllegalArgumentException("The " + key 747 + " key cannot be used to put a String"); 748 } 749 } 750 mBundle.putCharSequence(key, value); 751 return this; 752 } 753 754 /** 755 * Put a long value into the metadata. Custom keys may be used, but if 756 * the METADATA_KEYs defined in this class are used they may only be one 757 * of the following: 758 * <ul> 759 * <li>{@link #METADATA_KEY_DURATION}</li> 760 * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li> 761 * <li>{@link #METADATA_KEY_NUM_TRACKS}</li> 762 * <li>{@link #METADATA_KEY_DISC_NUMBER}</li> 763 * <li>{@link #METADATA_KEY_YEAR}</li> 764 * <li>{@link #METADATA_KEY_ADVERTISEMENT}</li> 765 * </ul> 766 * 767 * @param key The key for referencing this value 768 * @param value The String value to store 769 * @return The Builder to allow chaining 770 */ 771 public Builder putLong(@LongKey String key, long value) { 772 if (METADATA_KEYS_TYPE.containsKey(key)) { 773 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) { 774 throw new IllegalArgumentException("The " + key 775 + " key cannot be used to put a long"); 776 } 777 } 778 mBundle.putLong(key, value); 779 return this; 780 } 781 782 /** 783 * Put a {@link RatingCompat} into the metadata. Custom keys may be used, but 784 * if the METADATA_KEYs defined in this class are used they may only be 785 * one of the following: 786 * <ul> 787 * <li>{@link #METADATA_KEY_RATING}</li> 788 * <li>{@link #METADATA_KEY_USER_RATING}</li> 789 * </ul> 790 * 791 * @param key The key for referencing this value 792 * @param value The String value to store 793 * @return The Builder to allow chaining 794 */ 795 public Builder putRating(@RatingKey String key, RatingCompat value) { 796 if (METADATA_KEYS_TYPE.containsKey(key)) { 797 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) { 798 throw new IllegalArgumentException("The " + key 799 + " key cannot be used to put a Rating"); 800 } 801 } 802 if (Build.VERSION.SDK_INT >= 19) { 803 // On platform version 19 or higher, use Rating instead of RatingCompat so mBundle 804 // can be unmarshalled. 805 mBundle.putParcelable(key, (Parcelable) value.getRating()); 806 } else { 807 mBundle.putParcelable(key, value); 808 } 809 return this; 810 } 811 812 /** 813 * Put a {@link Bitmap} into the metadata. Custom keys may be used, but 814 * if the METADATA_KEYs defined in this class are used they may only be 815 * one of the following: 816 * <ul> 817 * <li>{@link #METADATA_KEY_ART}</li> 818 * <li>{@link #METADATA_KEY_ALBUM_ART}</li> 819 * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li> 820 * </ul> 821 * Large bitmaps may be scaled down when 822 * {@link android.support.v4.media.session.MediaSessionCompat#setMetadata} is called. 823 * To pass full resolution images {@link Uri Uris} should be used with 824 * {@link #putString}. 825 * 826 * @param key The key for referencing this value 827 * @param value The Bitmap to store 828 * @return The Builder to allow chaining 829 */ 830 public Builder putBitmap(@BitmapKey String key, Bitmap value) { 831 if (METADATA_KEYS_TYPE.containsKey(key)) { 832 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) { 833 throw new IllegalArgumentException("The " + key 834 + " key cannot be used to put a Bitmap"); 835 } 836 } 837 mBundle.putParcelable(key, value); 838 return this; 839 } 840 841 /** 842 * Creates a {@link MediaMetadataCompat} instance with the specified fields. 843 * 844 * @return The new MediaMetadata instance 845 */ 846 public MediaMetadataCompat build() { 847 return new MediaMetadataCompat(mBundle); 848 } 849 850 private Bitmap scaleBitmap(Bitmap bmp, int maxSize) { 851 float maxSizeF = maxSize; 852 float widthScale = maxSizeF / bmp.getWidth(); 853 float heightScale = maxSizeF / bmp.getHeight(); 854 float scale = Math.min(widthScale, heightScale); 855 int height = (int) (bmp.getHeight() * scale); 856 int width = (int) (bmp.getWidth() * scale); 857 return Bitmap.createScaledBitmap(bmp, width, height, true); 858 } 859 } 860 861} 862