public final class

MediaMetadata

extends CustomVersionedParcelable

 java.lang.Object

androidx.versionedparcelable.CustomVersionedParcelable

↳androidx.media2.MediaMetadata

Gradle dependencies

compile group: 'androidx.media2', name: 'media2', version: '1.0.0-alpha04'

  • groupId: androidx.media2
  • artifactId: media2
  • version: 1.0.0-alpha04

Artifact androidx.media2:media2:1.0.0-alpha04 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.media2:media2 com.android.support:media2

Overview

Contains metadata about an item, such as the title, artist, etc. This is optional, but you'd better to provide this as much as possible when you're using media widget and/or session APIs.

The media widget components build its UI based on the metadata here. For an example, MediaControlView will show title from the metadata.

The MediaLibraryService.MediaLibrarySession would require some metadata values when it provides MediaItems to MediaBrowser.

Topics covered here:

  1. Media ID
  2. Browsable type
  3. Playable
  4. Duration
  5. User rating

Media ID

If set, the media ID must be the persistent key for the underlying media contents, so MediaController and MediaBrowser can store the information and reuse it later. Some APIs requires a media ID (e.g. MediaController.setRating(String, Rating), so you'd better specify one.

Typical example of using media ID is the URI of the contents, but use it with the caution because the metadata is shared across the process in plain text.

The MediaLibraryService.MediaLibrarySession would require it for the library root, so MediaBrowser can call subsequent MediaBrowser.getChildren(String, int, int, MediaLibraryService.LibraryParams) with the ID.

Browsable type

Browsable defines whether the media item has children and type of children if any. With this, MediaBrowser can know whether the subsequent MediaBrowser.getChildren(String, int, int, MediaLibraryService.LibraryParams) would successfuly run.

The MediaLibraryService.MediaLibrarySession would require the explicit browsable type for the the media items returned by the MediaLibraryService.MediaLibrarySession.MediaLibrarySessionCallback.

Playable type

Playable defines whether the media item can be played or not. It may be possible for a playlist to contain a media item which isn't playable in order to show a disabled media item.

The MediaLibraryService.MediaLibrarySession would require the explicit playable value for the the media items returned by the MediaLibraryService.MediaLibrarySession.MediaLibrarySessionCallback.

  • Duration The duration is the length of the contents. The MediaController can only get the duration through the metadata. This tells when would the playback ends, and also tells about the allowed range of MediaController.seekTo(long).

    If it's not set by developer, MediaSession would update the duration in the metadata with the SessionPlayer.getDuration().

  • User rating

    Prefer to have unrated user rating instead of null, so MediaController can know the possible user rating type for calling MediaController.setRating(String, Rating).

    Summary

    Fields
    public static final longBROWSABLE_TYPE_ALBUMS

    The type of browsable that contains browsable items categorized by album.

    public static final longBROWSABLE_TYPE_ARTISTS

    The type of browsable that contains browsable items categorized by artist.

    public static final longBROWSABLE_TYPE_GENRES

    The type of browsable that contains browsable items categorized by genre.

    public static final longBROWSABLE_TYPE_MIXED

    The type of browsable that is unknown or contains media items of mixed types.

    public static final longBROWSABLE_TYPE_NONE

    The type of browsable for non-browsable media item.

    public static final longBROWSABLE_TYPE_PLAYLISTS

    The type of browsable that contains browsable items categorized by playlist.

    public static final longBROWSABLE_TYPE_TITLES

    The type of browsable that only contains playable media items.

    public static final longBROWSABLE_TYPE_YEARS

    The type of browsable that contains browsable items categorized by year.

    public static final java.lang.StringMETADATA_KEY_ADVERTISEMENT

    The metadata key for a java.lang.Long typed value to retrieve the information about whether the media is an advertisement.

    public static final java.lang.StringMETADATA_KEY_ALBUM

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the album title for the media.

    public static final java.lang.StringMETADATA_KEY_ALBUM_ART

    The metadata key for a Bitmap typed value to retrieve the information about the artwork for the album of the media's original source.

    public static final java.lang.StringMETADATA_KEY_ALBUM_ART_URI

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the Uri of the artwork for the album of the media's original source.

    public static final java.lang.StringMETADATA_KEY_ALBUM_ARTIST

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the artist for the album of the media's original source.

    public static final java.lang.StringMETADATA_KEY_ART

    The metadata key for a Bitmap typed value to retrieve the information about the artwork for the media.

    public static final java.lang.StringMETADATA_KEY_ART_URI

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about Uri of the artwork for the media.

    public static final java.lang.StringMETADATA_KEY_ARTIST

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the artist of the media.

    public static final java.lang.StringMETADATA_KEY_AUTHOR

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the author of the media.

    public static final java.lang.StringMETADATA_KEY_BROWSABLE

    The metadata key for a java.lang.Long typed value to retrieve the information about the type of browsable.

    public static final java.lang.StringMETADATA_KEY_COMPILATION

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the compilation status of the media.

    public static final java.lang.StringMETADATA_KEY_COMPOSER

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the composer of the media.

    public static final java.lang.StringMETADATA_KEY_DATE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the date the media was created or published.

    public static final java.lang.StringMETADATA_KEY_DISC_NUMBER

    The metadata key for a java.lang.Long typed value to retrieve the information about the disc number for the media's original source.

    public static final java.lang.StringMETADATA_KEY_DISPLAY_DESCRIPTION

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the description that is suitable for display to the user.

    public static final java.lang.StringMETADATA_KEY_DISPLAY_ICON

    The metadata key for a Bitmap typed value to retrieve the information about the icon or thumbnail that is suitable for display to the user.

    public static final java.lang.StringMETADATA_KEY_DISPLAY_ICON_URI

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the Uri of icon or thumbnail that is suitable for display to the user.

    public static final java.lang.StringMETADATA_KEY_DISPLAY_SUBTITLE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the subtitle that is suitable for display to the user.

    public static final java.lang.StringMETADATA_KEY_DISPLAY_TITLE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the title that is suitable for display to the user.

    public static final java.lang.StringMETADATA_KEY_DOWNLOAD_STATUS

    The metadata key for a java.lang.Long typed value to retrieve the information about the download status of the media which will be used for later offline playback.

    public static final java.lang.StringMETADATA_KEY_DURATION

    The metadata key for a java.lang.Long typed value to retrieve the information about the duration of the media in ms.

    public static final java.lang.StringMETADATA_KEY_EXTRAS

    A extra.

    public static final java.lang.StringMETADATA_KEY_GENRE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the genre of the media.

    public static final java.lang.StringMETADATA_KEY_MEDIA_ID

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the media ID of the content.

    public static final java.lang.StringMETADATA_KEY_MEDIA_URI

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the Uri of the content.

    public static final java.lang.StringMETADATA_KEY_NUM_TRACKS

    The metadata key for a java.lang.Long typed value to retrieve the information about the number of tracks in the media's original source.

    public static final java.lang.StringMETADATA_KEY_PLAYABLE

    The metadata key for a java.lang.Long typed value to retrieve the information about whether the media is playable.

    public static final java.lang.StringMETADATA_KEY_RADIO_FREQUENCY

    public static final java.lang.StringMETADATA_KEY_RADIO_PROGRAM_NAME

    public static final java.lang.StringMETADATA_KEY_RATING

    The metadata key for a Rating typed value to retrieve the information about the overall rating for the media.

    public static final java.lang.StringMETADATA_KEY_TITLE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the title of the media.

    public static final java.lang.StringMETADATA_KEY_TRACK_NUMBER

    The metadata key for a java.lang.Long typed value to retrieve the information about the track number for the media.

    public static final java.lang.StringMETADATA_KEY_USER_RATING

    The metadata key for a Rating typed value to retrieve the information about the user's rating for the media.

    public static final java.lang.StringMETADATA_KEY_WRITER

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the writer of the media.

    public static final java.lang.StringMETADATA_KEY_YEAR

    The metadata key for a java.lang.Long typed value to retrieve the information about the year the media was created or published.

    public static final longSTATUS_DOWNLOADED

    The status value to indicate the media item is downloaded for later offline playback.

    public static final longSTATUS_DOWNLOADING

    The status value to indicate the media item is being downloaded.

    public static final longSTATUS_NOT_DOWNLOADED

    The status value to indicate the media item is not downloaded.

    Methods
    public booleancontainsKey(java.lang.String key)

    Returns true if the given key is contained in the metadata

    public BitmapgetBitmap(java.lang.String key)

    Return a Bitmap for the given key or null if no bitmap exists for the given key.

    public BundlegetExtras()

    Get the extra from the metadata object.

    public floatgetFloat(java.lang.String key)

    Return the value associated with the given key, or 0.0f if no long exists for the given key.

    public longgetLong(java.lang.String key)

    Returns the value associated with the given key, or 0L if no long exists for the given key.

    public java.lang.StringgetMediaId()

    Returns the media id, or null if the id doesn't exist.

    public java.lang.ObjectgetObject(java.lang.String key)

    Gets the object which matches the given key in the backing bundle.

    public RatinggetRating(java.lang.String key)

    Return a Rating for the given key or null if no rating exists for the given key.

    public java.lang.StringgetString(java.lang.String key)

    Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key.

    public java.lang.CharSequencegetText(java.lang.String key)

    Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key.

    public java.util.Set<java.lang.String>keySet()

    Returns a Set containing the Strings used as keys in this metadata.

    public voidonPostParceling()

    public voidonPreParceling(boolean isStream)

    public intsize()

    Get the number of fields in this metadata.

    public java.lang.StringtoString()

    from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

    Fields

    public static final java.lang.String METADATA_KEY_TITLE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the title of the media.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_ARTIST

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the artist of the media.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_DURATION

    The metadata key for a java.lang.Long typed value to retrieve the information about the duration of the media in ms. A negative duration indicates that the duration is unknown (or infinite).

    See also: MediaMetadata.Builder.putLong(String, long), MediaMetadata.getLong(String)

    public static final java.lang.String METADATA_KEY_ALBUM

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the album title for the media.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_AUTHOR

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the author of the media.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_WRITER

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the writer of the media.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_COMPOSER

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the composer of the media.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_COMPILATION

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the compilation status of the media.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_DATE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the date the media was created or published. The format is unspecified but RFC 3339 is recommended.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_YEAR

    The metadata key for a java.lang.Long typed value to retrieve the information about the year the media was created or published.

    See also: MediaMetadata.Builder.putLong(String, long), MediaMetadata.getLong(String)

    public static final java.lang.String METADATA_KEY_GENRE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the genre of the media.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_TRACK_NUMBER

    The metadata key for a java.lang.Long typed value to retrieve the information about the track number for the media.

    See also: MediaMetadata.Builder.putLong(String, long), MediaMetadata.getLong(String)

    public static final java.lang.String METADATA_KEY_NUM_TRACKS

    The metadata key for a java.lang.Long typed value to retrieve the information about the number of tracks in the media's original source.

    See also: MediaMetadata.Builder.putLong(String, long), MediaMetadata.getLong(String)

    public static final java.lang.String METADATA_KEY_DISC_NUMBER

    The metadata key for a java.lang.Long typed value to retrieve the information about the disc number for the media's original source.

    See also: MediaMetadata.Builder.putLong(String, long), MediaMetadata.getLong(String)

    public static final java.lang.String METADATA_KEY_ALBUM_ARTIST

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the artist for the album of the media's original source.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_ART

    The metadata key for a Bitmap typed value to retrieve the information about the artwork for the media. The artwork should be relatively small and may be scaled down if it is too large. For higher resolution artwork, MediaMetadata.METADATA_KEY_ART_URI should be used instead.

    See also: MediaMetadata.Builder.putBitmap(String, Bitmap), MediaMetadata.getBitmap(String)

    public static final java.lang.String METADATA_KEY_ART_URI

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about Uri of the artwork for the media.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_ALBUM_ART

    The metadata key for a Bitmap typed value to retrieve the information about the artwork for the album of the media's original source. The artwork should be relatively small and may be scaled down if it is too large. For higher resolution artwork, MediaMetadata.METADATA_KEY_ALBUM_ART_URI should be used instead.

    See also: MediaMetadata.Builder.putBitmap(String, Bitmap), MediaMetadata.getBitmap(String)

    public static final java.lang.String METADATA_KEY_ALBUM_ART_URI

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the Uri of the artwork for the album of the media's original source.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_USER_RATING

    The metadata key for a Rating typed value to retrieve the information about the user's rating for the media. Prefer to have unrated user rating instead of null, so MediaController can know the possible user rating type.

    See also: MediaMetadata.Builder.putRating(String, Rating), MediaMetadata.getRating(String)

    public static final java.lang.String METADATA_KEY_RATING

    The metadata key for a Rating typed value to retrieve the information about the overall rating for the media.

    See also: MediaMetadata.Builder.putRating(String, Rating), MediaMetadata.getRating(String)

    public static final java.lang.String METADATA_KEY_DISPLAY_TITLE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the title that is suitable for display to the user. It will generally be the same as MediaMetadata.METADATA_KEY_TITLE but may differ for some formats. When displaying media described by this metadata, this should be preferred if present.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the subtitle that is suitable for display to the user. When displaying a second line for media described by this metadata, this should be preferred to other fields if present.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the description that is suitable for display to the user. When displaying more information for media described by this metadata, this should be preferred to other fields if present.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_DISPLAY_ICON

    The metadata key for a Bitmap typed value to retrieve the information about the icon or thumbnail that is suitable for display to the user. When displaying an icon for media described by this metadata, this should be preferred to other fields if present.

    The icon should be relatively small and may be scaled down if it is too large. For higher resolution artwork, MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI should be used instead.

    See also: MediaMetadata.Builder.putBitmap(String, Bitmap), MediaMetadata.getBitmap(String)

    public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the Uri of icon or thumbnail that is suitable for display to the user. When displaying more information for media described by this metadata, the display description should be preferred to other fields when present.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_MEDIA_ID

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the media ID of the content. This value is specific to the service providing the content. If used, this should be a persistent key for the underlying content. This ID is used by MediaController and MediaBrowser.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_MEDIA_URI

    The metadata key for a java.lang.CharSequence or java.lang.String typed value to retrieve the information about the Uri of the content. This value is specific to the service providing the content.

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_RADIO_FREQUENCY

    See also: MediaMetadata.Builder.putFloat(String, float), MediaMetadata.getFloat(String)

    public static final java.lang.String METADATA_KEY_RADIO_PROGRAM_NAME

    See also: MediaMetadata.Builder.putText(String, CharSequence), MediaMetadata.Builder.putString(String, String), MediaMetadata.getText(String), MediaMetadata.getString(String)

    public static final java.lang.String METADATA_KEY_BROWSABLE

    The metadata key for a java.lang.Long typed value to retrieve the information about the type of browsable. It should be one of the following:

    The values other than MediaMetadata.BROWSABLE_TYPE_NONE mean that the media item has children.[

    This matches with the bluetooth folder type of the media specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5.

    See also: MediaMetadata.Builder.putLong(String, long), MediaMetadata.getLong(String)

    public static final long BROWSABLE_TYPE_NONE

    The type of browsable for non-browsable media item.

    public static final long BROWSABLE_TYPE_MIXED

    The type of browsable that is unknown or contains media items of mixed types.

    This value matches with the folder type 'Mixed' as specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5.

    public static final long BROWSABLE_TYPE_TITLES

    The type of browsable that only contains playable media items.

    This value matches with the folder type 'Titles' as specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5.

    public static final long BROWSABLE_TYPE_ALBUMS

    The type of browsable that contains browsable items categorized by album.

    This value matches with the folder type 'Albums' as specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5.

    public static final long BROWSABLE_TYPE_ARTISTS

    The type of browsable that contains browsable items categorized by artist.

    This value matches with the folder type 'Artists' as specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5.

    public static final long BROWSABLE_TYPE_GENRES

    The type of browsable that contains browsable items categorized by genre.

    This value matches with the folder type 'Genres' as specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5.

    public static final long BROWSABLE_TYPE_PLAYLISTS

    The type of browsable that contains browsable items categorized by playlist.

    This value matches with the folder type 'Playlists' as specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5.

    public static final long BROWSABLE_TYPE_YEARS

    The type of browsable that contains browsable items categorized by year.

    This value matches with the folder type 'Years' as specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5.

    public static final java.lang.String METADATA_KEY_PLAYABLE

    The metadata key for a java.lang.Long typed value to retrieve the information about whether the media is playable. A value of 0 indicates it is not a playable item. A value of 1 or non-zero indicates it is playable.

    See also: MediaMetadata.Builder.putLong(String, long), MediaMetadata.getLong(String)

    public static final java.lang.String METADATA_KEY_ADVERTISEMENT

    The metadata key for a java.lang.Long typed value to retrieve the information about whether the media is an advertisement. A value of 0 indicates it is not an advertisement. A value of 1 or non-zero indicates it is an advertisement. If not specified, this value is set to 0 by default.

    See also: MediaMetadata.Builder.putLong(String, long), MediaMetadata.getLong(String)

    public static final java.lang.String METADATA_KEY_DOWNLOAD_STATUS

    The metadata key for a java.lang.Long typed value to retrieve the information about the download status of the media which will be used for later offline playback. It should be one of the following:

    See also: MediaMetadata.Builder.putLong(String, long), MediaMetadata.getLong(String)

    public static final long STATUS_NOT_DOWNLOADED

    The status value to indicate the media item is not downloaded.

    See also: MediaMetadata.METADATA_KEY_DOWNLOAD_STATUS

    public static final long STATUS_DOWNLOADING

    The status value to indicate the media item is being downloaded.

    See also: MediaMetadata.METADATA_KEY_DOWNLOAD_STATUS

    public static final long STATUS_DOWNLOADED

    The status value to indicate the media item is downloaded for later offline playback.

    See also: MediaMetadata.METADATA_KEY_DOWNLOAD_STATUS

    public static final java.lang.String METADATA_KEY_EXTRAS

    A extra.

    Methods

    public boolean containsKey(java.lang.String key)

    Returns true if the given key is contained in the metadata

    Parameters:

    key: a String key

    Returns:

    true if the key exists in this metadata, false otherwise

    public java.lang.CharSequence getText(java.lang.String key)

    Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key.

    Parameters:

    key: The key the value is stored under

    Returns:

    a CharSequence value, or null

    public java.lang.String getMediaId()

    Returns the media id, or null if the id doesn't exist.

    This is equivalent to the MediaMetadata.getString(String) with the MediaMetadata.METADATA_KEY_MEDIA_ID.

    Returns:

    media id. Can be null

    See also: MediaMetadata.METADATA_KEY_MEDIA_ID

    public java.lang.String getString(java.lang.String key)

    Returns the value associated with the given key, or null if no mapping of the desired type exists for the given key or a null value is explicitly associated with the key.

    Parameters:

    key: The key the value is stored under

    Returns:

    a String value, or null

    public long getLong(java.lang.String key)

    Returns the value associated with the given key, or 0L if no long exists for the given key.

    Parameters:

    key: The key the value is stored under

    Returns:

    a long value

    public Rating getRating(java.lang.String key)

    Return a Rating for the given key or null if no rating exists for the given key.

    For the MediaMetadata.METADATA_KEY_USER_RATING, A null return value means that user rating cannot be set by MediaController.

    Parameters:

    key: The key the value is stored under

    Returns:

    A Rating or null

    public float getFloat(java.lang.String key)

    Return the value associated with the given key, or 0.0f if no long exists for the given key.

    Parameters:

    key: The key the value is stored under

    Returns:

    a float value

    public Bitmap getBitmap(java.lang.String key)

    Return a Bitmap for the given key or null if no bitmap exists for the given key.

    Parameters:

    key: The key the value is stored under

    Returns:

    A Bitmap or null

    public Bundle getExtras()

    Get the extra from the metadata object.

    Returns:

    A or null

    public int size()

    Get the number of fields in this metadata.

    Returns:

    The number of fields in the metadata.

    public java.util.Set<java.lang.String> keySet()

    Returns a Set containing the Strings used as keys in this metadata.

    Returns:

    a Set of String keys

    public java.lang.String toString()

    public java.lang.Object getObject(java.lang.String key)

    Gets the object which matches the given key in the backing bundle.

    public void onPreParceling(boolean isStream)

    public void onPostParceling()

    Source

    /*
     * Copyright 2018 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package androidx.media2;
    
    import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
    
    import android.graphics.Bitmap;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Bundle;
    import android.util.Log;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import androidx.annotation.RestrictTo;
    import androidx.annotation.StringDef;
    import androidx.collection.ArrayMap;
    import androidx.media2.MediaLibraryService.MediaLibrarySession;
    import androidx.versionedparcelable.CustomVersionedParcelable;
    import androidx.versionedparcelable.ParcelField;
    import androidx.versionedparcelable.ParcelImpl;
    import androidx.versionedparcelable.ParcelUtils;
    import androidx.versionedparcelable.VersionedParcelable;
    import androidx.versionedparcelable.VersionedParcelize;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    
    /**
     * Contains metadata about an item, such as the title, artist, etc. This is optional, but you'd
     * better to provide this as much as possible when you're using media widget and/or session APIs.
     * <p>
     * The media widget components build its UI based on the metadata here. For an example,
     * {@link androidx.media2.widget.MediaControlView} will show title from the metadata.
     * <p>
     * The {@link MediaLibrarySession} would require some metadata values when it provides
     * {@link MediaItem}s to {@link MediaBrowser}.
     * <p>
     * Topics covered here:
     * <ol>
     * <li><a href="#MediaId">Media ID</a>
     * <li><a href="#Browsable">Browsable type</a>
     * <li><a href="#Playable">Playable</a>
     * <li><a href="#Duration">Duration</a>
     * <li><a href="#UserRating">User rating</a>
     * </ol>
     * <a name="MediaId"></a>
     * <h3>{@link MediaMetadata#METADATA_KEY_MEDIA_ID Media ID}</h3>
     * <p>
     * If set, the media ID must be the persistent key for the underlying media contents, so
     * {@link MediaController} and {@link MediaBrowser} can store the information and reuse it later.
     * Some APIs requires a media ID (e.g. {@link MediaController#setRating}, so you'd better specify
     * one.
     * <p>
     * Typical example of using media ID is the URI of the contents, but use it with the caution because
     * the metadata is shared across the process in plain text.
     * <p>
     * The {@link MediaLibrarySession} would require it for the library root, so {@link MediaBrowser}
     * can call subsequent {@link MediaBrowser#getChildren} with the ID.
     * <p>
     * <a name="Browsable"></a>
     * <h3>{@link MediaMetadata#METADATA_KEY_BROWSABLE Browsable type}</h3>
     * <p>
     * Browsable defines whether the media item has children and type of children if any. With this,
     * {@link MediaBrowser} can know whether the subsequent {@link MediaBrowser#getChildren} would
     * successfuly run.
     * <p>
     * The {@link MediaLibrarySession} would require the explicit browsable type for the the media items
     * returned by the
     * {@link androidx.media2.MediaLibraryService.MediaLibrarySession.MediaLibrarySessionCallback}.
     * <p>
     * <a name="Playable"></a>
     * <h3>{@link MediaMetadata#METADATA_KEY_PLAYABLE Playable type}</h3>
     * <p>
     * Playable defines whether the media item can be played or not. It may be possible for a playlist
     * to contain a media item which isn't playable in order to show a disabled media item.
     * <p>
     * The {@link MediaLibrarySession} would require the explicit playable value for the the media items
     * returned by the
     * {@link androidx.media2.MediaLibraryService.MediaLibrarySession.MediaLibrarySessionCallback}.
     * <p>
     * <a name="Duration"></a>
     * <li><a href="#Duration">{@link MediaMetadata#METADATA_KEY_DURATION Duration}</a>
     * The duration is the length of the contents. The {@link MediaController} can only get the
     * duration through the metadata. This tells when would the playback ends, and also tells about the
     * allowed range of {@link MediaController#seekTo(long)}.
     * <p>
     * If it's not set by developer, {@link MediaSession} would update the duration in the metadata
     * with the {@link SessionPlayer#getDuration()}.
     * <p>
     * <a name="UserRating"></a>
     * <li><a href="#UserRating">{@link MediaMetadata#METADATA_KEY_USER_RATING User rating}</a>
     * <p>
     * Prefer to have unrated user rating instead of {@code null}, so {@link MediaController} can know
     * the possible user rating type for calling {@link MediaController#setRating(String, Rating)}.
     */
    // New version of MediaMetadata with following changes
    //   - Don't implement Parcelable for updatable support.
    //   - Also support MediaDescription features. MediaDescription is deprecated instead because
    //     it was insufficient for controller to display media contents. (e.g. duration is missing)
    @VersionedParcelize(isCustom = true)
    public final class MediaMetadata extends CustomVersionedParcelable {
        private static final String TAG = "MediaMetadata";
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the title of the media.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_TITLE = android.media.MediaMetadata.METADATA_KEY_TITLE;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the artist of the media.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_ARTIST =
                android.media.MediaMetadata.METADATA_KEY_ARTIST;
    
        /**
         * The metadata key for a {@link Long} typed value to retrieve the information about the
         * duration of the media in ms. A negative duration indicates that the duration is unknown
         * (or infinite).
         *
         * @see Builder#putLong(String, long)
         * @see #getLong(String)
         */
        public static final String METADATA_KEY_DURATION =
                android.media.MediaMetadata.METADATA_KEY_DURATION;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the album title for the media.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_ALBUM =
                android.media.MediaMetadata.METADATA_KEY_ALBUM;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the author of the media.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_AUTHOR =
                android.media.MediaMetadata.METADATA_KEY_AUTHOR;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the writer of the media.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_WRITER =
                android.media.MediaMetadata.METADATA_KEY_WRITER;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the composer of the media.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_COMPOSER =
                android.media.MediaMetadata.METADATA_KEY_COMPOSER;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the compilation status of the media.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_COMPILATION =
                android.media.MediaMetadata.METADATA_KEY_COMPILATION;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the date the media was created or published.
         * The format is unspecified but RFC 3339 is recommended.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_DATE = android.media.MediaMetadata.METADATA_KEY_DATE;
    
        /**
         * The metadata key for a {@link Long} typed value to retrieve the information about the year
         * the media was created or published.
         *
         * @see Builder#putLong(String, long)
         * @see #getLong(String)
         */
        public static final String METADATA_KEY_YEAR = android.media.MediaMetadata.METADATA_KEY_YEAR;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the genre of the media.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_GENRE = android.media.MediaMetadata.METADATA_KEY_GENRE;
    
        /**
         * The metadata key for a {@link Long} typed value to retrieve the information about the
         * track number for the media.
         *
         * @see Builder#putLong(String, long)
         * @see #getLong(String)
         */
        public static final String METADATA_KEY_TRACK_NUMBER =
                android.media.MediaMetadata.METADATA_KEY_TRACK_NUMBER;
    
        /**
         * The metadata key for a {@link Long} typed value to retrieve the information about the
         * number of tracks in the media's original source.
         *
         * @see Builder#putLong(String, long)
         * @see #getLong(String)
         */
        public static final String METADATA_KEY_NUM_TRACKS =
                android.media.MediaMetadata.METADATA_KEY_NUM_TRACKS;
    
        /**
         * The metadata key for a {@link Long} typed value to retrieve the information about the
         * disc number for the media's original source.
         *
         * @see Builder#putLong(String, long)
         * @see #getLong(String)
         */
        public static final String METADATA_KEY_DISC_NUMBER =
                android.media.MediaMetadata.METADATA_KEY_DISC_NUMBER;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the artist for the album of the media's original source.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_ALBUM_ARTIST =
                android.media.MediaMetadata.METADATA_KEY_ALBUM_ARTIST;
    
        /**
         * The metadata key for a {@link Bitmap} typed value to retrieve the information about the
         * artwork for the media.
         * The artwork should be relatively small and may be scaled down if it is too large.
         * For higher resolution artwork, {@link #METADATA_KEY_ART_URI} should be used instead.
         *
         * @see Builder#putBitmap(String, Bitmap)
         * @see #getBitmap(String)
         */
        public static final String METADATA_KEY_ART = android.media.MediaMetadata.METADATA_KEY_ART;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about Uri of the artwork for the media.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_ART_URI =
                android.media.MediaMetadata.METADATA_KEY_ART_URI;
    
        /**
         * The metadata key for a {@link Bitmap} typed value to retrieve the information about the
         * artwork for the album of the media's original source.
         * The artwork should be relatively small and may be scaled down if it is too large.
         * For higher resolution artwork, {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead.
         *
         * @see Builder#putBitmap(String, Bitmap)
         * @see #getBitmap(String)
         */
        public static final String METADATA_KEY_ALBUM_ART =
                android.media.MediaMetadata.METADATA_KEY_ALBUM_ART;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the Uri of the artwork for the album of the media's original source.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_ALBUM_ART_URI =
                android.media.MediaMetadata.METADATA_KEY_ALBUM_ART_URI;
    
        /**
         * The metadata key for a {@link Rating} typed value to retrieve the information about the
         * user's rating for the media. Prefer to have unrated user rating instead of {@code null}, so
         * {@link MediaController} can know the possible user rating type.
         *
         * @see Builder#putRating(String, Rating)
         * @see #getRating(String)
         * @see <a href="#UserRating">User rating</a>
         */
        public static final String METADATA_KEY_USER_RATING =
                android.media.MediaMetadata.METADATA_KEY_USER_RATING;
    
        /**
         * The metadata key for a {@link Rating} typed value to retrieve the information about the
         * overall rating for the media.
         *
         * @see Builder#putRating(String, Rating)
         * @see #getRating(String)
         */
        public static final String METADATA_KEY_RATING =
                android.media.MediaMetadata.METADATA_KEY_RATING;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the title that is suitable for display to the user.
         * It will generally be the same as {@link #METADATA_KEY_TITLE} but may differ for some formats.
         * When displaying media described by this metadata, this should be preferred if present.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_DISPLAY_TITLE =
                android.media.MediaMetadata.METADATA_KEY_DISPLAY_TITLE;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the subtitle that is suitable for display to the user.
         * When displaying a second line for media described by this metadata, this should be preferred
         * to other fields if present.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_DISPLAY_SUBTITLE =
                android.media.MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the description that is suitable for display to the user.
         * When displaying more information for media described by this metadata,
         * this should be preferred to other fields if present.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_DISPLAY_DESCRIPTION =
                android.media.MediaMetadata.METADATA_KEY_DISPLAY_DESCRIPTION;
    
        /**
         * The metadata key for a {@link Bitmap} typed value to retrieve the information about the icon
         * or thumbnail that is suitable for display to the user.
         * When displaying an icon for media described by this metadata, this should be preferred to
         * other fields if present.
         * <p>
         * The icon should be relatively small and may be scaled down if it is too large.
         * For higher resolution artwork, {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead.
         *
         * @see Builder#putBitmap(String, Bitmap)
         * @see #getBitmap(String)
         */
        public static final String METADATA_KEY_DISPLAY_ICON =
                android.media.MediaMetadata.METADATA_KEY_DISPLAY_ICON;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the Uri of icon or thumbnail that is suitable for display to the user.
         * When displaying more information for media described by this metadata, the
         * display description should be preferred to other fields when present.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_DISPLAY_ICON_URI =
                android.media.MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the media ID of the content. This value is specific to the
         * service providing the content. If used, this should be a persistent key for the underlying
         * content. This ID is used by {@link MediaController} and {@link MediaBrowser}.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         * @see <a href="#MediaID">Media ID</a>
         */
        public static final String METADATA_KEY_MEDIA_ID =
                android.media.MediaMetadata.METADATA_KEY_MEDIA_ID;
    
        /**
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the Uri of the content. This value is specific to the service providing the
         * content.
         *
         * @see Builder#putText(String, CharSequence)
         * @see Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        public static final String METADATA_KEY_MEDIA_URI =
                android.media.MediaMetadata.METADATA_KEY_MEDIA_URI;
    
        /**
         * @hide
         * The metadata key for a {@link Float} typed value to retrieve the information about the
         * radio frequency if this metadata represents radio content.
         *
         * @see Builder#putFloat(String, float)
         * @see #getFloat(String)
         */
        @RestrictTo(LIBRARY_GROUP)
        public static final String METADATA_KEY_RADIO_FREQUENCY =
                "androidx.media2.metadata.RADIO_FREQUENCY";
    
        /**
         * @hide
         * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
         * information about the radio program name if this metadata represents radio content.
         *
         * @see MediaMetadata.Builder#putText(String, CharSequence)
         * @see MediaMetadata.Builder#putString(String, String)
         * @see #getText(String)
         * @see #getString(String)
         */
        @RestrictTo(LIBRARY_GROUP)
        public static final String METADATA_KEY_RADIO_PROGRAM_NAME =
                "androidx.media2.metadata.RADIO_PROGRAM_NAME";
    
        /**
         * The metadata key for a {@link Long} typed value to retrieve the information about the type
         * of browsable. It should be one of the following:
         * <ul>
         * <li>{@link #BROWSABLE_TYPE_NONE}</li>
         * <li>{@link #BROWSABLE_TYPE_MIXED}</li>
         * <li>{@link #BROWSABLE_TYPE_TITLES}</li>
         * <li>{@link #BROWSABLE_TYPE_ALBUMS}</li>
         * <li>{@link #BROWSABLE_TYPE_ARTISTS}</li>
         * <li>{@link #BROWSABLE_TYPE_GENRES}</li>
         * <li>{@link #BROWSABLE_TYPE_PLAYLISTS}</li>
         * <li>{@link #BROWSABLE_TYPE_YEARS}</li>
         * </ul>
         * <p>
         * The values other than {@link #BROWSABLE_TYPE_NONE} mean that the media item has children.[
         * <p>
         * This matches with the bluetooth folder type of the media specified in the section 6.10.2.2 of
         * the Bluetooth AVRCP 1.5.
         *
         * @see Builder#putLong(String, long)
         * @see #getLong(String)
         * @see <a href="#Browsable">Browsable</a>
         */
        public static final String METADATA_KEY_BROWSABLE =
                "androidx.media2.metadata.BROWSABLE";
    
        /**
         * The type of browsable for non-browsable media item.
         */
        public static final long BROWSABLE_TYPE_NONE = -1;
    
        /**
         * The type of browsable that is unknown or contains media items of mixed types.
         * <p>
         * This value matches with the folder type 'Mixed' as specified in the section 6.10.2.2 of the
         * Bluetooth AVRCP 1.5.
         */
        public static final long BROWSABLE_TYPE_MIXED = 0;
    
        /**
         * The type of browsable that only contains playable media items.
         * <p>
         * This value matches with the folder type 'Titles' as specified in the section 6.10.2.2 of the
         * Bluetooth AVRCP 1.5.
         */
        public static final long BROWSABLE_TYPE_TITLES = 1;
    
        /**
         * The type of browsable that contains browsable items categorized by album.
         * <p>
         * This value matches with the folder type 'Albums' as specified in the section 6.10.2.2 of the
         * Bluetooth AVRCP 1.5.
         */
        public static final long BROWSABLE_TYPE_ALBUMS = 2;
    
        /**
         * The type of browsable that contains browsable items categorized by artist.
         * <p>
         * This value matches with the folder type 'Artists' as specified in the section 6.10.2.2 of the
         * Bluetooth AVRCP 1.5.
         */
        public static final long BROWSABLE_TYPE_ARTISTS = 3;
    
        /**
         * The type of browsable that contains browsable items categorized by genre.
         * <p>
         * This value matches with the folder type 'Genres' as specified in the section 6.10.2.2 of the
         * Bluetooth AVRCP 1.5.
         */
        public static final long BROWSABLE_TYPE_GENRES = 4;
    
        /**
         * The type of browsable that contains browsable items categorized by playlist.
         * <p>
         * This value matches with the folder type 'Playlists' as specified in the section 6.10.2.2 of
         * the Bluetooth AVRCP 1.5.
         */
        public static final long BROWSABLE_TYPE_PLAYLISTS = 5;
    
        /**
         * The type of browsable that contains browsable items categorized by year.
         * <p>
         * This value matches with the folder type 'Years' as specified in the section 6.10.2.2 of the
         * Bluetooth AVRCP 1.5.
         */
        public static final long BROWSABLE_TYPE_YEARS = 6;
    
        /**
         * The metadata key for a {@link Long} typed value to retrieve the information about whether
         * the media is playable. A value of 0 indicates it is not a playable item.
         * A value of 1 or non-zero indicates it is playable.
         *
         * @see Builder#putLong(String, long)
         * @see #getLong(String)
         * @see <a href="#Playable">Playable</a>
         */
        public static final String METADATA_KEY_PLAYABLE = "androidx.media2.metadata.PLAYABLE";
    
        /**
         * The metadata key for a {@link Long} typed value to retrieve the information about whether
         * the media is an advertisement. A value of 0 indicates it is not an advertisement.
         * A value of 1 or non-zero indicates it is an advertisement.
         * If not specified, this value is set to 0 by default.
         *
         * @see Builder#putLong(String, long)
         * @see #getLong(String)
         */
        public static final String METADATA_KEY_ADVERTISEMENT =
                "androidx.media2.metadata.ADVERTISEMENT";
    
        /**
         * The metadata key for a {@link Long} typed value to retrieve the information about the
         * download status of the media which will be used for later offline playback. It should be
         * one of the following:
         *
         * <ul>
         * <li>{@link #STATUS_NOT_DOWNLOADED}</li>
         * <li>{@link #STATUS_DOWNLOADING}</li>
         * <li>{@link #STATUS_DOWNLOADED}</li>
         * </ul>
         *
         * @see Builder#putLong(String, long)
         * @see #getLong(String)
         */
        public static final String METADATA_KEY_DOWNLOAD_STATUS =
                "androidx.media2.metadata.DOWNLOAD_STATUS";
    
        /**
         * The status value to indicate the media item is not downloaded.
         *
         * @see #METADATA_KEY_DOWNLOAD_STATUS
         */
        public static final long STATUS_NOT_DOWNLOADED = 0;
    
        /**
         * The status value to indicate the media item is being downloaded.
         *
         * @see #METADATA_KEY_DOWNLOAD_STATUS
         */
        public static final long STATUS_DOWNLOADING = 1;
    
        /**
         * The status value to indicate the media item is downloaded for later offline playback.
         *
         * @see #METADATA_KEY_DOWNLOAD_STATUS
         */
        public static final long STATUS_DOWNLOADED = 2;
    
        /**
         * A {@link Bundle} extra.
         */
        public static final String METADATA_KEY_EXTRAS = "androidx.media2.metadata.EXTRAS";
    
        /**
         * @hide
         */
        @RestrictTo(LIBRARY_GROUP)
        @StringDef({METADATA_KEY_TITLE, METADATA_KEY_ARTIST, METADATA_KEY_ALBUM, METADATA_KEY_AUTHOR,
                METADATA_KEY_WRITER, METADATA_KEY_COMPOSER, METADATA_KEY_COMPILATION,
                METADATA_KEY_DATE, METADATA_KEY_GENRE, METADATA_KEY_ALBUM_ARTIST, METADATA_KEY_ART_URI,
                METADATA_KEY_ALBUM_ART_URI, METADATA_KEY_DISPLAY_TITLE, METADATA_KEY_DISPLAY_SUBTITLE,
                METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_KEY_DISPLAY_ICON_URI,
                METADATA_KEY_MEDIA_ID, METADATA_KEY_MEDIA_URI, METADATA_KEY_RADIO_PROGRAM_NAME})
        @Retention(RetentionPolicy.SOURCE)
        public @interface TextKey {}
    
        /**
         * @hide
         */
        @RestrictTo(LIBRARY_GROUP)
        @StringDef({METADATA_KEY_DURATION, METADATA_KEY_YEAR, METADATA_KEY_TRACK_NUMBER,
                METADATA_KEY_NUM_TRACKS, METADATA_KEY_DISC_NUMBER, METADATA_KEY_BROWSABLE,
                METADATA_KEY_PLAYABLE, METADATA_KEY_ADVERTISEMENT, METADATA_KEY_DOWNLOAD_STATUS})
        @Retention(RetentionPolicy.SOURCE)
        public @interface LongKey {}
    
        /**
         * @hide
         */
        @RestrictTo(LIBRARY_GROUP)
        @StringDef({METADATA_KEY_ART, METADATA_KEY_ALBUM_ART, METADATA_KEY_DISPLAY_ICON})
        @Retention(RetentionPolicy.SOURCE)
        public @interface BitmapKey {}
    
        /**
         * @hide
         */
        @RestrictTo(LIBRARY_GROUP)
        @StringDef({METADATA_KEY_USER_RATING, METADATA_KEY_RATING})
        @Retention(RetentionPolicy.SOURCE)
        public @interface RatingKey {}
    
        /**
         * @hide
         */
        @RestrictTo(LIBRARY_GROUP)
        @StringDef({METADATA_KEY_RADIO_FREQUENCY})
        @Retention(RetentionPolicy.SOURCE)
        public @interface FloatKey {}
    
        /**
         * @hide
         */
        @RestrictTo(LIBRARY_GROUP)
        @StringDef({METADATA_KEY_EXTRAS})
        @Retention(RetentionPolicy.SOURCE)
        public @interface BundleKey {}
    
        static final int METADATA_TYPE_LONG = 0;
        static final int METADATA_TYPE_TEXT = 1;
        static final int METADATA_TYPE_BITMAP = 2;
        static final int METADATA_TYPE_RATING = 3;
        static final int METADATA_TYPE_FLOAT = 4;
        static final int METADATA_TYPE_BUNDLE = 5;
        static final ArrayMap<String, Integer> METADATA_KEYS_TYPE;
    
        static {
            METADATA_KEYS_TYPE = new ArrayMap<>();
            METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG);
            METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
            METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
            METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
            METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
            METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP);
            METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP);
            METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
            METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
            METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP);
            METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_RADIO_FREQUENCY, METADATA_TYPE_FLOAT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_RADIO_PROGRAM_NAME, METADATA_TYPE_TEXT);
            METADATA_KEYS_TYPE.put(METADATA_KEY_BROWSABLE, METADATA_TYPE_LONG);
            METADATA_KEYS_TYPE.put(METADATA_KEY_PLAYABLE, METADATA_TYPE_LONG);
            METADATA_KEYS_TYPE.put(METADATA_KEY_ADVERTISEMENT, METADATA_TYPE_LONG);
            METADATA_KEYS_TYPE.put(METADATA_KEY_DOWNLOAD_STATUS, METADATA_TYPE_LONG);
            METADATA_KEYS_TYPE.put(METADATA_KEY_EXTRAS, METADATA_TYPE_BUNDLE);
        }
    
        private static final @MediaMetadata.TextKey
        String[] PREFERRED_DESCRIPTION_ORDER = {
                METADATA_KEY_TITLE,
                METADATA_KEY_ARTIST,
                METADATA_KEY_ALBUM,
                METADATA_KEY_ALBUM_ARTIST,
                METADATA_KEY_WRITER,
                METADATA_KEY_AUTHOR,
                METADATA_KEY_COMPOSER
        };
    
        private static final @MediaMetadata.BitmapKey
        String[] PREFERRED_BITMAP_ORDER = {
                METADATA_KEY_DISPLAY_ICON,
                METADATA_KEY_ART,
                METADATA_KEY_ALBUM_ART
        };
    
        private static final @MediaMetadata.TextKey
        String[] PREFERRED_URI_ORDER = {
                METADATA_KEY_DISPLAY_ICON_URI,
                METADATA_KEY_ART_URI,
                METADATA_KEY_ALBUM_ART_URI
        };
    
        @ParcelField(1)
        Bundle mBundle;
    
        @ParcelField(2)
        ParcelImplListSlice mBitmapListSlice;
    
        /**
         * Used for VersionedParcelable
         */
        MediaMetadata() {
        }
    
        MediaMetadata(Bundle bundle) {
            mBundle = new Bundle(bundle);
            mBundle.setClassLoader(MediaMetadata.class.getClassLoader());
        }
    
        /**
         * Returns true if the given key is contained in the metadata
         *
         * @param key a String key
         * @return true if the key exists in this metadata, false otherwise
         */
        public boolean containsKey(@NonNull String key) {
            if (key == null) {
                throw new IllegalArgumentException("key shouldn't be null");
            }
            return mBundle.containsKey(key);
        }
    
        /**
         * Returns the value associated with the given key, or null if no mapping of
         * the desired type exists for the given key or a null value is explicitly
         * associated with the key.
         *
         * @param key The key the value is stored under
         * @return a CharSequence value, or null
         */
        public @Nullable CharSequence getText(@NonNull @TextKey String key) {
            if (key == null) {
                throw new IllegalArgumentException("key shouldn't be null");
            }
            return mBundle.getCharSequence(key);
        }
    
        /**
         * Returns the media id, or {@code null} if the id doesn't exist.
         *<p>
         * This is equivalent to the {@link #getString(String)} with the {@link #METADATA_KEY_MEDIA_ID}.
         *
         * @return media id. Can be {@code null}
         * @see #METADATA_KEY_MEDIA_ID
         */
        // TODO(jaewan): Hide -- no setMediaId()
        public @Nullable String getMediaId() {
            return getString(METADATA_KEY_MEDIA_ID);
        }
    
        /**
         * Returns the value associated with the given key, or null if no mapping of
         * the desired type exists for the given key or a null value is explicitly
         * associated with the key.
         *
         * @param key The key the value is stored under
         * @return a String value, or null
         */
        public @Nullable String getString(@NonNull @TextKey String key) {
            if (key == null) {
                throw new IllegalArgumentException("key shouldn't be null");
            }
            CharSequence text = mBundle.getCharSequence(key);
            if (text != null) {
                return text.toString();
            }
            return null;
        }
    
        /**
         * Returns the value associated with the given key, or 0L if no long exists
         * for the given key.
         *
         * @param key The key the value is stored under
         * @return a long value
         */
        public long getLong(@NonNull @LongKey String key) {
            if (key == null) {
                throw new IllegalArgumentException("key shouldn't be null");
            }
            return mBundle.getLong(key, 0);
        }
    
        /**
         * Return a {@link Rating} for the given key or null if no rating exists for
         * the given key.
         * <p>
         * For the {@link #METADATA_KEY_USER_RATING}, A {@code null} return value means that user rating
         * cannot be set by {@link MediaController}.
         *
         * @param key The key the value is stored under
         * @return A {@link Rating} or {@code null}
         */
        public @Nullable Rating getRating(@NonNull @RatingKey String key) {
            if (key == null) {
                throw new IllegalArgumentException("key shouldn't be null");
            }
            Rating rating = null;
            try {
                rating = ParcelUtils.getVersionedParcelable(mBundle, key);
            } catch (Exception e) {
                // ignore, value was not a rating
                Log.w(TAG, "Failed to retrieve a key as Rating.", e);
            }
            return rating;
        }
    
        /**
         * Return the value associated with the given key, or 0.0f if no long exists
         * for the given key.
         *
         * @param key The key the value is stored under
         * @return a float value
         */
        public float getFloat(@NonNull @FloatKey String key) {
            if (key == null) {
                throw new IllegalArgumentException("key shouldn't be null");
            }
            return mBundle.getFloat(key);
        }
    
        /**
         * Return a {@link Bitmap} for the given key or null if no bitmap exists for
         * the given key.
         *
         * @param key The key the value is stored under
         * @return A {@link Bitmap} or null
         */
        public @Nullable Bitmap getBitmap(@NonNull @BitmapKey String key) {
            if (key == null) {
                throw new IllegalArgumentException("key shouldn't be null");
            }
            Bitmap bmp = null;
            try {
                bmp = mBundle.getParcelable(key);
            } catch (Exception e) {
                // ignore, value was not a bitmap
                Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
            }
            return bmp;
        }
    
        /**
         * Get the extra {@link Bundle} from the metadata object.
         *
         * @return A {@link Bundle} or {@code null}
         */
        public @Nullable Bundle getExtras() {
            try {
                return mBundle.getBundle(METADATA_KEY_EXTRAS);
            } catch (Exception e) {
                // ignore, value was not an bundle
                Log.w(TAG, "Failed to retrieve an extra");
            }
            return null;
        }
    
        /**
         * Get the number of fields in this metadata.
         *
         * @return The number of fields in the metadata.
         */
        public int size() {
            return mBundle.size();
        }
    
        /**
         * Returns a Set containing the Strings used as keys in this metadata.
         *
         * @return a Set of String keys
         */
        public @NonNull Set<String> keySet() {
            return mBundle.keySet();
        }
    
        @Override
        public String toString() {
            return mBundle.toString();
        }
    
        /**
         * Gets the object which matches the given key in the backing bundle.
         *
         * @hide
         */
        @RestrictTo(LIBRARY_GROUP)
        public @Nullable Object getObject(@NonNull String key) {
            if (key == null) {
                throw new IllegalArgumentException("key shouldn't be null");
            }
            return mBundle.get(key);
        }
    
        /**
         * @hide
         */
        @Override
        @RestrictTo(LIBRARY_GROUP)
        public void onPreParceling(boolean isStream) {
            List<ParcelImpl> parcelImplList = new ArrayList<>();
            List<String> keysForBitmap = new ArrayList<>();
            for (String key : mBundle.keySet()) {
                Object value = mBundle.get(key);
                if (!(value instanceof Bitmap)) {
                    // Note: Null bitmap is sent through mBundle.
                    continue;
                }
                Bitmap bitmap = (Bitmap) value;
                parcelImplList.add(MediaUtils.toParcelable(new BitmapEntry(key, bitmap)));
                keysForBitmap.add(key);
            }
            for (String key : keysForBitmap) {
                mBundle.remove(key);
            }
            mBitmapListSlice = new ParcelImplListSlice(parcelImplList);
        }
    
        /**
         * @hide
         */
        @Override
        @RestrictTo(LIBRARY_GROUP)
        public void onPostParceling() {
            List<ParcelImpl> parcelImplList = mBitmapListSlice.getList();
            for (ParcelImpl parcelImpl : parcelImplList) {
                BitmapEntry entry = MediaUtils.fromParcelable(parcelImpl);
                mBundle.putParcelable(entry.getKey(), entry.getBitmap());
            }
            parcelImplList.clear();
            mBitmapListSlice = null;
        }
    
        /**
         * Use to build MediaMetadatax objects. The system defined metadata keys must
         * use the appropriate data type.
         */
        public static final class Builder {
            final Bundle mBundle;
    
            /**
             * Create an empty Builder. Any field that should be included in the
             * {@link MediaMetadata} must be added.
             */
            public Builder() {
                mBundle = new Bundle();
            }
    
            /**
             * Create a Builder using a {@link MediaMetadata} instance to set the
             * initial values. All fields in the source metadata will be included in
             * the new metadata. Fields can be overwritten by adding the same key.
             *
             * @param source
             */
            public Builder(@NonNull MediaMetadata source) {
                mBundle = new Bundle(source.mBundle);
            }
    
            /**
             * Only for the backward compatibility.
             *
             * @param bundle
             */
            Builder(Bundle bundle) {
                mBundle = new Bundle(bundle);
            }
    
            /**
             * Put a CharSequence value into the metadata. Custom keys may be used,
             * but if the METADATA_KEYs defined in this class are used they may only
             * be one of the following:
             * <ul>
             * <li>{@link #METADATA_KEY_TITLE}</li>
             * <li>{@link #METADATA_KEY_ARTIST}</li>
             * <li>{@link #METADATA_KEY_ALBUM}</li>
             * <li>{@link #METADATA_KEY_AUTHOR}</li>
             * <li>{@link #METADATA_KEY_WRITER}</li>
             * <li>{@link #METADATA_KEY_COMPOSER}</li>
             * <li>{@link #METADATA_KEY_COMPILATION}</li>
             * <li>{@link #METADATA_KEY_DATE}</li>
             * <li>{@link #METADATA_KEY_GENRE}</li>
             * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
             * <li>{@link #METADATA_KEY_ART_URI}</li>
             * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
             * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
             * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
             * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
             * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
             * <li>{@link #METADATA_KEY_MEDIA_ID}</li>
             * <li>{@link #METADATA_KEY_MEDIA_URI}</li>
             * </ul>
             *
             * @param key The key for referencing this value
             * @param value The CharSequence value to store
             * @return The Builder to allow chaining
             */
            public @NonNull Builder putText(@NonNull @TextKey String key,
                    @Nullable CharSequence value) {
                if (key == null) {
                    throw new IllegalArgumentException("key shouldn't be null");
                }
                if (METADATA_KEYS_TYPE.containsKey(key)) {
                    if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
                        throw new IllegalArgumentException("The " + key
                                + " key cannot be used to put a CharSequence");
                    }
                }
                mBundle.putCharSequence(key, value);
                return this;
            }
    
            /**
             * Put a String value into the metadata. Custom keys may be used, but if
             * the METADATA_KEYs defined in this class are used they may only be one
             * of the following:
             * <ul>
             * <li>{@link #METADATA_KEY_TITLE}</li>
             * <li>{@link #METADATA_KEY_ARTIST}</li>
             * <li>{@link #METADATA_KEY_ALBUM}</li>
             * <li>{@link #METADATA_KEY_AUTHOR}</li>
             * <li>{@link #METADATA_KEY_WRITER}</li>
             * <li>{@link #METADATA_KEY_COMPOSER}</li>
             * <li>{@link #METADATA_KEY_COMPILATION}</li>
             * <li>{@link #METADATA_KEY_DATE}</li>
             * <li>{@link #METADATA_KEY_GENRE}</li>
             * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
             * <li>{@link #METADATA_KEY_ART_URI}</li>
             * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
             * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
             * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
             * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
             * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
             * <li>{@link #METADATA_KEY_MEDIA_ID}</li>
             * <li>{@link #METADATA_KEY_MEDIA_URI}</li>
             * </ul>
             *
             * @param key The key for referencing this value
             * @param value The String value to store
             * @return The Builder to allow chaining
             */
            public @NonNull Builder putString(@NonNull @TextKey String key,
                    @Nullable String value) {
                if (key == null) {
                    throw new IllegalArgumentException("key shouldn't be null");
                }
                if (METADATA_KEYS_TYPE.containsKey(key)) {
                    if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
                        throw new IllegalArgumentException("The " + key
                                + " key cannot be used to put a String");
                    }
                }
                mBundle.putCharSequence(key, value);
                return this;
            }
    
            /**
             * Put a long value into the metadata. Custom keys may be used, but if
             * the METADATA_KEYs defined in this class are used they may only be one
             * of the following:
             * <ul>
             * <li>{@link #METADATA_KEY_DURATION}</li>
             * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
             * <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
             * <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
             * <li>{@link #METADATA_KEY_YEAR}</li>
             * <li>{@link #METADATA_KEY_BROWSABLE}</li>
             * <li>{@link #METADATA_KEY_PLAYABLE}</li>
             * <li>{@link #METADATA_KEY_ADVERTISEMENT}</li>
             * <li>{@link #METADATA_KEY_DOWNLOAD_STATUS}</li>
             * </ul>
             *
             * @param key The key for referencing this value
             * @param value The String value to store
             * @return The Builder to allow chaining
             */
            public @NonNull Builder putLong(@NonNull @LongKey String key, long value) {
                if (key == null) {
                    throw new IllegalArgumentException("key shouldn't be null");
                }
                if (METADATA_KEYS_TYPE.containsKey(key)) {
                    if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
                        throw new IllegalArgumentException("The " + key
                                + " key cannot be used to put a long");
                    }
                }
                mBundle.putLong(key, value);
                return this;
            }
    
            /**
             * Put a {@link Rating} into the metadata. Custom keys may be used, but
             * if the METADATA_KEYs defined in this class are used they may only be
             * one of the following:
             * <ul>
             * <li>{@link #METADATA_KEY_RATING}</li>
             * <li>{@link #METADATA_KEY_USER_RATING}</li>
             * </ul>
             *
             * @param key The key for referencing this value
             * @param value The String value to store
             * @return The Builder to allow chaining
             */
            public @NonNull Builder putRating(@NonNull @RatingKey String key,
                    @Nullable Rating value) {
                if (key == null) {
                    throw new IllegalArgumentException("key shouldn't be null");
                }
                if (METADATA_KEYS_TYPE.containsKey(key)) {
                    if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
                        throw new IllegalArgumentException("The " + key
                                + " key cannot be used to put a Rating");
                    }
                }
                ParcelUtils.putVersionedParcelable(mBundle, key, value);
                return this;
            }
    
            /**
             * Put a {@link Bitmap} into the metadata. Custom keys may be used, but
             * if the METADATA_KEYs defined in this class are used they may only be
             * one of the following:
             * <ul>
             * <li>{@link #METADATA_KEY_ART}</li>
             * <li>{@link #METADATA_KEY_ALBUM_ART}</li>
             * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
             * </ul>
             * Large bitmaps may be scaled down when it is passed to the other process.
             * To pass full resolution images {@link Uri Uris} should be used with
             * {@link #putString}.
             *
             * @param key The key for referencing this value
             * @param value The Bitmap to store
             * @return The Builder to allow chaining
             */
            public @NonNull Builder putBitmap(@NonNull @BitmapKey String key,
                    @Nullable Bitmap value) {
                if (key == null) {
                    throw new IllegalArgumentException("key shouldn't be null");
                }
                if (METADATA_KEYS_TYPE.containsKey(key)) {
                    if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
                        throw new IllegalArgumentException("The " + key
                                + " key cannot be used to put a Bitmap");
                    }
                }
                mBundle.putParcelable(key, value);
                return this;
            }
    
            /**
             * Put a float value into the metadata. Custom keys may be used.
             *
             * @param key The key for referencing this value
             * @param value The float value to store
             * @return The Builder to allow chaining
             */
            public @NonNull Builder putFloat(@NonNull @LongKey String key, float value) {
                if (key == null) {
                    throw new IllegalArgumentException("key shouldn't be null");
                }
                if (METADATA_KEYS_TYPE.containsKey(key)) {
                    if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_FLOAT) {
                        throw new IllegalArgumentException("The " + key
                                + " key cannot be used to put a float");
                    }
                }
                mBundle.putFloat(key, value);
                return this;
            }
    
            /**
             * Set a bundle of extras.
             *
             * @param extras The extras to include with this description or null.
             * @return The Builder to allow chaining
             */
            public @NonNull Builder setExtras(@Nullable Bundle extras) {
                mBundle.putBundle(METADATA_KEY_EXTRAS, extras);
                return this;
            }
    
            /**
             * Creates a {@link MediaMetadata} instance with the specified fields.
             *
             * @return The new MediaMetadatax instance
             */
            public @NonNull MediaMetadata build() {
                return new MediaMetadata(mBundle);
            }
        }
    
        /**
         * Stores a bitmap and the matching key. Used for sending bitmaps to other process one-by-one.
         */
        @VersionedParcelize
        static final class BitmapEntry implements VersionedParcelable {
            static final int BITMAP_SIZE_LIMIT_IN_BYTES = 256 * 1024; // 256 KB
    
            @ParcelField(1)
            String mKey;
    
            @ParcelField(2)
            Bitmap mBitmap;
    
            /**
             * Used for VersionedParcelable
             */
            BitmapEntry() {
            }
    
            BitmapEntry(@NonNull String key, @NonNull Bitmap bitmap) {
                mKey = key;
                mBitmap = bitmap;
    
                // Scale bitmap if it is large.
                final int sizeInBytes = getBitmapSizeInBytes(mBitmap);
                if (sizeInBytes > BITMAP_SIZE_LIMIT_IN_BYTES) {
                    int oldWidth = bitmap.getWidth();
                    int oldHeight = bitmap.getHeight();
    
                    double scaleFactor = Math.sqrt(BITMAP_SIZE_LIMIT_IN_BYTES / (double) sizeInBytes);
                    int newWidth = (int) (oldWidth * scaleFactor);
                    int newHeight = (int) (oldHeight * scaleFactor);
                    Log.i(TAG, "Scaling large bitmap of " + oldWidth + "x" + oldHeight + " into "
                            + newWidth + "x" + newHeight);
                    mBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
                }
            }
    
            String getKey() {
                return mKey;
            }
    
            Bitmap getBitmap() {
                return mBitmap;
            }
    
            private int getBitmapSizeInBytes(Bitmap bitmap) {
                if (Build.VERSION.SDK_INT >= 19) {
                    return bitmap.getAllocationByteCount();
                } else {
                    return bitmap.getByteCount();
                }
            }
        }
    }