• 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.Nullable;
25 import android.text.TextUtils;
26 
27 /**
28  * A simple set of metadata for a media item suitable for display. This can be
29  * created using the Builder or retrieved from existing metadata using
30  * {@link MediaMetadataCompat#getDescription()}.
31  */
32 public final class MediaDescriptionCompat implements Parcelable {
33     /**
34      * Used as a long extra field to indicate the bluetooth folder type of the media item as
35      * specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5. This is valid only for
36      * {@link MediaBrowserCompat.MediaItem} with
37      * {@link MediaBrowserCompat.MediaItem#FLAG_BROWSABLE}. The value should be one of the
38      * following:
39      * <ul>
40      * <li>{@link #BT_FOLDER_TYPE_MIXED}</li>
41      * <li>{@link #BT_FOLDER_TYPE_TITLES}</li>
42      * <li>{@link #BT_FOLDER_TYPE_ALBUMS}</li>
43      * <li>{@link #BT_FOLDER_TYPE_ARTISTS}</li>
44      * <li>{@link #BT_FOLDER_TYPE_GENRES}</li>
45      * <li>{@link #BT_FOLDER_TYPE_PLAYLISTS}</li>
46      * <li>{@link #BT_FOLDER_TYPE_YEARS}</li>
47      * </ul>
48      *
49      * @see #getExtras()
50      */
51     public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
52 
53     /**
54      * The type of folder that is unknown or contains media elements of mixed types as specified in
55      * the section 6.10.2.2 of the Bluetooth AVRCP 1.5.
56      */
57     public static final long BT_FOLDER_TYPE_MIXED = 0;
58 
59     /**
60      * The type of folder that contains media elements only as specified in the section 6.10.2.2 of
61      * the Bluetooth AVRCP 1.5.
62      */
63     public static final long BT_FOLDER_TYPE_TITLES = 1;
64 
65     /**
66      * The type of folder that contains folders categorized by album as specified in the section
67      * 6.10.2.2 of the Bluetooth AVRCP 1.5.
68      */
69     public static final long BT_FOLDER_TYPE_ALBUMS = 2;
70 
71     /**
72      * The type of folder that contains folders categorized by artist as specified in the section
73      * 6.10.2.2 of the Bluetooth AVRCP 1.5.
74      */
75     public static final long BT_FOLDER_TYPE_ARTISTS = 3;
76 
77     /**
78      * The type of folder that contains folders categorized by genre as specified in the section
79      * 6.10.2.2 of the Bluetooth AVRCP 1.5.
80      */
81     public static final long BT_FOLDER_TYPE_GENRES = 4;
82 
83     /**
84      * The type of folder that contains folders categorized by playlist as specified in the section
85      * 6.10.2.2 of the Bluetooth AVRCP 1.5.
86      */
87     public static final long BT_FOLDER_TYPE_PLAYLISTS = 5;
88 
89     /**
90      * The type of folder that contains folders categorized by year as specified in the section
91      * 6.10.2.2 of the Bluetooth AVRCP 1.5.
92      */
93     public static final long BT_FOLDER_TYPE_YEARS = 6;
94 
95     /**
96      * Custom key to store a media URI on API 21-22 devices (before it became part of the
97      * framework class) when parceling/converting to and from framework objects.
98      *
99      * @hide
100      */
101     public static final String DESCRIPTION_KEY_MEDIA_URI =
102             "android.support.v4.media.description.MEDIA_URI";
103     /**
104      * Custom key to store whether the original Bundle provided by the developer was null
105      *
106      * @hide
107      */
108     public static final String DESCRIPTION_KEY_NULL_BUNDLE_FLAG =
109             "android.support.v4.media.description.NULL_BUNDLE_FLAG";
110     /**
111      * A unique persistent id for the content or null.
112      */
113     private final String mMediaId;
114     /**
115      * A primary title suitable for display or null.
116      */
117     private final CharSequence mTitle;
118     /**
119      * A subtitle suitable for display or null.
120      */
121     private final CharSequence mSubtitle;
122     /**
123      * A description suitable for display or null.
124      */
125     private final CharSequence mDescription;
126     /**
127      * A bitmap icon suitable for display or null.
128      */
129     private final Bitmap mIcon;
130     /**
131      * A Uri for an icon suitable for display or null.
132      */
133     private final Uri mIconUri;
134     /**
135      * Extras for opaque use by apps/system.
136      */
137     private final Bundle mExtras;
138     /**
139      * A Uri to identify this content.
140      */
141     private final Uri mMediaUri;
142 
143     /**
144      * A cached copy of the equivalent framework object.
145      */
146     private Object mDescriptionObj;
147 
MediaDescriptionCompat(String mediaId, CharSequence title, CharSequence subtitle, CharSequence description, Bitmap icon, Uri iconUri, Bundle extras, Uri mediaUri)148     private MediaDescriptionCompat(String mediaId, CharSequence title, CharSequence subtitle,
149             CharSequence description, Bitmap icon, Uri iconUri, Bundle extras, Uri mediaUri) {
150         mMediaId = mediaId;
151         mTitle = title;
152         mSubtitle = subtitle;
153         mDescription = description;
154         mIcon = icon;
155         mIconUri = iconUri;
156         mExtras = extras;
157         mMediaUri = mediaUri;
158     }
159 
MediaDescriptionCompat(Parcel in)160     private MediaDescriptionCompat(Parcel in) {
161         mMediaId = in.readString();
162         mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
163         mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
164         mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
165         mIcon = in.readParcelable(null);
166         mIconUri = in.readParcelable(null);
167         mExtras = in.readBundle();
168         mMediaUri = in.readParcelable(null);
169     }
170 
171     /**
172      * Returns the media id or null. See
173      * {@link MediaMetadataCompat#METADATA_KEY_MEDIA_ID}.
174      */
175     @Nullable
getMediaId()176     public String getMediaId() {
177         return mMediaId;
178     }
179 
180     /**
181      * Returns a title suitable for display or null.
182      *
183      * @return A title or null.
184      */
185     @Nullable
getTitle()186     public CharSequence getTitle() {
187         return mTitle;
188     }
189 
190     /**
191      * Returns a subtitle suitable for display or null.
192      *
193      * @return A subtitle or null.
194      */
195     @Nullable
getSubtitle()196     public CharSequence getSubtitle() {
197         return mSubtitle;
198     }
199 
200     /**
201      * Returns a description suitable for display or null.
202      *
203      * @return A description or null.
204      */
205     @Nullable
getDescription()206     public CharSequence getDescription() {
207         return mDescription;
208     }
209 
210     /**
211      * Returns a bitmap icon suitable for display or null.
212      *
213      * @return An icon or null.
214      */
215     @Nullable
getIconBitmap()216     public Bitmap getIconBitmap() {
217         return mIcon;
218     }
219 
220     /**
221      * Returns a Uri for an icon suitable for display or null.
222      *
223      * @return An icon uri or null.
224      */
225     @Nullable
getIconUri()226     public Uri getIconUri() {
227         return mIconUri;
228     }
229 
230     /**
231      * Returns any extras that were added to the description.
232      *
233      * @return A bundle of extras or null.
234      */
235     @Nullable
getExtras()236     public Bundle getExtras() {
237         return mExtras;
238     }
239 
240     /**
241      * Returns a Uri representing this content or null.
242      *
243      * @return A media Uri or null.
244      */
245     @Nullable
getMediaUri()246     public Uri getMediaUri() {
247         return mMediaUri;
248     }
249 
250     @Override
describeContents()251     public int describeContents() {
252         return 0;
253     }
254 
255     @Override
writeToParcel(Parcel dest, int flags)256     public void writeToParcel(Parcel dest, int flags) {
257         if (Build.VERSION.SDK_INT < 21) {
258             dest.writeString(mMediaId);
259             TextUtils.writeToParcel(mTitle, dest, flags);
260             TextUtils.writeToParcel(mSubtitle, dest, flags);
261             TextUtils.writeToParcel(mDescription, dest, flags);
262             dest.writeParcelable(mIcon, flags);
263             dest.writeParcelable(mIconUri, flags);
264             dest.writeBundle(mExtras);
265             dest.writeParcelable(mMediaUri, flags);
266         } else {
267             MediaDescriptionCompatApi21.writeToParcel(getMediaDescription(), dest, flags);
268         }
269     }
270 
271     @Override
toString()272     public String toString() {
273         return mTitle + ", " + mSubtitle + ", " + mDescription;
274     }
275 
276     /**
277      * Gets the underlying framework {@link android.media.MediaDescription}
278      * object.
279      * <p>
280      * This method is only supported on
281      * {@link android.os.Build.VERSION_CODES#LOLLIPOP} and later.
282      * </p>
283      *
284      * @return An equivalent {@link android.media.MediaDescription} object, or
285      *         null if none.
286      */
getMediaDescription()287     public Object getMediaDescription() {
288         if (mDescriptionObj != null || Build.VERSION.SDK_INT < 21) {
289             return mDescriptionObj;
290         }
291         Object bob = MediaDescriptionCompatApi21.Builder.newInstance();
292         MediaDescriptionCompatApi21.Builder.setMediaId(bob, mMediaId);
293         MediaDescriptionCompatApi21.Builder.setTitle(bob, mTitle);
294         MediaDescriptionCompatApi21.Builder.setSubtitle(bob, mSubtitle);
295         MediaDescriptionCompatApi21.Builder.setDescription(bob, mDescription);
296         MediaDescriptionCompatApi21.Builder.setIconBitmap(bob, mIcon);
297         MediaDescriptionCompatApi21.Builder.setIconUri(bob, mIconUri);
298         // Media URI was not added until API 23, so add it to the Bundle of extras to
299         // ensure the data is not lost - this ensures that
300         // fromMediaDescription(getMediaDescription(mediaDescriptionCompat)) returns
301         // an equivalent MediaDescriptionCompat on all API levels
302         Bundle extras = mExtras;
303         if (Build.VERSION.SDK_INT < 23 && mMediaUri != null) {
304             if (extras == null) {
305                 extras = new Bundle();
306                 extras.putBoolean(DESCRIPTION_KEY_NULL_BUNDLE_FLAG, true);
307             }
308             extras.putParcelable(DESCRIPTION_KEY_MEDIA_URI, mMediaUri);
309         }
310         MediaDescriptionCompatApi21.Builder.setExtras(bob, extras);
311         if (Build.VERSION.SDK_INT >= 23) {
312             MediaDescriptionCompatApi23.Builder.setMediaUri(bob, mMediaUri);
313         }
314         mDescriptionObj = MediaDescriptionCompatApi21.Builder.build(bob);
315 
316         return mDescriptionObj;
317     }
318 
319     /**
320      * Creates an instance from a framework
321      * {@link android.media.MediaDescription} object.
322      * <p>
323      * This method is only supported on API 21+.
324      * </p>
325      *
326      * @param descriptionObj A {@link android.media.MediaDescription} object, or
327      *            null if none.
328      * @return An equivalent {@link MediaMetadataCompat} object, or null if
329      *         none.
330      */
fromMediaDescription(Object descriptionObj)331     public static MediaDescriptionCompat fromMediaDescription(Object descriptionObj) {
332         if (descriptionObj == null || Build.VERSION.SDK_INT < 21) {
333             return null;
334         }
335 
336         Builder bob = new Builder();
337         bob.setMediaId(MediaDescriptionCompatApi21.getMediaId(descriptionObj));
338         bob.setTitle(MediaDescriptionCompatApi21.getTitle(descriptionObj));
339         bob.setSubtitle(MediaDescriptionCompatApi21.getSubtitle(descriptionObj));
340         bob.setDescription(MediaDescriptionCompatApi21.getDescription(descriptionObj));
341         bob.setIconBitmap(MediaDescriptionCompatApi21.getIconBitmap(descriptionObj));
342         bob.setIconUri(MediaDescriptionCompatApi21.getIconUri(descriptionObj));
343         Bundle extras = MediaDescriptionCompatApi21.getExtras(descriptionObj);
344         Uri mediaUri = extras == null ? null :
345                 (Uri) extras.getParcelable(DESCRIPTION_KEY_MEDIA_URI);
346         if (mediaUri != null) {
347             if (extras.containsKey(DESCRIPTION_KEY_NULL_BUNDLE_FLAG) && extras.size() == 2) {
348                 // The extras were only created for the media URI, so we set it back to null to
349                 // ensure mediaDescriptionCompat.getExtras() equals
350                 // fromMediaDescription(getMediaDescription(mediaDescriptionCompat)).getExtras()
351                 extras = null;
352             } else {
353                 // Remove media URI keys to ensure mediaDescriptionCompat.getExtras().keySet()
354                 // equals fromMediaDescription(getMediaDescription(mediaDescriptionCompat))
355                 // .getExtras().keySet()
356                 extras.remove(DESCRIPTION_KEY_MEDIA_URI);
357                 extras.remove(DESCRIPTION_KEY_NULL_BUNDLE_FLAG);
358             }
359         }
360         bob.setExtras(extras);
361         if (mediaUri != null) {
362             bob.setMediaUri(mediaUri);
363         } else if (Build.VERSION.SDK_INT >= 23) {
364             bob.setMediaUri(MediaDescriptionCompatApi23.getMediaUri(descriptionObj));
365         }
366         MediaDescriptionCompat descriptionCompat = bob.build();
367         descriptionCompat.mDescriptionObj = descriptionObj;
368 
369         return descriptionCompat;
370     }
371 
372     public static final Parcelable.Creator<MediaDescriptionCompat> CREATOR =
373             new Parcelable.Creator<MediaDescriptionCompat>() {
374             @Override
375                 public MediaDescriptionCompat createFromParcel(Parcel in) {
376                     if (Build.VERSION.SDK_INT < 21) {
377                         return new MediaDescriptionCompat(in);
378                     } else {
379                         return fromMediaDescription(MediaDescriptionCompatApi21.fromParcel(in));
380                     }
381                 }
382 
383             @Override
384                 public MediaDescriptionCompat[] newArray(int size) {
385                     return new MediaDescriptionCompat[size];
386                 }
387             };
388 
389     /**
390      * Builder for {@link MediaDescriptionCompat} objects.
391      */
392     public static final class Builder {
393         private String mMediaId;
394         private CharSequence mTitle;
395         private CharSequence mSubtitle;
396         private CharSequence mDescription;
397         private Bitmap mIcon;
398         private Uri mIconUri;
399         private Bundle mExtras;
400         private Uri mMediaUri;
401 
402         /**
403          * Creates an initially empty builder.
404          */
Builder()405         public Builder() {
406         }
407 
408         /**
409          * Sets the media id.
410          *
411          * @param mediaId The unique id for the item or null.
412          * @return this
413          */
setMediaId(@ullable String mediaId)414         public Builder setMediaId(@Nullable String mediaId) {
415             mMediaId = mediaId;
416             return this;
417         }
418 
419         /**
420          * Sets the title.
421          *
422          * @param title A title suitable for display to the user or null.
423          * @return this
424          */
setTitle(@ullable CharSequence title)425         public Builder setTitle(@Nullable CharSequence title) {
426             mTitle = title;
427             return this;
428         }
429 
430         /**
431          * Sets the subtitle.
432          *
433          * @param subtitle A subtitle suitable for display to the user or null.
434          * @return this
435          */
setSubtitle(@ullable CharSequence subtitle)436         public Builder setSubtitle(@Nullable CharSequence subtitle) {
437             mSubtitle = subtitle;
438             return this;
439         }
440 
441         /**
442          * Sets the description.
443          *
444          * @param description A description suitable for display to the user or
445          *            null.
446          * @return this
447          */
setDescription(@ullable CharSequence description)448         public Builder setDescription(@Nullable CharSequence description) {
449             mDescription = description;
450             return this;
451         }
452 
453         /**
454          * Sets the icon.
455          *
456          * @param icon A {@link Bitmap} icon suitable for display to the user or
457          *            null.
458          * @return this
459          */
setIconBitmap(@ullable Bitmap icon)460         public Builder setIconBitmap(@Nullable Bitmap icon) {
461             mIcon = icon;
462             return this;
463         }
464 
465         /**
466          * Sets the icon uri.
467          *
468          * @param iconUri A {@link Uri} for an icon suitable for display to the
469          *            user or null.
470          * @return this
471          */
setIconUri(@ullable Uri iconUri)472         public Builder setIconUri(@Nullable Uri iconUri) {
473             mIconUri = iconUri;
474             return this;
475         }
476 
477         /**
478          * Sets a bundle of extras.
479          *
480          * @param extras The extras to include with this description or null.
481          * @return this
482          */
setExtras(@ullable Bundle extras)483         public Builder setExtras(@Nullable Bundle extras) {
484             mExtras = extras;
485             return this;
486         }
487 
488         /**
489          * Sets the media uri.
490          *
491          * @param mediaUri The content's {@link Uri} for the item or null.
492          * @return this
493          */
setMediaUri(@ullable Uri mediaUri)494         public Builder setMediaUri(@Nullable Uri mediaUri) {
495             mMediaUri = mediaUri;
496             return this;
497         }
498 
499         /**
500          * Creates a {@link MediaDescriptionCompat} instance with the specified
501          * fields.
502          *
503          * @return A MediaDescriptionCompat instance.
504          */
build()505         public MediaDescriptionCompat build() {
506             return new MediaDescriptionCompat(mMediaId, mTitle, mSubtitle, mDescription, mIcon,
507                     mIconUri, mExtras, mMediaUri);
508         }
509     }
510 }
511