Expand MediaItems in session demo instead of just replacing them
When MediaItems are added from the controller, we currently completely replace the item with the one from our database, overriding any potential additional information the controller may have set. Also forward the onAddMediaItems/onSetMediaItems callbacks to common helper methods instead of redirecting them through super methods #minor-release Issue: androidx/media#706 PiperOrigin-RevId: 573799351
This commit is contained in:
parent
37c86f3c15
commit
00425dbe80
@ -88,7 +88,7 @@ class PlayableFolderActivity : AppCompatActivity() {
|
||||
browser.shuffleModeEnabled = true
|
||||
browser.prepare()
|
||||
browser.play()
|
||||
browser?.sessionActivity?.send()
|
||||
browser.sessionActivity?.send()
|
||||
}
|
||||
|
||||
findViewById<Button>(R.id.play_button).setOnClickListener {
|
||||
|
@ -25,6 +25,7 @@ import androidx.media3.session.CommandButton
|
||||
import androidx.media3.session.LibraryResult
|
||||
import androidx.media3.session.MediaLibraryService
|
||||
import androidx.media3.session.MediaSession
|
||||
import androidx.media3.session.MediaSession.MediaItemsWithStartPosition
|
||||
import androidx.media3.session.SessionCommand
|
||||
import androidx.media3.session.SessionResult
|
||||
import com.google.common.collect.ImmutableList
|
||||
@ -32,7 +33,7 @@ import com.google.common.util.concurrent.Futures
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
|
||||
/** A [MediaLibraryService.MediaLibrarySession.Callback] implementation. */
|
||||
open class DemoMediaLibrarySessionCallback(private val context: Context) :
|
||||
open class DemoMediaLibrarySessionCallback(context: Context) :
|
||||
MediaLibraryService.MediaLibrarySession.Callback {
|
||||
|
||||
init {
|
||||
@ -155,14 +156,7 @@ open class DemoMediaLibrarySessionCallback(private val context: Context) :
|
||||
controller: MediaSession.ControllerInfo,
|
||||
mediaItems: List<MediaItem>
|
||||
): ListenableFuture<List<MediaItem>> {
|
||||
val playlist = mutableListOf<MediaItem>()
|
||||
mediaItems.forEach { mediaItem ->
|
||||
when (mediaItem.requestMetadata.searchQuery) {
|
||||
null -> MediaItemTree.getItem(mediaItem.mediaId)?.let { playlist.add(it) }
|
||||
else -> playlist.addAll(MediaItemTree.search(mediaItem.requestMetadata.searchQuery!!))
|
||||
}
|
||||
}
|
||||
return Futures.immediateFuture(playlist)
|
||||
return Futures.immediateFuture(resolveMediaItems(mediaItems))
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class) // MediaSession.MediaItemsWithStartPosition
|
||||
@ -172,34 +166,57 @@ open class DemoMediaLibrarySessionCallback(private val context: Context) :
|
||||
mediaItems: List<MediaItem>,
|
||||
startIndex: Int,
|
||||
startPositionMs: Long
|
||||
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
|
||||
): ListenableFuture<MediaItemsWithStartPosition> {
|
||||
if (mediaItems.size == 1) {
|
||||
// Try to expand a single item to a playlist.
|
||||
val mediaId = mediaItems.first().mediaId
|
||||
val mediaItem = MediaItemTree.getItem(mediaId)
|
||||
val playlist = mutableListOf<MediaItem>()
|
||||
var indexInPlaylist = startIndex
|
||||
mediaItem?.apply {
|
||||
if (mediaMetadata.isBrowsable == true) {
|
||||
// Get children browsable item.
|
||||
playlist.addAll(MediaItemTree.getChildren(mediaId))
|
||||
} else if (requestMetadata.searchQuery == null) {
|
||||
// Try to get the parent and its children.
|
||||
MediaItemTree.getParentId(mediaId)?.let {
|
||||
playlist.addAll(MediaItemTree.getChildren(it))
|
||||
indexInPlaylist = MediaItemTree.getIndexInMediaItems(mediaId, playlist)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (playlist.isNotEmpty()) {
|
||||
// Return the expanded playlist to be set on the player of the session.
|
||||
return Futures.immediateFuture(
|
||||
MediaSession.MediaItemsWithStartPosition(playlist, indexInPlaylist, startPositionMs)
|
||||
)
|
||||
maybeExpandSingleItemToPlaylist(mediaItems.first(), startIndex, startPositionMs)?.also {
|
||||
return Futures.immediateFuture(it)
|
||||
}
|
||||
}
|
||||
// Let super serve the request if item isn't expanded.
|
||||
return super.onSetMediaItems(mediaSession, browser, mediaItems, startIndex, startPositionMs)
|
||||
return Futures.immediateFuture(
|
||||
MediaItemsWithStartPosition(resolveMediaItems(mediaItems), startIndex, startPositionMs)
|
||||
)
|
||||
}
|
||||
|
||||
private fun resolveMediaItems(mediaItems: List<MediaItem>): List<MediaItem> {
|
||||
val playlist = mutableListOf<MediaItem>()
|
||||
mediaItems.forEach { mediaItem ->
|
||||
if (mediaItem.mediaId.isNotEmpty()) {
|
||||
MediaItemTree.expandItem(mediaItem)?.let { playlist.add(it) }
|
||||
} else if (mediaItem.requestMetadata.searchQuery != null) {
|
||||
playlist.addAll(MediaItemTree.search(mediaItem.requestMetadata.searchQuery!!))
|
||||
}
|
||||
}
|
||||
return playlist
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class) // MediaSession.MediaItemsWithStartPosition
|
||||
private fun maybeExpandSingleItemToPlaylist(
|
||||
mediaItem: MediaItem,
|
||||
startIndex: Int,
|
||||
startPositionMs: Long
|
||||
): MediaItemsWithStartPosition? {
|
||||
var playlist = listOf<MediaItem>()
|
||||
var indexInPlaylist = startIndex
|
||||
MediaItemTree.getItem(mediaItem.mediaId)?.apply {
|
||||
if (mediaMetadata.isBrowsable == true) {
|
||||
// Get children browsable item.
|
||||
playlist = MediaItemTree.getChildren(mediaId)
|
||||
} else if (requestMetadata.searchQuery == null) {
|
||||
// Try to get the parent and its children.
|
||||
MediaItemTree.getParentId(mediaId)?.let {
|
||||
playlist =
|
||||
MediaItemTree.getChildren(it).map { mediaItem ->
|
||||
if (mediaItem.mediaId == mediaId) MediaItemTree.expandItem(mediaItem)!! else mediaItem
|
||||
}
|
||||
indexInPlaylist = MediaItemTree.getIndexInMediaItems(mediaId, playlist)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (playlist.isNotEmpty()) {
|
||||
return MediaItemsWithStartPosition(playlist, indexInPlaylist, startPositionMs)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onSearch(
|
||||
|
@ -17,9 +17,11 @@ package androidx.media3.demo.session
|
||||
|
||||
import android.content.res.AssetManager
|
||||
import android.net.Uri
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.MediaItem.SubtitleConfiguration
|
||||
import androidx.media3.common.MediaMetadata
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.google.common.collect.ImmutableList
|
||||
import java.io.BufferedReader
|
||||
import java.lang.StringBuilder
|
||||
@ -275,6 +277,18 @@ object MediaItemTree {
|
||||
return treeNodes[id]?.item
|
||||
}
|
||||
|
||||
fun expandItem(item: MediaItem): MediaItem? {
|
||||
val treeItem = getItem(item.mediaId) ?: return null
|
||||
@OptIn(UnstableApi::class) // MediaMetadata.populate
|
||||
val metadata = treeItem.mediaMetadata.buildUpon().populate(item.mediaMetadata).build()
|
||||
return item
|
||||
.buildUpon()
|
||||
.setMediaMetadata(metadata)
|
||||
.setSubtitleConfigurations(treeItem.localConfiguration?.subtitleConfigurations ?: listOf())
|
||||
.setUri(treeItem.localConfiguration?.uri)
|
||||
.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the media ID of the parent of the given media ID, or null if the media ID wasn't found.
|
||||
*
|
||||
@ -342,19 +356,6 @@ object MediaItemTree {
|
||||
return treeNodes[id]?.getChildren() ?: listOf()
|
||||
}
|
||||
|
||||
fun getRandomItem(): MediaItem {
|
||||
var curRoot = getRootItem()
|
||||
while (curRoot.mediaMetadata.isBrowsable == true) {
|
||||
val children = getChildren(curRoot.mediaId)
|
||||
curRoot = children.random()
|
||||
}
|
||||
return curRoot
|
||||
}
|
||||
|
||||
fun getItemFromTitle(title: String): MediaItem? {
|
||||
return titleMap[title]?.item
|
||||
}
|
||||
|
||||
private fun normalizeSearchText(text: CharSequence?): String {
|
||||
if (text.isNullOrEmpty() || text.trim().length == 1) {
|
||||
return ""
|
||||
|
Loading…
x
Reference in New Issue
Block a user