• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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