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