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:
tonihei 2022-12-07 10:22:45 +00:00 committed by Ian Baker
parent 4895bc42ff
commit ae8000aeca
15 changed files with 251 additions and 78 deletions

View File

@ -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.

View File

@ -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()
}

View File

@ -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;
}
}
}

View File

@ -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)

View File

@ -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");
}

View File

@ -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();

View File

@ -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)}.

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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)

View File

@ -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();