service: bundle parent info into extras
Instead of using mediaId. This makes it so that there is only really one mediaId to work with, with an optional extra for playback that I desperately hope is preserved on all instances of Android Auto.
This commit is contained in:
parent
0b3a136320
commit
19f3e07c8e
6 changed files with 44 additions and 74 deletions
|
@ -36,6 +36,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.music.service.MusicServiceFragment
|
||||
import org.oxycblt.auxio.playback.service.PlaybackServiceFragment
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AuxioService :
|
||||
|
@ -149,6 +150,7 @@ class AuxioService :
|
|||
}
|
||||
|
||||
override fun invalidateMusic(mediaId: String) {
|
||||
logD(mediaId)
|
||||
notifyChildrenChanged(mediaId)
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ sealed interface DetailSection {
|
|||
|
||||
data class Artists(override val items: List<Artist>) : PlainSection<Artist>() {
|
||||
override val order = 0
|
||||
override val stringRes = R.string.lbl_songs
|
||||
override val stringRes = R.string.lbl_artists
|
||||
}
|
||||
|
||||
data class Albums(val category: Category, override val items: List<Album>) :
|
||||
|
|
|
@ -47,10 +47,6 @@ sealed interface MediaSessionUID {
|
|||
override fun toString() = "$ID_ITEM:$uid"
|
||||
}
|
||||
|
||||
data class ChildItem(val parentUid: Music.UID, val childUid: Music.UID) : MediaSessionUID {
|
||||
override fun toString() = "$ID_ITEM:$parentUid>$childUid"
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ID_CATEGORY = BuildConfig.APPLICATION_ID + ".category"
|
||||
const val ID_ITEM = BuildConfig.APPLICATION_ID + ".item"
|
||||
|
@ -62,16 +58,7 @@ sealed interface MediaSessionUID {
|
|||
}
|
||||
return when (parts[0]) {
|
||||
ID_CATEGORY -> Tab(TabNode.fromString(parts[1]) ?: return null)
|
||||
ID_ITEM -> {
|
||||
val uids = parts[1].split(">", limit = 2)
|
||||
if (uids.size == 1) {
|
||||
Music.UID.fromString(uids[0])?.let { SingleItem(it) }
|
||||
} else {
|
||||
Music.UID.fromString(uids[0])?.let { parent ->
|
||||
Music.UID.fromString(uids[1])?.let { child -> ChildItem(parent, child) }
|
||||
}
|
||||
}
|
||||
}
|
||||
ID_ITEM -> SingleItem(Music.UID.fromString(parts[1]) ?: return null)
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +76,10 @@ fun header(name: String): Sugar = {
|
|||
putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, name)
|
||||
}
|
||||
|
||||
fun child(of: MusicParent): Sugar = {
|
||||
putString(MusicBrowser.KEY_CHILD_OF, MediaSessionUID.SingleItem(of.uid).toString())
|
||||
}
|
||||
|
||||
private fun style(style: Int): Sugar = {
|
||||
putInt(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM, style)
|
||||
}
|
||||
|
@ -115,17 +106,8 @@ fun TabNode.toMediaItem(context: Context): MediaItem {
|
|||
return MediaItem(description.build(), MediaItem.FLAG_BROWSABLE)
|
||||
}
|
||||
|
||||
fun Song.toMediaDescription(
|
||||
context: Context,
|
||||
parent: MusicParent? = null,
|
||||
vararg sugar: Sugar
|
||||
): MediaDescriptionCompat {
|
||||
val mediaSessionUID =
|
||||
if (parent == null) {
|
||||
MediaSessionUID.SingleItem(uid)
|
||||
} else {
|
||||
MediaSessionUID.ChildItem(parent.uid, uid)
|
||||
}
|
||||
fun Song.toMediaDescription(context: Context, vararg sugar: Sugar): MediaDescriptionCompat {
|
||||
val mediaSessionUID = MediaSessionUID.SingleItem(uid)
|
||||
val extras = makeExtras(context, *sugar)
|
||||
return MediaDescriptionCompat.Builder()
|
||||
.setMediaId(mediaSessionUID.toString())
|
||||
|
@ -138,25 +120,12 @@ fun Song.toMediaDescription(
|
|||
.build()
|
||||
}
|
||||
|
||||
fun Song.toMediaItem(
|
||||
context: Context,
|
||||
parent: MusicParent? = null,
|
||||
vararg sugar: Sugar
|
||||
): MediaItem {
|
||||
return MediaItem(toMediaDescription(context, parent, *sugar), MediaItem.FLAG_PLAYABLE)
|
||||
fun Song.toMediaItem(context: Context, vararg sugar: Sugar): MediaItem {
|
||||
return MediaItem(toMediaDescription(context, *sugar), MediaItem.FLAG_PLAYABLE)
|
||||
}
|
||||
|
||||
fun Album.toMediaItem(
|
||||
context: Context,
|
||||
parent: MusicParent? = null,
|
||||
vararg sugar: Sugar
|
||||
): MediaItem {
|
||||
val mediaSessionUID =
|
||||
if (parent == null) {
|
||||
MediaSessionUID.SingleItem(uid)
|
||||
} else {
|
||||
MediaSessionUID.ChildItem(parent.uid, uid)
|
||||
}
|
||||
fun Album.toMediaItem(context: Context, vararg sugar: Sugar): MediaItem {
|
||||
val mediaSessionUID = MediaSessionUID.SingleItem(uid)
|
||||
val extras = makeExtras(context, *sugar)
|
||||
val counts = context.getPlural(R.plurals.fmt_song_count, songs.size)
|
||||
val description =
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.oxycblt.auxio.music.service
|
|||
import android.content.Context
|
||||
import android.support.v4.media.MediaBrowserCompat.MediaItem
|
||||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.BuildConfig
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.detail.DetailGenerator
|
||||
import org.oxycblt.auxio.detail.DetailSection
|
||||
|
@ -117,8 +118,6 @@ private constructor(
|
|||
is MediaSessionUID.Tab -> return uid.node.toMediaItem(context)
|
||||
is MediaSessionUID.SingleItem ->
|
||||
musicRepository.find(uid.uid)?.let { musicRepository.find(it.uid) }
|
||||
is MediaSessionUID.ChildItem ->
|
||||
musicRepository.find(uid.childUid)?.let { musicRepository.find(it.uid) }
|
||||
null -> null
|
||||
}
|
||||
?: return null
|
||||
|
@ -128,7 +127,7 @@ private constructor(
|
|||
is Artist -> music.toMediaItem(context)
|
||||
is Genre -> music.toMediaItem(context)
|
||||
is Playlist -> music.toMediaItem(context)
|
||||
is Song -> music.toMediaItem(context, null)
|
||||
is Song -> music.toMediaItem(context)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,10 +159,10 @@ private constructor(
|
|||
private fun SearchEngine.Items.toMediaItems(): MutableList<MediaItem> {
|
||||
val music = mutableListOf<MediaItem>()
|
||||
if (songs != null) {
|
||||
music.addAll(songs.map { it.toMediaItem(context, null, header(R.string.lbl_songs)) })
|
||||
music.addAll(songs.map { it.toMediaItem(context, header(R.string.lbl_songs)) })
|
||||
}
|
||||
if (albums != null) {
|
||||
music.addAll(albums.map { it.toMediaItem(context, null, header(R.string.lbl_albums)) })
|
||||
music.addAll(albums.map { it.toMediaItem(context, header(R.string.lbl_albums)) })
|
||||
}
|
||||
if (artists != null) {
|
||||
music.addAll(artists.map { it.toMediaItem(context, header(R.string.lbl_artists)) })
|
||||
|
@ -185,9 +184,6 @@ private constructor(
|
|||
is MediaSessionUID.SingleItem -> {
|
||||
getChildMediaItems(mediaSessionUID.uid)
|
||||
}
|
||||
is MediaSessionUID.ChildItem -> {
|
||||
getChildMediaItems(mediaSessionUID.childUid)
|
||||
}
|
||||
null -> {
|
||||
return null
|
||||
}
|
||||
|
@ -208,11 +204,11 @@ private constructor(
|
|||
}
|
||||
is TabNode.More -> {
|
||||
val tabs = homeGenerator.tabs()
|
||||
tabs.takeLast(tabs.size - maxTabs).map { TabNode.Home(it).toMediaItem(context) }
|
||||
tabs.takeLast(tabs.size - maxTabs + 1).map { TabNode.Home(it).toMediaItem(context) }
|
||||
}
|
||||
is TabNode.Home ->
|
||||
when (node.type) {
|
||||
MusicType.SONGS -> homeGenerator.songs().map { it.toMediaItem(context, null) }
|
||||
MusicType.SONGS -> homeGenerator.songs().map { it.toMediaItem(context) }
|
||||
MusicType.ALBUMS -> homeGenerator.albums().map { it.toMediaItem(context) }
|
||||
MusicType.ARTISTS -> homeGenerator.artists().map { it.toMediaItem(context) }
|
||||
MusicType.GENRES -> homeGenerator.genres().map { it.toMediaItem(context) }
|
||||
|
@ -225,18 +221,24 @@ private constructor(
|
|||
return detail.sections.flatMap { section ->
|
||||
when (section) {
|
||||
is DetailSection.Songs ->
|
||||
section.items.map { it.toMediaItem(context, null, header(section.stringRes)) }
|
||||
section.items.map {
|
||||
it.toMediaItem(context, header(section.stringRes), child(detail.parent))
|
||||
}
|
||||
is DetailSection.Albums ->
|
||||
section.items.map { it.toMediaItem(context, null, header(section.stringRes)) }
|
||||
section.items.map { it.toMediaItem(context, header(section.stringRes)) }
|
||||
is DetailSection.Artists ->
|
||||
section.items.map { it.toMediaItem(context, header(section.stringRes)) }
|
||||
is DetailSection.Discs ->
|
||||
section.discs.flatMap { (disc, songs) ->
|
||||
val discString = disc.resolveNumber(context)
|
||||
songs.map { it.toMediaItem(context, null, header(discString)) }
|
||||
songs.map { it.toMediaItem(context, header(discString)) }
|
||||
}
|
||||
else -> error("Unknown section type: $section")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY_CHILD_OF = BuildConfig.APPLICATION_ID + ".key.CHILD_OF"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -295,7 +295,7 @@ private constructor(
|
|||
queue.mapIndexed { i, song ->
|
||||
val description =
|
||||
song.toMediaDescription(
|
||||
context, null, { putInt(MediaSessionInterface.KEY_QUEUE_POS, i) })
|
||||
context, { putInt(MediaSessionInterface.KEY_QUEUE_POS, i) })
|
||||
// Store the item index so we can then use the analogous index in the
|
||||
// playback state.
|
||||
MediaSessionCompat.QueueItem(description, i.toLong())
|
||||
|
|
|
@ -41,11 +41,13 @@ import org.oxycblt.auxio.music.Song
|
|||
import org.oxycblt.auxio.music.device.DeviceLibrary
|
||||
import org.oxycblt.auxio.music.info.Name
|
||||
import org.oxycblt.auxio.music.service.MediaSessionUID
|
||||
import org.oxycblt.auxio.music.service.MusicBrowser
|
||||
import org.oxycblt.auxio.music.user.UserLibrary
|
||||
import org.oxycblt.auxio.playback.state.PlaybackCommand
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.playback.state.RepeatMode
|
||||
import org.oxycblt.auxio.playback.state.ShuffleMode
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
class MediaSessionInterface
|
||||
@Inject
|
||||
|
@ -80,7 +82,10 @@ constructor(
|
|||
override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) {
|
||||
super.onPlayFromMediaId(mediaId, extras)
|
||||
val uid = MediaSessionUID.fromString(mediaId ?: return) ?: return
|
||||
val command = expandUidIntoCommand(uid)
|
||||
val parentUid =
|
||||
extras?.getString(MusicBrowser.KEY_CHILD_OF)?.let { MediaSessionUID.fromString(it) }
|
||||
val command = expandUidIntoCommand(uid, parentUid)
|
||||
logD(extras?.getString(MusicBrowser.KEY_CHILD_OF))
|
||||
playbackManager.play(requireNotNull(command) { "Invalid playback configuration" })
|
||||
}
|
||||
|
||||
|
@ -105,7 +110,6 @@ constructor(
|
|||
val songUid =
|
||||
when (uid) {
|
||||
is MediaSessionUID.SingleItem -> uid.uid
|
||||
is MediaSessionUID.ChildItem -> uid.childUid
|
||||
else -> return
|
||||
}
|
||||
val song = deviceLibrary.songs.find { it.uid == songUid } ?: return
|
||||
|
@ -126,7 +130,6 @@ constructor(
|
|||
val songUid =
|
||||
when (uid) {
|
||||
is MediaSessionUID.SingleItem -> uid.uid
|
||||
is MediaSessionUID.ChildItem -> uid.childUid
|
||||
else -> return
|
||||
}
|
||||
val firstAt = playbackManager.queue.indexOfFirst { it.uid == songUid }
|
||||
|
@ -194,20 +197,14 @@ constructor(
|
|||
context.sendBroadcast(Intent(action))
|
||||
}
|
||||
|
||||
private fun expandUidIntoCommand(uid: MediaSessionUID): PlaybackCommand? {
|
||||
val music: Music
|
||||
var parent: MusicParent? = null
|
||||
when (uid) {
|
||||
is MediaSessionUID.SingleItem -> {
|
||||
music = musicRepository.find(uid.uid) ?: return null
|
||||
}
|
||||
is MediaSessionUID.ChildItem -> {
|
||||
music = musicRepository.find(uid.childUid) ?: return null
|
||||
parent = musicRepository.find(uid.parentUid) as? MusicParent ?: return null
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
private fun expandUidIntoCommand(
|
||||
uid: MediaSessionUID,
|
||||
parentUid: MediaSessionUID?
|
||||
): PlaybackCommand? {
|
||||
val unwrappedUid = (uid as? MediaSessionUID.SingleItem)?.uid ?: return null
|
||||
val unwrappedParentUid = (parentUid as? MediaSessionUID.SingleItem)?.uid
|
||||
val music = musicRepository.find(unwrappedUid) ?: return null
|
||||
val parent = unwrappedParentUid?.let { musicRepository.find(it) as? MusicParent }
|
||||
return expandMusicIntoCommand(music, parent)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue