MediaMetadataCompat.java revision 33cd4ae9d391f85b812fa666b942dc8ed3ebbd31
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 android.graphics.Bitmap; 19import android.os.Build; 20import android.os.Bundle; 21import android.os.Parcel; 22import android.os.Parcelable; 23import android.support.v4.util.ArrayMap; 24import android.util.Log; 25 26import java.util.Set; 27 28/** 29 * Contains metadata about an item, such as the title, artist, etc. 30 */ 31public final class MediaMetadataCompat implements Parcelable { 32 private static final String TAG = "MediaMetadata"; 33 34 /** 35 * The title of the media. 36 */ 37 public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE"; 38 39 /** 40 * The artist of the media. 41 */ 42 public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST"; 43 44 /** 45 * The duration of the media in ms. A negative duration indicates that the 46 * duration is unknown (or infinite). 47 */ 48 public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION"; 49 50 /** 51 * The album title for the media. 52 */ 53 public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM"; 54 55 /** 56 * The author of the media. 57 */ 58 public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR"; 59 60 /** 61 * The writer of the media. 62 */ 63 public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER"; 64 65 /** 66 * The composer of the media. 67 */ 68 public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER"; 69 70 /** 71 * The compilation status of the media. 72 */ 73 public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION"; 74 75 /** 76 * The date the media was created or published as TODO determine format. 77 */ 78 public static final String METADATA_KEY_DATE = "android.media.metadata.DATE"; 79 80 /** 81 * The year the media was created or published as a long. 82 */ 83 public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR"; 84 85 /** 86 * The genre of the media. 87 */ 88 public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE"; 89 90 /** 91 * The track number for the media. 92 */ 93 public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER"; 94 95 /** 96 * The number of tracks in the media's original source. 97 */ 98 public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS"; 99 100 /** 101 * The disc number for the media's original source. 102 */ 103 public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER"; 104 105 /** 106 * The artist for the album of the media's original source. 107 */ 108 public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST"; 109 110 /** 111 * The artwork for the media as a {@link Bitmap}. 112 */ 113 public static final String METADATA_KEY_ART = "android.media.metadata.ART"; 114 115 /** 116 * The artwork for the media as a Uri style String. 117 */ 118 public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI"; 119 120 /** 121 * The artwork for the album of the media's original source as a 122 * {@link Bitmap}. 123 */ 124 public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART"; 125 126 /** 127 * The artwork for the album of the media's original source as a Uri style 128 * String. 129 */ 130 public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI"; 131 132 /** 133 * The user's rating for the media. 134 * 135 * @see RatingCompat 136 */ 137 public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING"; 138 139 /** 140 * The overall rating for the media. 141 * 142 * @see RatingCompat 143 */ 144 public static final String METADATA_KEY_RATING = "android.media.metadata.RATING"; 145 146 /** 147 * A title that is suitable for display to the user. This will generally be 148 * the same as {@link #METADATA_KEY_TITLE} but may differ for some formats. 149 * When displaying media described by this metadata this should be preferred 150 * if present. 151 */ 152 public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE"; 153 154 /** 155 * A subtitle that is suitable for display to the user. When displaying a 156 * second line for media described by this metadata this should be preferred 157 * to other fields if present. 158 */ 159 public static final String METADATA_KEY_DISPLAY_SUBTITLE 160 = "android.media.metadata.DISPLAY_SUBTITLE"; 161 162 /** 163 * A description that is suitable for display to the user. When displaying 164 * more information for media described by this metadata this should be 165 * preferred to other fields if present. 166 */ 167 public static final String METADATA_KEY_DISPLAY_DESCRIPTION 168 = "android.media.metadata.DISPLAY_DESCRIPTION"; 169 170 /** 171 * An icon or thumbnail that is suitable for display to the user. When 172 * displaying an icon for media described by this metadata this should be 173 * preferred to other fields if present. This must be a {@link Bitmap}. 174 */ 175 public static final String METADATA_KEY_DISPLAY_ICON 176 = "android.media.metadata.DISPLAY_ICON"; 177 178 /** 179 * An icon or thumbnail that is suitable for display to the user. When 180 * displaying more information for media described by this metadata the 181 * display description should be preferred to other fields when present. 182 * This must be a Uri style String. 183 */ 184 public static final String METADATA_KEY_DISPLAY_ICON_URI 185 = "android.media.metadata.DISPLAY_ICON_URI"; 186 187 private static final int METADATA_TYPE_LONG = 0; 188 private static final int METADATA_TYPE_TEXT = 1; 189 private static final int METADATA_TYPE_BITMAP = 2; 190 private static final int METADATA_TYPE_RATING = 3; 191 private static final ArrayMap<String, Integer> METADATA_KEYS_TYPE; 192 193 static { 194 METADATA_KEYS_TYPE = new ArrayMap<String, Integer>(); 195 METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT); 196 METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT); 197 METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG); 198 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT); 199 METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT); 200 METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT); 201 METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT); 202 METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT); 203 METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT); 204 METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG); 205 METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT); 206 METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG); 207 METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG); 208 METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG); 209 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT); 210 METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP); 211 METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT); 212 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP); 213 METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT); 214 METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING); 215 METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING); 216 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT); 217 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT); 218 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT); 219 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP); 220 METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT); 221 } 222 223 private final Bundle mBundle; 224 private Object mMetadataObj; 225 226 private MediaMetadataCompat(Bundle bundle) { 227 mBundle = new Bundle(bundle); 228 } 229 230 private MediaMetadataCompat(Parcel in) { 231 mBundle = in.readBundle(); 232 } 233 234 /** 235 * Returns true if the given key is contained in the metadata 236 * 237 * @param key a String key 238 * @return true if the key exists in this metadata, false otherwise 239 */ 240 public boolean containsKey(String key) { 241 return mBundle.containsKey(key); 242 } 243 244 /** 245 * Returns the value associated with the given key, or null if no mapping of 246 * the desired type exists for the given key or a null value is explicitly 247 * associated with the key. 248 * 249 * @param key The key the value is stored under 250 * @return a CharSequence value, or null 251 */ 252 public CharSequence getText(String key) { 253 return mBundle.getCharSequence(key); 254 } 255 256 /** 257 * Returns the value associated with the given key, or null if no mapping of 258 * the desired type exists for the given key or a null value is explicitly 259 * associated with the key. 260 * 261 * @param key The key the value is stored under 262 * @return a String value, or null 263 */ 264 public String getString(String key) { 265 CharSequence text = mBundle.getCharSequence(key); 266 if (text != null) { 267 return text.toString(); 268 } 269 return null; 270 } 271 272 /** 273 * Returns the value associated with the given key, or 0L if no long exists 274 * for the given key. 275 * 276 * @param key The key the value is stored under 277 * @return a long value 278 */ 279 public long getLong(String key) { 280 return mBundle.getLong(key, 0); 281 } 282 283 /** 284 * Return a {@link RatingCompat} for the given key or null if no rating exists for 285 * the given key. 286 * 287 * @param key The key the value is stored under 288 * @return A {@link RatingCompat} or null 289 */ 290 public RatingCompat getRating(String key) { 291 RatingCompat rating = null; 292 try { 293 rating = mBundle.getParcelable(key); 294 } catch (Exception e) { 295 // ignore, value was not a bitmap 296 Log.w(TAG, "Failed to retrieve a key as Rating.", e); 297 } 298 return rating; 299 } 300 301 /** 302 * Return a {@link Bitmap} for the given key or null if no bitmap exists for 303 * the given key. 304 * 305 * @param key The key the value is stored under 306 * @return A {@link Bitmap} or null 307 */ 308 public Bitmap getBitmap(String key) { 309 Bitmap bmp = null; 310 try { 311 bmp = mBundle.getParcelable(key); 312 } catch (Exception e) { 313 // ignore, value was not a bitmap 314 Log.w(TAG, "Failed to retrieve a key as Bitmap.", e); 315 } 316 return bmp; 317 } 318 319 @Override 320 public int describeContents() { 321 return 0; 322 } 323 324 @Override 325 public void writeToParcel(Parcel dest, int flags) { 326 dest.writeBundle(mBundle); 327 } 328 329 /** 330 * Get the number of fields in this metadata. 331 * 332 * @return The number of fields in the metadata. 333 */ 334 public int size() { 335 return mBundle.size(); 336 } 337 338 /** 339 * Returns a Set containing the Strings used as keys in this metadata. 340 * 341 * @return a Set of String keys 342 */ 343 public Set<String> keySet() { 344 return mBundle.keySet(); 345 } 346 347 /** 348 * Creates an instance from a framework {@link android.media.MediaMetadata} object. 349 * <p> 350 * This method is only supported on API 21+. 351 * </p> 352 * 353 * @param metadataObj A {@link android.media.MediaMetadata} object, or null if none. 354 * @return An equivalent {@link MediaMetadataCompat} object, or null if none. 355 */ 356 public static MediaMetadataCompat fromMediaMetadata(Object metadataObj) { 357 if (metadataObj == null || Build.VERSION.SDK_INT < 21) { 358 return null; 359 } 360 361 Builder builder = new Builder(); 362 for (String key : MediaMetadataCompatApi21.keySet(metadataObj)) { 363 Integer type = METADATA_KEYS_TYPE.get(key); 364 if (type != null) { 365 switch (type) { 366 case METADATA_TYPE_BITMAP: 367 builder.putBitmap(key, 368 MediaMetadataCompatApi21.getBitmap(metadataObj, key)); 369 break; 370 case METADATA_TYPE_LONG: 371 builder.putLong(key, 372 MediaMetadataCompatApi21.getLong(metadataObj, key)); 373 break; 374 case METADATA_TYPE_RATING: 375 builder.putRating(key, RatingCompat.fromRating( 376 MediaMetadataCompatApi21.getRating(metadataObj, key))); 377 break; 378 case METADATA_TYPE_TEXT: 379 builder.putText(key, 380 MediaMetadataCompatApi21.getText(metadataObj, key)); 381 break; 382 } 383 } 384 } 385 MediaMetadataCompat metadata = builder.build(); 386 metadata.mMetadataObj = metadataObj; 387 return metadata; 388 } 389 390 /** 391 * Gets the underlying framework {@link android.media.MediaMetadata} object. 392 * <p> 393 * This method is only supported on API 21+. 394 * </p> 395 * 396 * @return An equivalent {@link android.media.MediaMetadata} object, or null if none. 397 */ 398 public Object getMediaMetadata() { 399 if (mMetadataObj != null || Build.VERSION.SDK_INT < 21) { 400 return mMetadataObj; 401 } 402 403 Object builderObj = MediaMetadataCompatApi21.Builder.newInstance(); 404 for (String key : keySet()) { 405 Integer type = METADATA_KEYS_TYPE.get(key); 406 if (type != null) { 407 switch (type) { 408 case METADATA_TYPE_BITMAP: 409 MediaMetadataCompatApi21.Builder.putBitmap(builderObj, key, 410 getBitmap(key)); 411 break; 412 case METADATA_TYPE_LONG: 413 MediaMetadataCompatApi21.Builder.putLong(builderObj, key, 414 getLong(key)); 415 break; 416 case METADATA_TYPE_RATING: 417 MediaMetadataCompatApi21.Builder.putRating(builderObj, key, 418 getRating(key).getRating()); 419 break; 420 case METADATA_TYPE_TEXT: 421 MediaMetadataCompatApi21.Builder.putText(builderObj, key, 422 getText(key)); 423 break; 424 } 425 } 426 } 427 mMetadataObj = MediaMetadataCompatApi21.Builder.build(builderObj); 428 return mMetadataObj; 429 } 430 431 public static final Parcelable.Creator<MediaMetadataCompat> CREATOR = 432 new Parcelable.Creator<MediaMetadataCompat>() { 433 @Override 434 public MediaMetadataCompat createFromParcel(Parcel in) { 435 return new MediaMetadataCompat(in); 436 } 437 438 @Override 439 public MediaMetadataCompat[] newArray(int size) { 440 return new MediaMetadataCompat[size]; 441 } 442 }; 443 444 /** 445 * Use to build MediaMetadata objects. The system defined metadata keys must 446 * use the appropriate data type. 447 */ 448 public static final class Builder { 449 private final Bundle mBundle; 450 451 /** 452 * Create an empty Builder. Any field that should be included in the 453 * {@link MediaMetadataCompat} must be added. 454 */ 455 public Builder() { 456 mBundle = new Bundle(); 457 } 458 459 /** 460 * Create a Builder using a {@link MediaMetadataCompat} instance to set the 461 * initial values. All fields in the source metadata will be included in 462 * the new metadata. Fields can be overwritten by adding the same key. 463 * 464 * @param source 465 */ 466 public Builder(MediaMetadataCompat source) { 467 mBundle = new Bundle(source.mBundle); 468 } 469 470 /** 471 * Put a CharSequence value into the metadata. Custom keys may be used, 472 * but if the METADATA_KEYs defined in this class are used they may only 473 * be one of the following: 474 * <ul> 475 * <li>{@link #METADATA_KEY_TITLE}</li> 476 * <li>{@link #METADATA_KEY_ARTIST}</li> 477 * <li>{@link #METADATA_KEY_ALBUM}</li> 478 * <li>{@link #METADATA_KEY_AUTHOR}</li> 479 * <li>{@link #METADATA_KEY_WRITER}</li> 480 * <li>{@link #METADATA_KEY_COMPOSER}</li> 481 * <li>{@link #METADATA_KEY_DATE}</li> 482 * <li>{@link #METADATA_KEY_GENRE}</li> 483 * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li> 484 * <li>{@link #METADATA_KEY_ART_URI}</li> 485 * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li> 486 * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li> 487 * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li> 488 * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li> 489 * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li> 490 * </ul> 491 * 492 * @param key The key for referencing this value 493 * @param value The CharSequence value to store 494 * @return The Builder to allow chaining 495 */ 496 public Builder putText(String key, CharSequence value) { 497 if (METADATA_KEYS_TYPE.containsKey(key)) { 498 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) { 499 throw new IllegalArgumentException("The " + key 500 + " key cannot be used to put a CharSequence"); 501 } 502 } 503 mBundle.putCharSequence(key, value); 504 return this; 505 } 506 507 /** 508 * Put a String value into the metadata. Custom keys may be used, but if 509 * the METADATA_KEYs defined in this class are used they may only be one 510 * of the following: 511 * <ul> 512 * <li>{@link #METADATA_KEY_TITLE}</li> 513 * <li>{@link #METADATA_KEY_ARTIST}</li> 514 * <li>{@link #METADATA_KEY_ALBUM}</li> 515 * <li>{@link #METADATA_KEY_AUTHOR}</li> 516 * <li>{@link #METADATA_KEY_WRITER}</li> 517 * <li>{@link #METADATA_KEY_COMPOSER}</li> 518 * <li>{@link #METADATA_KEY_DATE}</li> 519 * <li>{@link #METADATA_KEY_GENRE}</li> 520 * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li> 521 * <li>{@link #METADATA_KEY_ART_URI}</li> 522 * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li> 523 * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li> 524 * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li> 525 * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li> 526 * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li> 527 * </ul> 528 * 529 * @param key The key for referencing this value 530 * @param value The String value to store 531 * @return The Builder to allow chaining 532 */ 533 public Builder putString(String key, String value) { 534 if (METADATA_KEYS_TYPE.containsKey(key)) { 535 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) { 536 throw new IllegalArgumentException("The " + key 537 + " key cannot be used to put a String"); 538 } 539 } 540 mBundle.putCharSequence(key, value); 541 return this; 542 } 543 544 /** 545 * Put a long value into the metadata. Custom keys may be used, but if 546 * the METADATA_KEYs defined in this class are used they may only be one 547 * of the following: 548 * <ul> 549 * <li>{@link #METADATA_KEY_DURATION}</li> 550 * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li> 551 * <li>{@link #METADATA_KEY_NUM_TRACKS}</li> 552 * <li>{@link #METADATA_KEY_DISC_NUMBER}</li> 553 * <li>{@link #METADATA_KEY_YEAR}</li> 554 * </ul> 555 * 556 * @param key The key for referencing this value 557 * @param value The String value to store 558 * @return The Builder to allow chaining 559 */ 560 public Builder putLong(String key, long value) { 561 if (METADATA_KEYS_TYPE.containsKey(key)) { 562 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) { 563 throw new IllegalArgumentException("The " + key 564 + " key cannot be used to put a long"); 565 } 566 } 567 mBundle.putLong(key, value); 568 return this; 569 } 570 571 /** 572 * Put a {@link RatingCompat} into the metadata. Custom keys may be used, but 573 * if the METADATA_KEYs defined in this class are used they may only be 574 * one of the following: 575 * <ul> 576 * <li>{@link #METADATA_KEY_RATING}</li> 577 * <li>{@link #METADATA_KEY_USER_RATING}</li> 578 * </ul> 579 * 580 * @param key The key for referencing this value 581 * @param value The String value to store 582 * @return The Builder to allow chaining 583 */ 584 public Builder putRating(String key, RatingCompat value) { 585 if (METADATA_KEYS_TYPE.containsKey(key)) { 586 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) { 587 throw new IllegalArgumentException("The " + key 588 + " key cannot be used to put a Rating"); 589 } 590 } 591 mBundle.putParcelable(key, value); 592 return this; 593 } 594 595 /** 596 * Put a {@link Bitmap} into the metadata. Custom keys may be used, but 597 * if the METADATA_KEYs defined in this class are used they may only be 598 * one of the following: 599 * <ul> 600 * <li>{@link #METADATA_KEY_ART}</li> 601 * <li>{@link #METADATA_KEY_ALBUM_ART}</li> 602 * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li> 603 * </ul> 604 * 605 * @param key The key for referencing this value 606 * @param value The Bitmap to store 607 * @return The Builder to allow chaining 608 */ 609 public Builder putBitmap(String key, Bitmap value) { 610 if (METADATA_KEYS_TYPE.containsKey(key)) { 611 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) { 612 throw new IllegalArgumentException("The " + key 613 + " key cannot be used to put a Bitmap"); 614 } 615 } 616 mBundle.putParcelable(key, value); 617 return this; 618 } 619 620 /** 621 * Creates a {@link MediaMetadataCompat} instance with the specified fields. 622 * 623 * @return The new MediaMetadata instance 624 */ 625 public MediaMetadataCompat build() { 626 return new MediaMetadataCompat(mBundle); 627 } 628 } 629 630} 631