diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 887eea6c08..0d6f026f79 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -22,6 +22,8 @@ * Metadata: * Parse multiple null-separated values from ID3 frames, as permitted by ID3 v2.4. + * Add `MediaMetadata.mediaType` to denote the type of content or the type + of folder described by the metadata. * Cast extension * Bump Cast SDK version to 21.2.0. diff --git a/libraries/common/src/main/java/androidx/media3/common/MediaMetadata.java b/libraries/common/src/main/java/androidx/media3/common/MediaMetadata.java index 05d37b29de..b1d23866a0 100644 --- a/libraries/common/src/main/java/androidx/media3/common/MediaMetadata.java +++ b/libraries/common/src/main/java/androidx/media3/common/MediaMetadata.java @@ -76,6 +76,7 @@ public final class MediaMetadata implements Bundleable { @Nullable private CharSequence genre; @Nullable private CharSequence compilation; @Nullable private CharSequence station; + @Nullable private @MediaType Integer mediaType; @Nullable private Bundle extras; public Builder() {} @@ -111,6 +112,7 @@ public final class MediaMetadata implements Bundleable { this.genre = mediaMetadata.genre; this.compilation = mediaMetadata.compilation; this.station = mediaMetadata.station; + this.mediaType = mediaMetadata.mediaType; this.extras = mediaMetadata.extras; } @@ -383,6 +385,14 @@ public final class MediaMetadata implements Bundleable { return this; } + /** Sets the {@link MediaType}. */ + @CanIgnoreReturnValue + @UnstableApi + public Builder setMediaType(@Nullable @MediaType Integer mediaType) { + this.mediaType = mediaType; + return this; + } + /** Sets the extras {@link Bundle}. */ @CanIgnoreReturnValue public Builder setExtras(@Nullable Bundle extras) { @@ -529,6 +539,9 @@ public final class MediaMetadata implements Bundleable { if (mediaMetadata.station != null) { setStation(mediaMetadata.station); } + if (mediaMetadata.mediaType != null) { + setMediaType(mediaMetadata.mediaType); + } if (mediaMetadata.extras != null) { setExtras(mediaMetadata.extras); } @@ -542,12 +555,186 @@ public final class MediaMetadata implements Bundleable { } } + /** + * The type of content described by the media item. + * + *

One of {@link #MEDIA_TYPE_MIXED}, {@link #MEDIA_TYPE_MUSIC}, {@link + * #MEDIA_TYPE_AUDIO_BOOK_CHAPTER}, {@link #MEDIA_TYPE_PODCAST_EPISODE}, {@link + * #MEDIA_TYPE_RADIO_STATION}, {@link #MEDIA_TYPE_NEWS}, {@link #MEDIA_TYPE_VIDEO}, {@link + * #MEDIA_TYPE_TRAILER}, {@link #MEDIA_TYPE_MOVIE}, {@link #MEDIA_TYPE_TV_SHOW}, {@link + * #MEDIA_TYPE_ALBUM}, {@link #MEDIA_TYPE_ARTIST}, {@link #MEDIA_TYPE_GENRE}, {@link + * #MEDIA_TYPE_PLAYLIST}, {@link #MEDIA_TYPE_YEAR}, {@link #MEDIA_TYPE_AUDIO_BOOK}, {@link + * #MEDIA_TYPE_PODCAST}, {@link #MEDIA_TYPE_TV_CHANNEL}, {@link #MEDIA_TYPE_TV_SERIES}, {@link + * #MEDIA_TYPE_TV_SEASON}, {@link #MEDIA_TYPE_FOLDER_MIXED}, {@link #MEDIA_TYPE_FOLDER_ALBUMS}, + * {@link #MEDIA_TYPE_FOLDER_ARTISTS}, {@link #MEDIA_TYPE_FOLDER_GENRES}, {@link + * #MEDIA_TYPE_FOLDER_PLAYLISTS}, {@link #MEDIA_TYPE_FOLDER_YEARS}, {@link + * #MEDIA_TYPE_FOLDER_AUDIO_BOOKS}, {@link #MEDIA_TYPE_FOLDER_PODCASTS}, {@link + * #MEDIA_TYPE_FOLDER_TV_CHANNELS}, {@link #MEDIA_TYPE_FOLDER_TV_SERIES}, {@link + * #MEDIA_TYPE_FOLDER_TV_SHOWS}, {@link #MEDIA_TYPE_FOLDER_RADIO_STATIONS}, {@link + * #MEDIA_TYPE_FOLDER_NEWS}, {@link #MEDIA_TYPE_FOLDER_VIDEOS}, {@link + * #MEDIA_TYPE_FOLDER_TRAILERS} or {@link #MEDIA_TYPE_FOLDER_MOVIES}. + */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @Target(TYPE_USE) + @UnstableApi + @IntDef({ + MEDIA_TYPE_MIXED, + MEDIA_TYPE_MUSIC, + MEDIA_TYPE_AUDIO_BOOK_CHAPTER, + MEDIA_TYPE_PODCAST_EPISODE, + MEDIA_TYPE_RADIO_STATION, + MEDIA_TYPE_NEWS, + MEDIA_TYPE_VIDEO, + MEDIA_TYPE_TRAILER, + MEDIA_TYPE_MOVIE, + MEDIA_TYPE_TV_SHOW, + MEDIA_TYPE_ALBUM, + MEDIA_TYPE_ARTIST, + MEDIA_TYPE_GENRE, + MEDIA_TYPE_PLAYLIST, + MEDIA_TYPE_YEAR, + MEDIA_TYPE_AUDIO_BOOK, + MEDIA_TYPE_PODCAST, + MEDIA_TYPE_TV_CHANNEL, + MEDIA_TYPE_TV_SERIES, + MEDIA_TYPE_TV_SEASON, + MEDIA_TYPE_FOLDER_MIXED, + MEDIA_TYPE_FOLDER_ALBUMS, + MEDIA_TYPE_FOLDER_ARTISTS, + MEDIA_TYPE_FOLDER_GENRES, + MEDIA_TYPE_FOLDER_PLAYLISTS, + MEDIA_TYPE_FOLDER_YEARS, + MEDIA_TYPE_FOLDER_AUDIO_BOOKS, + MEDIA_TYPE_FOLDER_PODCASTS, + MEDIA_TYPE_FOLDER_TV_CHANNELS, + MEDIA_TYPE_FOLDER_TV_SERIES, + MEDIA_TYPE_FOLDER_TV_SHOWS, + MEDIA_TYPE_FOLDER_RADIO_STATIONS, + MEDIA_TYPE_FOLDER_NEWS, + MEDIA_TYPE_FOLDER_VIDEOS, + MEDIA_TYPE_FOLDER_TRAILERS, + MEDIA_TYPE_FOLDER_MOVIES, + }) + public @interface MediaType {} + + /** Media of undetermined type or a mix of multiple {@linkplain MediaType media types}. */ + @UnstableApi public static final int MEDIA_TYPE_MIXED = 0; + /** {@link MediaType} for music. */ + @UnstableApi public static final int MEDIA_TYPE_MUSIC = 1; + /** {@link MediaType} for an audio book chapter. */ + @UnstableApi public static final int MEDIA_TYPE_AUDIO_BOOK_CHAPTER = 2; + /** {@link MediaType} for a podcast episode. */ + @UnstableApi public static final int MEDIA_TYPE_PODCAST_EPISODE = 3; + /** {@link MediaType} for a radio station. */ + @UnstableApi public static final int MEDIA_TYPE_RADIO_STATION = 4; + /** {@link MediaType} for news. */ + @UnstableApi public static final int MEDIA_TYPE_NEWS = 5; + /** {@link MediaType} for a video. */ + @UnstableApi public static final int MEDIA_TYPE_VIDEO = 6; + /** {@link MediaType} for a movie trailer. */ + @UnstableApi public static final int MEDIA_TYPE_TRAILER = 7; + /** {@link MediaType} for a movie. */ + @UnstableApi public static final int MEDIA_TYPE_MOVIE = 8; + /** {@link MediaType} for a TV show. */ + @UnstableApi public static final int MEDIA_TYPE_TV_SHOW = 9; + /** + * {@link MediaType} for a group of items (e.g., {@link #MEDIA_TYPE_MUSIC music}) belonging to an + * album. + */ + @UnstableApi public static final int MEDIA_TYPE_ALBUM = 10; + /** + * {@link MediaType} for a group of items (e.g., {@link #MEDIA_TYPE_MUSIC music}) from the same + * artist. + */ + @UnstableApi public static final int MEDIA_TYPE_ARTIST = 11; + /** + * {@link MediaType} for a group of items (e.g., {@link #MEDIA_TYPE_MUSIC music}) of the same + * genre. + */ + @UnstableApi public static final int MEDIA_TYPE_GENRE = 12; + /** + * {@link MediaType} for a group of items (e.g., {@link #MEDIA_TYPE_MUSIC music}) forming a + * playlist. + */ + @UnstableApi public static final int MEDIA_TYPE_PLAYLIST = 13; + /** + * {@link MediaType} for a group of items (e.g., {@link #MEDIA_TYPE_MUSIC music}) from the same + * year. + */ + @UnstableApi public static final int MEDIA_TYPE_YEAR = 14; + /** + * {@link MediaType} for a group of items forming an audio book. Items in this group are typically + * of type {@link #MEDIA_TYPE_AUDIO_BOOK_CHAPTER}. + */ + @UnstableApi public static final int MEDIA_TYPE_AUDIO_BOOK = 15; + /** + * {@link MediaType} for a group of items belonging to a podcast. Items in this group are + * typically of type {@link #MEDIA_TYPE_PODCAST_EPISODE}. + */ + @UnstableApi public static final int MEDIA_TYPE_PODCAST = 16; + /** + * {@link MediaType} for a group of items that are part of a TV channel. Items in this group are + * typically of type {@link #MEDIA_TYPE_TV_SHOW}, {@link #MEDIA_TYPE_TV_SERIES} or {@link + * #MEDIA_TYPE_MOVIE}. + */ + @UnstableApi public static final int MEDIA_TYPE_TV_CHANNEL = 17; + /** + * {@link MediaType} for a group of items that are part of a TV series. Items in this group are + * typically of type {@link #MEDIA_TYPE_TV_SHOW} or {@link #MEDIA_TYPE_TV_SEASON}. + */ + @UnstableApi public static final int MEDIA_TYPE_TV_SERIES = 18; + /** + * {@link MediaType} for a group of items that are part of a TV series. Items in this group are + * typically of type {@link #MEDIA_TYPE_TV_SHOW}. + */ + @UnstableApi public static final int MEDIA_TYPE_TV_SEASON = 19; + /** {@link MediaType} for a folder with mixed or undetermined content. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_MIXED = 20; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_ALBUM albums}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_ALBUMS = 21; + /** {@link MediaType} for a folder containing {@linkplain #FIELD_ARTIST artists}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_ARTISTS = 22; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_GENRE genres}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_GENRES = 23; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_PLAYLIST playlists}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_PLAYLISTS = 24; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_YEAR years}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_YEARS = 25; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_AUDIO_BOOK audio books}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_AUDIO_BOOKS = 26; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_PODCAST podcasts}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_PODCASTS = 27; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_TV_CHANNEL TV channels}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_TV_CHANNELS = 28; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_TV_SERIES TV series}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_TV_SERIES = 29; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_TV_SHOW TV shows}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_TV_SHOWS = 30; + /** + * {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_RADIO_STATION radio + * stations}. + */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_RADIO_STATIONS = 31; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_NEWS news}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_NEWS = 32; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_VIDEO videos}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_VIDEOS = 33; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_TRAILER movie trailers}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_TRAILERS = 34; + /** {@link MediaType} for a folder containing {@linkplain #MEDIA_TYPE_MOVIE movies}. */ + @UnstableApi public static final int MEDIA_TYPE_FOLDER_MOVIES = 35; + /** * The folder type of the media item. * *

This can be used as the type of a browsable bluetooth folder (see section 6.10.2.2 of the Bluetooth * AVRCP 1.6.2). + * + *

One of {@link #FOLDER_TYPE_NONE}, {@link #FOLDER_TYPE_MIXED}, {@link #FOLDER_TYPE_TITLES}, + * {@link #FOLDER_TYPE_ALBUMS}, {@link #FOLDER_TYPE_ARTISTS}, {@link #FOLDER_TYPE_GENRES}, {@link + * #FOLDER_TYPE_PLAYLISTS} or {@link #FOLDER_TYPE_YEARS}. */ // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility // with Kotlin usages from before TYPE_USE was added. @@ -588,6 +775,17 @@ public final class MediaMetadata implements Bundleable { * *

Values sourced from the ID3 v2.4 specification (See section 4.14 of * https://id3.org/id3v2.4.0-frames). + * + *

One of {@link #PICTURE_TYPE_OTHER}, {@link #PICTURE_TYPE_FILE_ICON}, {@link + * #PICTURE_TYPE_FILE_ICON_OTHER}, {@link #PICTURE_TYPE_FRONT_COVER}, {@link + * #PICTURE_TYPE_BACK_COVER}, {@link #PICTURE_TYPE_LEAFLET_PAGE}, {@link #PICTURE_TYPE_MEDIA}, + * {@link #PICTURE_TYPE_LEAD_ARTIST_PERFORMER}, {@link #PICTURE_TYPE_ARTIST_PERFORMER}, {@link + * #PICTURE_TYPE_CONDUCTOR}, {@link #PICTURE_TYPE_BAND_ORCHESTRA}, {@link #PICTURE_TYPE_COMPOSER}, + * {@link #PICTURE_TYPE_LYRICIST}, {@link #PICTURE_TYPE_RECORDING_LOCATION}, {@link + * #PICTURE_TYPE_DURING_RECORDING}, {@link #PICTURE_TYPE_DURING_PERFORMANCE}, {@link + * #PICTURE_TYPE_MOVIE_VIDEO_SCREEN_CAPTURE}, {@link #PICTURE_TYPE_A_BRIGHT_COLORED_FISH}, {@link + * #PICTURE_TYPE_ILLUSTRATION}, {@link #PICTURE_TYPE_BAND_ARTIST_LOGO} or {@link + * #PICTURE_TYPE_PUBLISHER_STUDIO_LOGO}. */ // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility // with Kotlin usages from before TYPE_USE was added. @@ -729,6 +927,8 @@ public final class MediaMetadata implements Bundleable { @Nullable public final CharSequence compilation; /** Optional name of the station streaming the media. */ @Nullable public final CharSequence station; + /** Optional {@link MediaType}. */ + @UnstableApi @Nullable public final @MediaType Integer mediaType; /** * Optional extras {@link Bundle}. @@ -770,6 +970,7 @@ public final class MediaMetadata implements Bundleable { this.genre = builder.genre; this.compilation = builder.compilation; this.station = builder.station; + this.mediaType = builder.mediaType; this.extras = builder.extras; } @@ -816,7 +1017,8 @@ public final class MediaMetadata implements Bundleable { && Util.areEqual(totalDiscCount, that.totalDiscCount) && Util.areEqual(genre, that.genre) && Util.areEqual(compilation, that.compilation) - && Util.areEqual(station, that.station); + && Util.areEqual(station, that.station) + && Util.areEqual(mediaType, that.mediaType); } @Override @@ -851,7 +1053,8 @@ public final class MediaMetadata implements Bundleable { totalDiscCount, genre, compilation, - station); + station, + mediaType); } // Bundleable implementation. @@ -891,7 +1094,8 @@ public final class MediaMetadata implements Bundleable { FIELD_GENRE, FIELD_COMPILATION, FIELD_STATION, - FIELD_EXTRAS + FIELD_MEDIA_TYPE, + FIELD_EXTRAS, }) private @interface FieldNumber {} @@ -926,6 +1130,7 @@ public final class MediaMetadata implements Bundleable { private static final int FIELD_COMPILATION = 28; private static final int FIELD_ARTWORK_DATA_TYPE = 29; private static final int FIELD_STATION = 30; + private static final int FIELD_MEDIA_TYPE = 31; private static final int FIELD_EXTRAS = 1000; @UnstableApi @@ -993,6 +1198,9 @@ public final class MediaMetadata implements Bundleable { if (artworkDataType != null) { bundle.putInt(keyForField(FIELD_ARTWORK_DATA_TYPE), artworkDataType); } + if (mediaType != null) { + bundle.putInt(keyForField(FIELD_MEDIA_TYPE), mediaType); + } if (extras != null) { bundle.putBundle(keyForField(FIELD_EXTRAS), extras); } @@ -1074,6 +1282,9 @@ public final class MediaMetadata implements Bundleable { if (bundle.containsKey(keyForField(FIELD_TOTAL_DISC_COUNT))) { builder.setTotalDiscCount(bundle.getInt(keyForField(FIELD_TOTAL_DISC_COUNT))); } + if (bundle.containsKey(keyForField(FIELD_MEDIA_TYPE))) { + builder.setMediaType(bundle.getInt(keyForField(FIELD_MEDIA_TYPE))); + } return builder.build(); } diff --git a/libraries/common/src/test/java/androidx/media3/common/MediaMetadataTest.java b/libraries/common/src/test/java/androidx/media3/common/MediaMetadataTest.java index 7e606597c4..4d66cd922a 100644 --- a/libraries/common/src/test/java/androidx/media3/common/MediaMetadataTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/MediaMetadataTest.java @@ -64,6 +64,7 @@ public class MediaMetadataTest { assertThat(mediaMetadata.genre).isNull(); assertThat(mediaMetadata.compilation).isNull(); assertThat(mediaMetadata.station).isNull(); + assertThat(mediaMetadata.mediaType).isNull(); assertThat(mediaMetadata.extras).isNull(); } @@ -149,6 +150,7 @@ public class MediaMetadataTest { .setGenre("Pop") .setCompilation("Amazing songs.") .setStation("radio station") + .setMediaType(MediaMetadata.MEDIA_TYPE_MIXED) .setExtras(extras) .build(); }