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