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 static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 19 20 import android.graphics.Bitmap; 21 import android.net.Uri; 22 import android.os.Build; 23 import android.os.Bundle; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.support.annotation.RestrictTo; 27 import android.support.annotation.StringDef; 28 import android.support.v4.media.session.MediaControllerCompat.TransportControls; 29 import android.support.v4.util.ArrayMap; 30 import android.text.TextUtils; 31 import android.util.Log; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.util.Set; 36 37 /** 38 * Contains metadata about an item, such as the title, artist, etc. 39 */ 40 public 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>(); METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT)307 METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT)308 METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG)309 METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT)310 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT)311 METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT)312 METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT)313 METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT)314 METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT)315 METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG)316 METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT)317 METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG)318 METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG)319 METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG)320 METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT)321 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP)322 METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP); METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT)323 METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP)324 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP); METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT)325 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING)326 METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING); METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING)327 METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT)328 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT)329 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT)330 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP)331 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP); METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT)332 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT)333 METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_BT_FOLDER_TYPE, METADATA_TYPE_LONG)334 METADATA_KEYS_TYPE.put(METADATA_KEY_BT_FOLDER_TYPE, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT)335 METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT); METADATA_KEYS_TYPE.put(METADATA_KEY_ADVERTISEMENT, METADATA_TYPE_LONG)336 METADATA_KEYS_TYPE.put(METADATA_KEY_ADVERTISEMENT, METADATA_TYPE_LONG); METADATA_KEYS_TYPE.put(METADATA_KEY_DOWNLOAD_STATUS, 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 MediaMetadataCompat(Bundle bundle)366 MediaMetadataCompat(Bundle bundle) { 367 mBundle = new Bundle(bundle); 368 } 369 MediaMetadataCompat(Parcel in)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 */ containsKey(String key)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 */ getText(@extKey String key)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 */ getString(@extKey String key)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 */ getLong(@ongKey String key)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 */ getRating(@atingKey String key)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 */ getBitmap(@itmapKey String key)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 */ getDescription()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 describeContents()553 public int describeContents() { 554 return 0; 555 } 556 557 @Override writeToParcel(Parcel dest, int flags)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 */ size()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 */ keySet()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 */ getBundle()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 */ fromMediaMetadata(Object metadataObj)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 */ getMediaMetadata()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 */ Builder()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 */ Builder(MediaMetadataCompat source)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 * 682 * @param source The original metadata to copy. 683 * @param maxBitmapSize The maximum height/width for bitmaps contained 684 * in the metadata. 685 * @hide 686 */ 687 @RestrictTo(LIBRARY_GROUP) Builder(MediaMetadataCompat source, int maxBitmapSize)688 public Builder(MediaMetadataCompat source, int maxBitmapSize) { 689 this(source); 690 for (String key : mBundle.keySet()) { 691 Object value = mBundle.get(key); 692 if (value instanceof Bitmap) { 693 Bitmap bmp = (Bitmap) value; 694 if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) { 695 putBitmap(key, scaleBitmap(bmp, maxBitmapSize)); 696 } 697 } 698 } 699 } 700 701 /** 702 * Put a CharSequence value into the metadata. Custom keys may be used, 703 * but if the METADATA_KEYs defined in this class are used they may only 704 * be one of the following: 705 * <ul> 706 * <li>{@link #METADATA_KEY_TITLE}</li> 707 * <li>{@link #METADATA_KEY_ARTIST}</li> 708 * <li>{@link #METADATA_KEY_ALBUM}</li> 709 * <li>{@link #METADATA_KEY_AUTHOR}</li> 710 * <li>{@link #METADATA_KEY_WRITER}</li> 711 * <li>{@link #METADATA_KEY_COMPOSER}</li> 712 * <li>{@link #METADATA_KEY_DATE}</li> 713 * <li>{@link #METADATA_KEY_GENRE}</li> 714 * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li> 715 * <li>{@link #METADATA_KEY_ART_URI}</li> 716 * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li> 717 * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li> 718 * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li> 719 * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li> 720 * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li> 721 * </ul> 722 * 723 * @param key The key for referencing this value 724 * @param value The CharSequence value to store 725 * @return The Builder to allow chaining 726 */ putText(@extKey String key, CharSequence value)727 public Builder putText(@TextKey String key, CharSequence value) { 728 if (METADATA_KEYS_TYPE.containsKey(key)) { 729 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) { 730 throw new IllegalArgumentException("The " + key 731 + " key cannot be used to put a CharSequence"); 732 } 733 } 734 mBundle.putCharSequence(key, value); 735 return this; 736 } 737 738 /** 739 * Put a String value into the metadata. Custom keys may be used, but if 740 * the METADATA_KEYs defined in this class are used they may only be one 741 * of the following: 742 * <ul> 743 * <li>{@link #METADATA_KEY_TITLE}</li> 744 * <li>{@link #METADATA_KEY_ARTIST}</li> 745 * <li>{@link #METADATA_KEY_ALBUM}</li> 746 * <li>{@link #METADATA_KEY_AUTHOR}</li> 747 * <li>{@link #METADATA_KEY_WRITER}</li> 748 * <li>{@link #METADATA_KEY_COMPOSER}</li> 749 * <li>{@link #METADATA_KEY_DATE}</li> 750 * <li>{@link #METADATA_KEY_GENRE}</li> 751 * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li> 752 * <li>{@link #METADATA_KEY_ART_URI}</li> 753 * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li> 754 * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li> 755 * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li> 756 * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li> 757 * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</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 */ putString(@extKey String key, String value)764 public Builder putString(@TextKey String key, String value) { 765 if (METADATA_KEYS_TYPE.containsKey(key)) { 766 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) { 767 throw new IllegalArgumentException("The " + key 768 + " key cannot be used to put a String"); 769 } 770 } 771 mBundle.putCharSequence(key, value); 772 return this; 773 } 774 775 /** 776 * Put a long value into the metadata. Custom keys may be used, but if 777 * the METADATA_KEYs defined in this class are used they may only be one 778 * of the following: 779 * <ul> 780 * <li>{@link #METADATA_KEY_DURATION}</li> 781 * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li> 782 * <li>{@link #METADATA_KEY_NUM_TRACKS}</li> 783 * <li>{@link #METADATA_KEY_DISC_NUMBER}</li> 784 * <li>{@link #METADATA_KEY_YEAR}</li> 785 * <li>{@link #METADATA_KEY_BT_FOLDER_TYPE}</li> 786 * <li>{@link #METADATA_KEY_ADVERTISEMENT}</li> 787 * <li>{@link #METADATA_KEY_DOWNLOAD_STATUS}</li> 788 * </ul> 789 * 790 * @param key The key for referencing this value 791 * @param value The String value to store 792 * @return The Builder to allow chaining 793 */ putLong(@ongKey String key, long value)794 public Builder putLong(@LongKey String key, long value) { 795 if (METADATA_KEYS_TYPE.containsKey(key)) { 796 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) { 797 throw new IllegalArgumentException("The " + key 798 + " key cannot be used to put a long"); 799 } 800 } 801 mBundle.putLong(key, value); 802 return this; 803 } 804 805 /** 806 * Put a {@link RatingCompat} 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_RATING}</li> 811 * <li>{@link #METADATA_KEY_USER_RATING}</li> 812 * </ul> 813 * 814 * @param key The key for referencing this value 815 * @param value The String value to store 816 * @return The Builder to allow chaining 817 */ putRating(@atingKey String key, RatingCompat value)818 public Builder putRating(@RatingKey String key, RatingCompat value) { 819 if (METADATA_KEYS_TYPE.containsKey(key)) { 820 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) { 821 throw new IllegalArgumentException("The " + key 822 + " key cannot be used to put a Rating"); 823 } 824 } 825 if (Build.VERSION.SDK_INT >= 19) { 826 // On platform version 19 or higher, use Rating instead of RatingCompat so mBundle 827 // can be unmarshalled. 828 mBundle.putParcelable(key, (Parcelable) value.getRating()); 829 } else { 830 mBundle.putParcelable(key, value); 831 } 832 return this; 833 } 834 835 /** 836 * Put a {@link Bitmap} into the metadata. Custom keys may be used, but 837 * if the METADATA_KEYs defined in this class are used they may only be 838 * one of the following: 839 * <ul> 840 * <li>{@link #METADATA_KEY_ART}</li> 841 * <li>{@link #METADATA_KEY_ALBUM_ART}</li> 842 * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li> 843 * </ul> 844 * Large bitmaps may be scaled down when 845 * {@link android.support.v4.media.session.MediaSessionCompat#setMetadata} is called. 846 * To pass full resolution images {@link Uri Uris} should be used with 847 * {@link #putString}. 848 * 849 * @param key The key for referencing this value 850 * @param value The Bitmap to store 851 * @return The Builder to allow chaining 852 */ putBitmap(@itmapKey String key, Bitmap value)853 public Builder putBitmap(@BitmapKey String key, Bitmap value) { 854 if (METADATA_KEYS_TYPE.containsKey(key)) { 855 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) { 856 throw new IllegalArgumentException("The " + key 857 + " key cannot be used to put a Bitmap"); 858 } 859 } 860 mBundle.putParcelable(key, value); 861 return this; 862 } 863 864 /** 865 * Creates a {@link MediaMetadataCompat} instance with the specified fields. 866 * 867 * @return The new MediaMetadata instance 868 */ build()869 public MediaMetadataCompat build() { 870 return new MediaMetadataCompat(mBundle); 871 } 872 scaleBitmap(Bitmap bmp, int maxSize)873 private Bitmap scaleBitmap(Bitmap bmp, int maxSize) { 874 float maxSizeF = maxSize; 875 float widthScale = maxSizeF / bmp.getWidth(); 876 float heightScale = maxSizeF / bmp.getHeight(); 877 float scale = Math.min(widthScale, heightScale); 878 int height = (int) (bmp.getHeight() * scale); 879 int width = (int) (bmp.getWidth() * scale); 880 return Bitmap.createScaledBitmap(bmp, width, height, true); 881 } 882 } 883 884 } 885