Skip to content

Commit

Permalink
service: bundle parent info into extras
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
OxygenCobalt committed Sep 30, 2024
1 parent df48039 commit aa4436d
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 74 deletions.
2 changes: 2 additions & 0 deletions app/src/main/java/org/oxycblt/auxio/AuxioService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 :
Expand Down Expand Up @@ -149,6 +150,7 @@ class AuxioService :
}

override fun invalidateMusic(mediaId: String) {
logD(mediaId)
notifyChildrenChanged(mediaId)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>) :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
}
}
Expand All @@ -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)
}
Expand All @@ -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())
Expand All @@ -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 =
Expand Down
28 changes: 15 additions & 13 deletions app/src/main/java/org/oxycblt/auxio/music/service/MusicBrowser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
}
}

Expand Down Expand Up @@ -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)) })
Expand All @@ -185,9 +184,6 @@ private constructor(
is MediaSessionUID.SingleItem -> {
getChildMediaItems(mediaSessionUID.uid)
}
is MediaSessionUID.ChildItem -> {
getChildMediaItems(mediaSessionUID.childUid)
}
null -> {
return null
}
Expand All @@ -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) }
Expand All @@ -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"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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" })
}

Expand All @@ -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
Expand All @@ -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 }
Expand Down Expand Up @@ -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)
}

Expand Down

0 comments on commit aa4436d

Please sign in to comment.