Replace MediaMetadata folderType by isBrowsable
The folder type has a mix of information about the item. It shows whether the item is browsable (type != FOLDER_TYPE_NONE) and which Bluetooth folder type to set for legacy session information. It's a lot clearer to split this into a boolean isBrowsable and use the existing mediaType to map back to the bluetooth folder type where required. folderType is not marked as deprecated yet as this would be an API change, which will be done later. PiperOrigin-RevId: 493544589
This commit is contained in:
parent
4895bc42ff
commit
ae8000aeca
@ -32,6 +32,9 @@ Release notes
|
||||
ID3 v2.4.
|
||||
* Add `MediaMetadata.mediaType` to denote the type of content or the type
|
||||
of folder described by the metadata.
|
||||
* Add `MediaMetadata.isBrowsable` as a replacement for
|
||||
`MediaMetadata.folderType`. The folder type will be deprecated in the
|
||||
next release.
|
||||
* Remove deprecated symbols:
|
||||
* Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder`
|
||||
instead.
|
||||
|
@ -20,11 +20,6 @@ import android.net.Uri
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
||||
import androidx.media3.common.MediaMetadata
|
||||
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_ALBUMS
|
||||
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_ARTISTS
|
||||
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_GENRES
|
||||
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_MIXED
|
||||
import androidx.media3.common.MediaMetadata.FOLDER_TYPE_NONE
|
||||
import androidx.media3.common.util.Util
|
||||
import com.google.common.collect.ImmutableList
|
||||
import org.json.JSONObject
|
||||
@ -67,7 +62,8 @@ object MediaItemTree {
|
||||
title: String,
|
||||
mediaId: String,
|
||||
isPlayable: Boolean,
|
||||
@MediaMetadata.FolderType folderType: Int,
|
||||
isBrowsable: Boolean,
|
||||
mediaType: @MediaMetadata.MediaType Int,
|
||||
subtitleConfigurations: List<SubtitleConfiguration> = mutableListOf(),
|
||||
album: String? = null,
|
||||
artist: String? = null,
|
||||
@ -81,9 +77,10 @@ object MediaItemTree {
|
||||
.setTitle(title)
|
||||
.setArtist(artist)
|
||||
.setGenre(genre)
|
||||
.setFolderType(folderType)
|
||||
.setIsBrowsable(isBrowsable)
|
||||
.setIsPlayable(isPlayable)
|
||||
.setArtworkUri(imageUri)
|
||||
.setMediaType(mediaType)
|
||||
.build()
|
||||
|
||||
return MediaItem.Builder()
|
||||
@ -109,7 +106,8 @@ object MediaItemTree {
|
||||
title = "Root Folder",
|
||||
mediaId = ROOT_ID,
|
||||
isPlayable = false,
|
||||
folderType = FOLDER_TYPE_MIXED
|
||||
isBrowsable = true,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED
|
||||
)
|
||||
)
|
||||
treeNodes[ALBUM_ID] =
|
||||
@ -118,7 +116,8 @@ object MediaItemTree {
|
||||
title = "Album Folder",
|
||||
mediaId = ALBUM_ID,
|
||||
isPlayable = false,
|
||||
folderType = FOLDER_TYPE_MIXED
|
||||
isBrowsable = true,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS
|
||||
)
|
||||
)
|
||||
treeNodes[ARTIST_ID] =
|
||||
@ -127,7 +126,8 @@ object MediaItemTree {
|
||||
title = "Artist Folder",
|
||||
mediaId = ARTIST_ID,
|
||||
isPlayable = false,
|
||||
folderType = FOLDER_TYPE_MIXED
|
||||
isBrowsable = true,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ARTISTS
|
||||
)
|
||||
)
|
||||
treeNodes[GENRE_ID] =
|
||||
@ -136,7 +136,8 @@ object MediaItemTree {
|
||||
title = "Genre Folder",
|
||||
mediaId = GENRE_ID,
|
||||
isPlayable = false,
|
||||
folderType = FOLDER_TYPE_MIXED
|
||||
isBrowsable = true,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_GENRES
|
||||
)
|
||||
)
|
||||
treeNodes[ROOT_ID]!!.addChild(ALBUM_ID)
|
||||
@ -188,7 +189,8 @@ object MediaItemTree {
|
||||
title = title,
|
||||
mediaId = idInTree,
|
||||
isPlayable = true,
|
||||
folderType = FOLDER_TYPE_NONE,
|
||||
isBrowsable = false,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_MUSIC,
|
||||
subtitleConfigurations,
|
||||
album = album,
|
||||
artist = artist,
|
||||
@ -207,7 +209,8 @@ object MediaItemTree {
|
||||
title = album,
|
||||
mediaId = albumFolderIdInTree,
|
||||
isPlayable = true,
|
||||
folderType = FOLDER_TYPE_ALBUMS,
|
||||
isBrowsable = true,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_ALBUM,
|
||||
subtitleConfigurations
|
||||
)
|
||||
)
|
||||
@ -223,7 +226,8 @@ object MediaItemTree {
|
||||
title = artist,
|
||||
mediaId = artistFolderIdInTree,
|
||||
isPlayable = true,
|
||||
folderType = FOLDER_TYPE_ARTISTS,
|
||||
isBrowsable = true,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_ARTIST,
|
||||
subtitleConfigurations
|
||||
)
|
||||
)
|
||||
@ -239,7 +243,8 @@ object MediaItemTree {
|
||||
title = genre,
|
||||
mediaId = genreFolderIdInTree,
|
||||
isPlayable = true,
|
||||
folderType = FOLDER_TYPE_GENRES,
|
||||
isBrowsable = true,
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_GENRE,
|
||||
subtitleConfigurations
|
||||
)
|
||||
)
|
||||
@ -262,7 +267,7 @@ object MediaItemTree {
|
||||
|
||||
fun getRandomItem(): MediaItem {
|
||||
var curRoot = getRootItem()
|
||||
while (curRoot.mediaMetadata.folderType != FOLDER_TYPE_NONE) {
|
||||
while (curRoot.mediaMetadata.isBrowsable == true) {
|
||||
val children = getChildren(curRoot.mediaId)!!
|
||||
curRoot = children.random()
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ public final class MediaMetadata implements Bundleable {
|
||||
@Nullable private Integer trackNumber;
|
||||
@Nullable private Integer totalTrackCount;
|
||||
@Nullable private @FolderType Integer folderType;
|
||||
@Nullable private Boolean isBrowsable;
|
||||
@Nullable private Boolean isPlayable;
|
||||
@Nullable private Integer recordingYear;
|
||||
@Nullable private Integer recordingMonth;
|
||||
@ -97,6 +98,7 @@ public final class MediaMetadata implements Bundleable {
|
||||
this.trackNumber = mediaMetadata.trackNumber;
|
||||
this.totalTrackCount = mediaMetadata.totalTrackCount;
|
||||
this.folderType = mediaMetadata.folderType;
|
||||
this.isBrowsable = mediaMetadata.isBrowsable;
|
||||
this.isPlayable = mediaMetadata.isPlayable;
|
||||
this.recordingYear = mediaMetadata.recordingYear;
|
||||
this.recordingMonth = mediaMetadata.recordingMonth;
|
||||
@ -246,13 +248,26 @@ public final class MediaMetadata implements Bundleable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the {@link FolderType}. */
|
||||
/**
|
||||
* Sets the {@link FolderType}.
|
||||
*
|
||||
* <p>This method will be deprecated. Use {@link #setIsBrowsable} to indicate if an item is a
|
||||
* browsable folder and use {@link #setMediaType} to indicate the type of the folder.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setFolderType(@Nullable @FolderType Integer folderType) {
|
||||
this.folderType = folderType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets whether the media is a browsable folder. */
|
||||
@UnstableApi
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setIsBrowsable(@Nullable Boolean isBrowsable) {
|
||||
this.isBrowsable = isBrowsable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets whether the media is playable. */
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setIsPlayable(@Nullable Boolean isPlayable) {
|
||||
@ -491,6 +506,9 @@ public final class MediaMetadata implements Bundleable {
|
||||
if (mediaMetadata.folderType != null) {
|
||||
setFolderType(mediaMetadata.folderType);
|
||||
}
|
||||
if (mediaMetadata.isBrowsable != null) {
|
||||
setIsBrowsable(mediaMetadata.isBrowsable);
|
||||
}
|
||||
if (mediaMetadata.isPlayable != null) {
|
||||
setIsPlayable(mediaMetadata.isPlayable);
|
||||
}
|
||||
@ -874,9 +892,16 @@ public final class MediaMetadata implements Bundleable {
|
||||
@Nullable public final Integer trackNumber;
|
||||
/** Optional total number of tracks. */
|
||||
@Nullable public final Integer totalTrackCount;
|
||||
/** Optional {@link FolderType}. */
|
||||
/**
|
||||
* Optional {@link FolderType}.
|
||||
*
|
||||
* <p>This field will be deprecated. Use {@link #isBrowsable} to indicate if an item is a
|
||||
* browsable folder and use {@link #mediaType} to indicate the type of the folder.
|
||||
*/
|
||||
@Nullable public final @FolderType Integer folderType;
|
||||
/** Optional boolean for media playability. */
|
||||
/** Optional boolean to indicate that the media is a browsable folder. */
|
||||
@UnstableApi @Nullable public final Boolean isBrowsable;
|
||||
/** Optional boolean to indicate that the media is playable. */
|
||||
@Nullable public final Boolean isPlayable;
|
||||
/**
|
||||
* @deprecated Use {@link #recordingYear} instead.
|
||||
@ -939,6 +964,22 @@ public final class MediaMetadata implements Bundleable {
|
||||
@Nullable public final Bundle extras;
|
||||
|
||||
private MediaMetadata(Builder builder) {
|
||||
// Handle compatibility for deprecated fields.
|
||||
@Nullable Boolean isBrowsable = builder.isBrowsable;
|
||||
@Nullable Integer folderType = builder.folderType;
|
||||
@Nullable Integer mediaType = builder.mediaType;
|
||||
if (isBrowsable != null) {
|
||||
if (!isBrowsable) {
|
||||
folderType = FOLDER_TYPE_NONE;
|
||||
} else if (folderType == null || folderType == FOLDER_TYPE_NONE) {
|
||||
folderType = mediaType != null ? getFolderTypeFromMediaType(mediaType) : FOLDER_TYPE_MIXED;
|
||||
}
|
||||
} else if (folderType != null) {
|
||||
isBrowsable = folderType != FOLDER_TYPE_NONE;
|
||||
if (isBrowsable && mediaType == null) {
|
||||
mediaType = getMediaTypeFromFolderType(folderType);
|
||||
}
|
||||
}
|
||||
this.title = builder.title;
|
||||
this.artist = builder.artist;
|
||||
this.albumTitle = builder.albumTitle;
|
||||
@ -953,7 +994,8 @@ public final class MediaMetadata implements Bundleable {
|
||||
this.artworkUri = builder.artworkUri;
|
||||
this.trackNumber = builder.trackNumber;
|
||||
this.totalTrackCount = builder.totalTrackCount;
|
||||
this.folderType = builder.folderType;
|
||||
this.folderType = folderType;
|
||||
this.isBrowsable = isBrowsable;
|
||||
this.isPlayable = builder.isPlayable;
|
||||
this.year = builder.recordingYear;
|
||||
this.recordingYear = builder.recordingYear;
|
||||
@ -970,7 +1012,7 @@ public final class MediaMetadata implements Bundleable {
|
||||
this.genre = builder.genre;
|
||||
this.compilation = builder.compilation;
|
||||
this.station = builder.station;
|
||||
this.mediaType = builder.mediaType;
|
||||
this.mediaType = mediaType;
|
||||
this.extras = builder.extras;
|
||||
}
|
||||
|
||||
@ -1003,6 +1045,7 @@ public final class MediaMetadata implements Bundleable {
|
||||
&& Util.areEqual(trackNumber, that.trackNumber)
|
||||
&& Util.areEqual(totalTrackCount, that.totalTrackCount)
|
||||
&& Util.areEqual(folderType, that.folderType)
|
||||
&& Util.areEqual(isBrowsable, that.isBrowsable)
|
||||
&& Util.areEqual(isPlayable, that.isPlayable)
|
||||
&& Util.areEqual(recordingYear, that.recordingYear)
|
||||
&& Util.areEqual(recordingMonth, that.recordingMonth)
|
||||
@ -1039,6 +1082,7 @@ public final class MediaMetadata implements Bundleable {
|
||||
trackNumber,
|
||||
totalTrackCount,
|
||||
folderType,
|
||||
isBrowsable,
|
||||
isPlayable,
|
||||
recordingYear,
|
||||
recordingMonth,
|
||||
@ -1095,6 +1139,7 @@ public final class MediaMetadata implements Bundleable {
|
||||
FIELD_COMPILATION,
|
||||
FIELD_STATION,
|
||||
FIELD_MEDIA_TYPE,
|
||||
FIELD_IS_BROWSABLE,
|
||||
FIELD_EXTRAS,
|
||||
})
|
||||
private @interface FieldNumber {}
|
||||
@ -1131,6 +1176,7 @@ public final class MediaMetadata implements Bundleable {
|
||||
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_IS_BROWSABLE = 32;
|
||||
private static final int FIELD_EXTRAS = 1000;
|
||||
|
||||
@UnstableApi
|
||||
@ -1168,6 +1214,9 @@ public final class MediaMetadata implements Bundleable {
|
||||
if (folderType != null) {
|
||||
bundle.putInt(keyForField(FIELD_FOLDER_TYPE), folderType);
|
||||
}
|
||||
if (isBrowsable != null) {
|
||||
bundle.putBoolean(keyForField(FIELD_IS_BROWSABLE), isBrowsable);
|
||||
}
|
||||
if (isPlayable != null) {
|
||||
bundle.putBoolean(keyForField(FIELD_IS_PLAYABLE), isPlayable);
|
||||
}
|
||||
@ -1255,6 +1304,9 @@ public final class MediaMetadata implements Bundleable {
|
||||
if (bundle.containsKey(keyForField(FIELD_FOLDER_TYPE))) {
|
||||
builder.setFolderType(bundle.getInt(keyForField(FIELD_FOLDER_TYPE)));
|
||||
}
|
||||
if (bundle.containsKey(keyForField(FIELD_IS_BROWSABLE))) {
|
||||
builder.setIsBrowsable(bundle.getBoolean(keyForField(FIELD_IS_BROWSABLE)));
|
||||
}
|
||||
if (bundle.containsKey(keyForField(FIELD_IS_PLAYABLE))) {
|
||||
builder.setIsPlayable(bundle.getBoolean(keyForField(FIELD_IS_PLAYABLE)));
|
||||
}
|
||||
@ -1292,4 +1344,74 @@ public final class MediaMetadata implements Bundleable {
|
||||
private static String keyForField(@FieldNumber int field) {
|
||||
return Integer.toString(field, Character.MAX_RADIX);
|
||||
}
|
||||
|
||||
private static @FolderType int getFolderTypeFromMediaType(@MediaType int mediaType) {
|
||||
switch (mediaType) {
|
||||
case MEDIA_TYPE_ALBUM:
|
||||
case MEDIA_TYPE_ARTIST:
|
||||
case MEDIA_TYPE_AUDIO_BOOK:
|
||||
case MEDIA_TYPE_AUDIO_BOOK_CHAPTER:
|
||||
case MEDIA_TYPE_FOLDER_MOVIES:
|
||||
case MEDIA_TYPE_FOLDER_NEWS:
|
||||
case MEDIA_TYPE_FOLDER_RADIO_STATIONS:
|
||||
case MEDIA_TYPE_FOLDER_TRAILERS:
|
||||
case MEDIA_TYPE_FOLDER_VIDEOS:
|
||||
case MEDIA_TYPE_GENRE:
|
||||
case MEDIA_TYPE_MOVIE:
|
||||
case MEDIA_TYPE_MUSIC:
|
||||
case MEDIA_TYPE_NEWS:
|
||||
case MEDIA_TYPE_PLAYLIST:
|
||||
case MEDIA_TYPE_PODCAST:
|
||||
case MEDIA_TYPE_PODCAST_EPISODE:
|
||||
case MEDIA_TYPE_RADIO_STATION:
|
||||
case MEDIA_TYPE_TRAILER:
|
||||
case MEDIA_TYPE_TV_CHANNEL:
|
||||
case MEDIA_TYPE_TV_SEASON:
|
||||
case MEDIA_TYPE_TV_SERIES:
|
||||
case MEDIA_TYPE_TV_SHOW:
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
case MEDIA_TYPE_YEAR:
|
||||
return FOLDER_TYPE_TITLES;
|
||||
case MEDIA_TYPE_FOLDER_ALBUMS:
|
||||
return FOLDER_TYPE_ALBUMS;
|
||||
case MEDIA_TYPE_FOLDER_ARTISTS:
|
||||
return FOLDER_TYPE_ARTISTS;
|
||||
case MEDIA_TYPE_FOLDER_GENRES:
|
||||
return FOLDER_TYPE_GENRES;
|
||||
case MEDIA_TYPE_FOLDER_PLAYLISTS:
|
||||
return FOLDER_TYPE_PLAYLISTS;
|
||||
case MEDIA_TYPE_FOLDER_YEARS:
|
||||
return FOLDER_TYPE_YEARS;
|
||||
case MEDIA_TYPE_FOLDER_AUDIO_BOOKS:
|
||||
case MEDIA_TYPE_FOLDER_MIXED:
|
||||
case MEDIA_TYPE_FOLDER_TV_CHANNELS:
|
||||
case MEDIA_TYPE_FOLDER_TV_SERIES:
|
||||
case MEDIA_TYPE_FOLDER_TV_SHOWS:
|
||||
case MEDIA_TYPE_FOLDER_PODCASTS:
|
||||
case MEDIA_TYPE_MIXED:
|
||||
default:
|
||||
return FOLDER_TYPE_MIXED;
|
||||
}
|
||||
}
|
||||
|
||||
private static @MediaType int getMediaTypeFromFolderType(@FolderType int folderType) {
|
||||
switch (folderType) {
|
||||
case FOLDER_TYPE_ALBUMS:
|
||||
return MEDIA_TYPE_FOLDER_ALBUMS;
|
||||
case FOLDER_TYPE_ARTISTS:
|
||||
return MEDIA_TYPE_FOLDER_ARTISTS;
|
||||
case FOLDER_TYPE_GENRES:
|
||||
return MEDIA_TYPE_FOLDER_GENRES;
|
||||
case FOLDER_TYPE_PLAYLISTS:
|
||||
return MEDIA_TYPE_FOLDER_PLAYLISTS;
|
||||
case FOLDER_TYPE_TITLES:
|
||||
return MEDIA_TYPE_MIXED;
|
||||
case FOLDER_TYPE_YEARS:
|
||||
return MEDIA_TYPE_FOLDER_YEARS;
|
||||
case FOLDER_TYPE_MIXED:
|
||||
case FOLDER_TYPE_NONE:
|
||||
default:
|
||||
return MEDIA_TYPE_FOLDER_MIXED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ public class MediaMetadataTest {
|
||||
assertThat(mediaMetadata.trackNumber).isNull();
|
||||
assertThat(mediaMetadata.totalTrackCount).isNull();
|
||||
assertThat(mediaMetadata.folderType).isNull();
|
||||
assertThat(mediaMetadata.isBrowsable).isNull();
|
||||
assertThat(mediaMetadata.isPlayable).isNull();
|
||||
assertThat(mediaMetadata.recordingYear).isNull();
|
||||
assertThat(mediaMetadata.recordingMonth).isNull();
|
||||
@ -115,6 +116,61 @@ public class MediaMetadataTest {
|
||||
assertThat(fromBundle.extras.getString(EXTRAS_KEY)).isEqualTo(EXTRAS_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderSetFolderType_toNone_setsIsBrowsableToFalse() {
|
||||
MediaMetadata mediaMetadata =
|
||||
new MediaMetadata.Builder().setFolderType(MediaMetadata.FOLDER_TYPE_NONE).build();
|
||||
|
||||
assertThat(mediaMetadata.isBrowsable).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderSetFolderType_toNotNone_setsIsBrowsableToTrueAndMatchingMediaType() {
|
||||
MediaMetadata mediaMetadata =
|
||||
new MediaMetadata.Builder().setFolderType(MediaMetadata.FOLDER_TYPE_PLAYLISTS).build();
|
||||
|
||||
assertThat(mediaMetadata.isBrowsable).isTrue();
|
||||
assertThat(mediaMetadata.mediaType).isEqualTo(MediaMetadata.MEDIA_TYPE_FOLDER_PLAYLISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
builderSetFolderType_toNotNoneWithManualMediaType_setsIsBrowsableToTrueAndDoesNotOverrideMediaType() {
|
||||
MediaMetadata mediaMetadata =
|
||||
new MediaMetadata.Builder()
|
||||
.setMediaType(MediaMetadata.MEDIA_TYPE_FOLDER_PODCASTS)
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_PLAYLISTS)
|
||||
.build();
|
||||
|
||||
assertThat(mediaMetadata.isBrowsable).isTrue();
|
||||
assertThat(mediaMetadata.mediaType).isEqualTo(MediaMetadata.MEDIA_TYPE_FOLDER_PODCASTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderSetIsBrowsable_toTrueWithoutMediaType_setsFolderTypeToMixed() {
|
||||
MediaMetadata mediaMetadata = new MediaMetadata.Builder().setIsBrowsable(true).build();
|
||||
|
||||
assertThat(mediaMetadata.folderType).isEqualTo(MediaMetadata.FOLDER_TYPE_MIXED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderSetIsBrowsable_toTrueWithMediaType_setsFolderTypeToMatchMediaType() {
|
||||
MediaMetadata mediaMetadata =
|
||||
new MediaMetadata.Builder()
|
||||
.setIsBrowsable(true)
|
||||
.setMediaType(MediaMetadata.MEDIA_TYPE_FOLDER_ARTISTS)
|
||||
.build();
|
||||
|
||||
assertThat(mediaMetadata.folderType).isEqualTo(MediaMetadata.FOLDER_TYPE_ARTISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderSetFolderType_toFalse_setsFolderTypeToNone() {
|
||||
MediaMetadata mediaMetadata = new MediaMetadata.Builder().setIsBrowsable(false).build();
|
||||
|
||||
assertThat(mediaMetadata.folderType).isEqualTo(MediaMetadata.FOLDER_TYPE_NONE);
|
||||
}
|
||||
|
||||
private static MediaMetadata getFullyPopulatedMediaMetadata() {
|
||||
Bundle extras = new Bundle();
|
||||
extras.putString(EXTRAS_KEY, EXTRAS_VALUE);
|
||||
@ -135,6 +191,7 @@ public class MediaMetadataTest {
|
||||
.setTrackNumber(4)
|
||||
.setTotalTrackCount(12)
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_PLAYLISTS)
|
||||
.setIsBrowsable(true)
|
||||
.setIsPlayable(true)
|
||||
.setRecordingYear(2000)
|
||||
.setRecordingMonth(11)
|
||||
|
@ -175,8 +175,8 @@ public final class LibraryResult<V> implements Bundleable {
|
||||
/**
|
||||
* Creates an instance with a media item and {@link #resultCode}{@code ==}{@link #RESULT_SUCCESS}.
|
||||
*
|
||||
* <p>The {@link MediaItem#mediaMetadata} must specify {@link MediaMetadata#folderType} and {@link
|
||||
* MediaMetadata#isPlayable} fields.
|
||||
* <p>The {@link MediaItem#mediaMetadata} must specify {@link MediaMetadata#isBrowsable} (or
|
||||
* {@link MediaMetadata#folderType}) and {@link MediaMetadata#isPlayable} fields.
|
||||
*
|
||||
* @param item The media item.
|
||||
* @param params The optional parameters to describe the media item.
|
||||
@ -192,7 +192,8 @@ public final class LibraryResult<V> implements Bundleable {
|
||||
* #RESULT_SUCCESS}.
|
||||
*
|
||||
* <p>The {@link MediaItem#mediaMetadata} of each item in the list must specify {@link
|
||||
* MediaMetadata#folderType} and {@link MediaMetadata#isPlayable} fields.
|
||||
* MediaMetadata#isBrowsable} (or {@link MediaMetadata#folderType}) and {@link
|
||||
* MediaMetadata#isPlayable} fields.
|
||||
*
|
||||
* @param items The list of media items.
|
||||
* @param params The optional parameters to describe the list of media items.
|
||||
@ -255,7 +256,7 @@ public final class LibraryResult<V> implements Bundleable {
|
||||
|
||||
private static void verifyMediaItem(MediaItem item) {
|
||||
checkNotEmpty(item.mediaId, "mediaId must not be empty");
|
||||
checkArgument(item.mediaMetadata.folderType != null, "mediaMetadata must specify folderType");
|
||||
checkArgument(item.mediaMetadata.isBrowsable != null, "mediaMetadata must specify isBrowsable");
|
||||
checkArgument(item.mediaMetadata.isPlayable != null, "mediaMetadata must specify isPlayable");
|
||||
}
|
||||
|
||||
|
@ -311,7 +311,8 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization;
|
||||
String mediaId = browserCompat.getRoot();
|
||||
MediaMetadata mediaMetadata =
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_MIXED)
|
||||
.setIsBrowsable(true)
|
||||
.setMediaType(MediaMetadata.MEDIA_TYPE_FOLDER_MIXED)
|
||||
.setIsPlayable(false)
|
||||
.setExtras(browserCompat.getExtras())
|
||||
.build();
|
||||
|
@ -213,7 +213,7 @@ public final class MediaConstants {
|
||||
* {@link MediaBrowser#getLibraryRoot}, the preference applies to all playable items within the
|
||||
* browse tree.
|
||||
*
|
||||
* <p>If exposed through {@link MediaMetadata#extras} of a {@linkplain MediaMetadata#folderType
|
||||
* <p>If exposed through {@link MediaMetadata#extras} of a {@linkplain MediaMetadata#isBrowsable
|
||||
* browsable media item}, the preference applies to only the immediate playable children. It takes
|
||||
* precedence over preferences received with {@link MediaBrowser#getLibraryRoot}.
|
||||
*
|
||||
@ -238,7 +238,7 @@ public final class MediaConstants {
|
||||
* {@link MediaBrowser#getLibraryRoot}, the preference applies to all browsable items within the
|
||||
* browse tree.
|
||||
*
|
||||
* <p>If exposed through {@link MediaMetadata#extras} of a {@linkplain MediaMetadata#folderType
|
||||
* <p>If exposed through {@link MediaMetadata#extras} of a {@linkplain MediaMetadata#isBrowsable
|
||||
* browsable media item}, the preference applies to only the immediate browsable children. It
|
||||
* takes precedence over preferences received with {@link
|
||||
* MediaBrowser#getLibraryRoot(LibraryParams)}.
|
||||
|
@ -123,8 +123,9 @@ public abstract class MediaLibraryService extends MediaSessionService {
|
||||
* An extended {@link MediaSession.Callback} for the {@link MediaLibrarySession}.
|
||||
*
|
||||
* <p>When you return {@link LibraryResult} with {@link MediaItem media items}, each item must
|
||||
* have valid {@link MediaItem#mediaId} and specify {@link MediaMetadata#folderType} and {@link
|
||||
* MediaMetadata#isPlayable} in its {@link MediaItem#mediaMetadata}.
|
||||
* have valid {@link MediaItem#mediaId} and specify {@link MediaMetadata#isBrowsable} (or {@link
|
||||
* MediaMetadata#folderType}) and {@link MediaMetadata#isPlayable} in its {@link
|
||||
* MediaItem#mediaMetadata}.
|
||||
*/
|
||||
public interface Callback extends MediaSession.Callback {
|
||||
|
||||
|
@ -145,7 +145,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
MediaDescriptionCompat description = convertToMediaDescriptionCompat(item, artworkBitmap);
|
||||
MediaMetadata metadata = item.mediaMetadata;
|
||||
int flags = 0;
|
||||
if (metadata.folderType != null && metadata.folderType != MediaMetadata.FOLDER_TYPE_NONE) {
|
||||
if (metadata.isBrowsable != null && metadata.isBrowsable) {
|
||||
flags |= MediaBrowserCompat.MediaItem.FLAG_BROWSABLE;
|
||||
}
|
||||
if (metadata.isPlayable != null && metadata.isPlayable) {
|
||||
@ -375,11 +375,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
if (queueTitle == null) {
|
||||
return MediaMetadata.EMPTY;
|
||||
}
|
||||
return new MediaMetadata.Builder()
|
||||
.setTitle(queueTitle)
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_MIXED)
|
||||
.setIsPlayable(true)
|
||||
.build();
|
||||
return new MediaMetadata.Builder().setTitle(queueTitle).build();
|
||||
}
|
||||
|
||||
public static MediaMetadata convertToMediaMetadata(
|
||||
@ -417,20 +413,22 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
builder.setArtworkData(artworkData, MediaMetadata.PICTURE_TYPE_FRONT_COVER);
|
||||
}
|
||||
|
||||
@Nullable Bundle extras = descriptionCompat.getExtras();
|
||||
builder.setExtras(extras);
|
||||
@Nullable Bundle compatExtras = descriptionCompat.getExtras();
|
||||
@Nullable Bundle extras = compatExtras == null ? null : new Bundle(compatExtras);
|
||||
|
||||
if (extras != null && extras.containsKey(MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE)) {
|
||||
builder.setFolderType(
|
||||
convertToFolderType(extras.getLong(MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE)));
|
||||
} else if (browsable) {
|
||||
builder.setFolderType(MediaMetadata.FOLDER_TYPE_MIXED);
|
||||
} else {
|
||||
builder.setFolderType(MediaMetadata.FOLDER_TYPE_NONE);
|
||||
extras.remove(MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE);
|
||||
}
|
||||
builder.setIsBrowsable(browsable);
|
||||
|
||||
if (extras != null && extras.containsKey(MediaConstants.EXTRAS_KEY_MEDIA_TYPE_COMPAT)) {
|
||||
builder.setMediaType((int) extras.getLong(MediaConstants.EXTRAS_KEY_MEDIA_TYPE_COMPAT));
|
||||
extras.remove(MediaConstants.EXTRAS_KEY_MEDIA_TYPE_COMPAT);
|
||||
}
|
||||
if (extras != null && !extras.isEmpty()) {
|
||||
builder.setExtras(extras);
|
||||
}
|
||||
|
||||
builder.setIsPlayable(playable);
|
||||
@ -501,12 +499,13 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
}
|
||||
}
|
||||
|
||||
if (metadataCompat.containsKey(MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE)) {
|
||||
boolean isBrowsable =
|
||||
metadataCompat.containsKey(MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE);
|
||||
builder.setIsBrowsable(isBrowsable);
|
||||
if (isBrowsable) {
|
||||
builder.setFolderType(
|
||||
convertToFolderType(
|
||||
metadataCompat.getLong(MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE)));
|
||||
} else {
|
||||
builder.setFolderType(MediaMetadata.FOLDER_TYPE_NONE);
|
||||
}
|
||||
|
||||
if (metadataCompat.containsKey(MediaConstants.EXTRAS_KEY_MEDIA_TYPE_COMPAT)) {
|
||||
@ -653,7 +652,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
} else if (extraBtFolderType == MediaDescriptionCompat.BT_FOLDER_TYPE_YEARS) {
|
||||
return MediaMetadata.FOLDER_TYPE_YEARS;
|
||||
} else {
|
||||
return MediaMetadata.FOLDER_TYPE_NONE;
|
||||
return MediaMetadata.FOLDER_TYPE_MIXED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,17 +30,14 @@ public class LibraryResultTest {
|
||||
@Test
|
||||
public void constructor_mediaItemWithoutMediaId_throwsIAE() {
|
||||
MediaMetadata metadata =
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_MIXED)
|
||||
.setIsPlayable(true)
|
||||
.build();
|
||||
new MediaMetadata.Builder().setIsBrowsable(true).setIsPlayable(true).build();
|
||||
MediaItem item = new MediaItem.Builder().setMediaMetadata(metadata).build();
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> LibraryResult.ofItem(item, /* params= */ null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructor_mediaItemWithoutFolderType_throwsIAE() {
|
||||
public void constructor_mediaItemWithoutIsBrowsable_throwsIAE() {
|
||||
MediaMetadata metadata = new MediaMetadata.Builder().setIsPlayable(true).build();
|
||||
MediaItem item = new MediaItem.Builder().setMediaId("id").setMediaMetadata(metadata).build();
|
||||
assertThrows(
|
||||
@ -49,8 +46,7 @@ public class LibraryResultTest {
|
||||
|
||||
@Test
|
||||
public void constructor_mediaItemWithoutIsPlayable_throwsIAE() {
|
||||
MediaMetadata metadata =
|
||||
new MediaMetadata.Builder().setFolderType(MediaMetadata.FOLDER_TYPE_MIXED).build();
|
||||
MediaMetadata metadata = new MediaMetadata.Builder().setIsBrowsable(true).build();
|
||||
MediaItem item = new MediaItem.Builder().setMediaId("id").setMediaMetadata(metadata).build();
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> LibraryResult.ofItem(item, /* params= */ null));
|
||||
|
@ -42,7 +42,6 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MediaMetadata;
|
||||
import androidx.media3.session.MediaLibraryService.LibraryParams;
|
||||
import androidx.media3.test.session.common.MediaBrowserConstants;
|
||||
import androidx.media3.test.session.common.TestUtils;
|
||||
@ -155,7 +154,7 @@ public class MediaBrowserListenerTest extends MediaControllerListenerTest {
|
||||
|
||||
assertThat(result.resultCode).isEqualTo(RESULT_SUCCESS);
|
||||
assertThat(result.value.mediaId).isEqualTo(mediaId);
|
||||
assertThat(result.value.mediaMetadata.folderType).isEqualTo(MediaMetadata.FOLDER_TYPE_MIXED);
|
||||
assertThat(result.value.mediaMetadata.isBrowsable).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -142,7 +142,7 @@ public class MediaBrowserServiceCompatCallbackWithMediaBrowserTest {
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(result.resultCode).isEqualTo(LibraryResult.RESULT_SUCCESS);
|
||||
assertItemEquals(testItem, result.value);
|
||||
assertThat(result.value.mediaMetadata.folderType).isEqualTo(MediaMetadata.FOLDER_TYPE_MIXED);
|
||||
assertThat(result.value.mediaMetadata.isBrowsable).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -138,7 +138,6 @@ public class MediaSessionServiceNotificationTest {
|
||||
.setTitle("Test Song Name")
|
||||
.setArtist("Test Artist Name")
|
||||
.setArtworkData(artworkData)
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_NONE)
|
||||
.setIsPlayable(true)
|
||||
.build();
|
||||
}
|
||||
@ -147,7 +146,6 @@ public class MediaSessionServiceNotificationTest {
|
||||
return new MediaMetadata.Builder()
|
||||
.setTitle("New Song Name")
|
||||
.setArtist("New Artist Name")
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_NONE)
|
||||
.setIsPlayable(true)
|
||||
.build();
|
||||
}
|
||||
|
@ -56,8 +56,8 @@ public final class MediaTestUtils {
|
||||
public static MediaItem createMediaItem(String mediaId) {
|
||||
MediaMetadata mediaMetadata =
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_TITLES)
|
||||
.setMediaType(MediaMetadata.MEDIA_TYPE_PLAYLIST)
|
||||
.setIsBrowsable(false)
|
||||
.setIsPlayable(true)
|
||||
.build();
|
||||
return new MediaItem.Builder().setMediaId(mediaId).setMediaMetadata(mediaMetadata).build();
|
||||
@ -66,8 +66,8 @@ public final class MediaTestUtils {
|
||||
public static MediaItem createMediaItemWithArtworkData(String mediaId) {
|
||||
MediaMetadata.Builder mediaMetadataBuilder =
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_TITLES)
|
||||
.setMediaType(MediaMetadata.MEDIA_TYPE_PLAYLIST)
|
||||
.setIsBrowsable(false)
|
||||
.setIsPlayable(true);
|
||||
try {
|
||||
byte[] artworkData =
|
||||
@ -107,8 +107,8 @@ public final class MediaTestUtils {
|
||||
|
||||
public static MediaMetadata createMediaMetadata() {
|
||||
return new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_NONE)
|
||||
.setIsPlayable(false)
|
||||
.setIsBrowsable(false)
|
||||
.setIsPlayable(true)
|
||||
.setTitle(METADATA_TITLE)
|
||||
.setSubtitle(METADATA_SUBTITLE)
|
||||
.setDescription(METADATA_DESCRIPTION)
|
||||
@ -120,8 +120,8 @@ public final class MediaTestUtils {
|
||||
public static MediaMetadata createMediaMetadataWithArtworkData() {
|
||||
MediaMetadata.Builder mediaMetadataBuilder =
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_NONE)
|
||||
.setIsPlayable(false)
|
||||
.setIsBrowsable(false)
|
||||
.setIsPlayable(true)
|
||||
.setTitle(METADATA_TITLE)
|
||||
.setSubtitle(METADATA_SUBTITLE)
|
||||
.setDescription(METADATA_DESCRIPTION)
|
||||
|
@ -102,10 +102,7 @@ public class MockMediaLibraryService extends MediaLibraryService {
|
||||
new MediaItem.Builder()
|
||||
.setMediaId(ROOT_ID)
|
||||
.setMediaMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_MIXED)
|
||||
.setIsPlayable(false)
|
||||
.build())
|
||||
new MediaMetadata.Builder().setIsBrowsable(true).setIsPlayable(false).build())
|
||||
.build();
|
||||
public static final LibraryParams ROOT_PARAMS =
|
||||
new LibraryParams.Builder().setExtras(ROOT_EXTRAS).build();
|
||||
@ -228,10 +225,7 @@ public class MockMediaLibraryService extends MediaLibraryService {
|
||||
new MediaItem.Builder()
|
||||
.setMediaId(customLibraryRoot)
|
||||
.setMediaMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_ALBUMS)
|
||||
.setIsPlayable(false)
|
||||
.build())
|
||||
new MediaMetadata.Builder().setIsBrowsable(true).setIsPlayable(false).build())
|
||||
.build();
|
||||
}
|
||||
if (params != null) {
|
||||
@ -243,10 +237,7 @@ public class MockMediaLibraryService extends MediaLibraryService {
|
||||
new MediaItem.Builder()
|
||||
.setMediaId(ROOT_ID_SUPPORTS_BROWSABLE_CHILDREN_ONLY)
|
||||
.setMediaMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_MIXED)
|
||||
.setIsPlayable(false)
|
||||
.build())
|
||||
new MediaMetadata.Builder().setIsBrowsable(true).setIsPlayable(false).build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -478,7 +469,7 @@ public class MockMediaLibraryService extends MediaLibraryService {
|
||||
private MediaItem createBrowsableMediaItem(String mediaId) {
|
||||
MediaMetadata mediaMetadata =
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_MIXED)
|
||||
.setIsBrowsable(true)
|
||||
.setIsPlayable(false)
|
||||
.setArtworkData(getArtworkData(), MediaMetadata.PICTURE_TYPE_FRONT_COVER)
|
||||
.build();
|
||||
@ -501,7 +492,7 @@ public class MockMediaLibraryService extends MediaLibraryService {
|
||||
extras.putInt(EXTRAS_KEY_COMPLETION_STATUS, EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED);
|
||||
MediaMetadata mediaMetadata =
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_NONE)
|
||||
.setIsBrowsable(false)
|
||||
.setIsPlayable(true)
|
||||
.setExtras(extras)
|
||||
.build();
|
||||
|
Loading…
x
Reference in New Issue
Block a user