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