playback: use custom service lifecycle

This commit is contained in:
Alexander Capehart 2024-04-08 21:15:04 -06:00
parent 481c647342
commit 08e00c7fb1
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47

View file

@ -18,6 +18,7 @@
package org.oxycblt.auxio.service package org.oxycblt.auxio.service
import android.app.Notification
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -56,6 +57,7 @@ import androidx.media3.session.DefaultMediaNotificationProvider
import androidx.media3.session.LibraryResult import androidx.media3.session.LibraryResult
import androidx.media3.session.MediaLibraryService import androidx.media3.session.MediaLibraryService
import androidx.media3.session.MediaLibraryService.MediaLibrarySession import androidx.media3.session.MediaLibraryService.MediaLibrarySession
import androidx.media3.session.MediaNotification
import androidx.media3.session.MediaSession import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSession.ConnectionResult import androidx.media3.session.MediaSession.ConnectionResult
import androidx.media3.session.SessionCommand import androidx.media3.session.SessionCommand
@ -145,7 +147,7 @@ class AuxioService :
private val restoreScope = CoroutineScope(serviceJob + Dispatchers.IO) private val restoreScope = CoroutineScope(serviceJob + Dispatchers.IO)
private val saveScope = CoroutineScope(serviceJob + Dispatchers.IO) private val saveScope = CoroutineScope(serviceJob + Dispatchers.IO)
private var currentSaveJob: Job? = null private var currentSaveJob: Job? = null
private var sessionExposed = false private var hasPlayed = false
private var openAudioEffectSession = false private var openAudioEffectSession = false
@Inject lateinit var listSettings: ListSettings @Inject lateinit var listSettings: ListSettings
@ -195,8 +197,6 @@ class AuxioService :
.also { it.addListener(this) } .also { it.addListener(this) }
player = NeoPlayer(this, exoPlayer, musicRepository, playbackSettings) player = NeoPlayer(this, exoPlayer, musicRepository, playbackSettings)
mediaSession =
MediaLibrarySession.Builder(this, player, this).setBitmapLoader(bitmapLoader).build()
setMediaNotificationProvider( setMediaNotificationProvider(
DefaultMediaNotificationProvider.Builder(this) DefaultMediaNotificationProvider.Builder(this)
.setNotificationId(IntegerTable.PLAYBACK_NOTIFICATION_CODE) .setNotificationId(IntegerTable.PLAYBACK_NOTIFICATION_CODE)
@ -204,6 +204,9 @@ class AuxioService :
.setChannelName(R.string.lbl_playback) .setChannelName(R.string.lbl_playback)
.build() .build()
.also { it.setSmallIcon(R.drawable.ic_auxio_24) }) .also { it.setSmallIcon(R.drawable.ic_auxio_24) })
mediaSession =
MediaLibrarySession.Builder(this, player, this).setBitmapLoader(bitmapLoader).build()
addSession(mediaSession)
updateCustomButtons() updateCustomButtons()
val intentFilter = val intentFilter =
@ -273,9 +276,7 @@ class AuxioService :
openAudioEffectSession = false openAudioEffectSession = false
} }
if (sessionExposed) { removeSession(mediaSession)
removeSession(mediaSession)
}
mediaSession.release() mediaSession.release()
player.release() player.release()
} }
@ -593,12 +594,9 @@ class AuxioService :
super.onPlayWhenReadyChanged(playWhenReady, reason) super.onPlayWhenReadyChanged(playWhenReady, reason)
if (player.playWhenReady) { if (player.playWhenReady) {
if (!sessionExposed) {
addSession(mediaSession)
}
// Mark that we have started playing so that the notification can now be posted. // Mark that we have started playing so that the notification can now be posted.
sessionExposed = true
logD("Player has started playing") logD("Player has started playing")
hasPlayed = true
if (!openAudioEffectSession) { if (!openAudioEffectSession) {
// Convention to start an audioeffect session on play/pause rather than // Convention to start an audioeffect session on play/pause rather than
// start/stop // start/stop
@ -689,8 +687,24 @@ class AuxioService :
mediaSession mediaSession
override fun onUpdateNotification(session: MediaSession, startInForegroundRequired: Boolean) { override fun onUpdateNotification(session: MediaSession, startInForegroundRequired: Boolean) {
super.onUpdateNotification(session, startInForegroundRequired) if (hasPlayed) {
onIndexingStateChanged() logD(hasPlayed)
val notification =
mediaNotificationProvider.createNotification(
session, session.customLayout, mediaNotificationManager.actionFactory) {
notification ->
postNotification(notification, session)
}
postNotification(notification, session)
}
}
private fun postNotification(notification: MediaNotification, session: MediaSession) {
// Pulled from MediaNotificationManager: Need to specify MediaSession token manually
// in notification
val fwkToken = session.sessionCompatToken.token as android.media.session.MediaSession.Token
notification.notification.extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, fwkToken)
startForeground(notification.notificationId, notification.notification)
} }
override fun onConnect( override fun onConnect(
@ -894,13 +908,12 @@ class AuxioService :
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
// User could feasibly start playing again if they were fast enough, so // User could feasibly start playing again if they were fast enough, so
// we need to avoid stopping the foreground state if that's the case. // we need to avoid stopping the foreground state if that's the case.
if (!player.isPlaying) { if (player.isPlaying) {
playbackManager.playing(false) playbackManager.playing(false)
} }
if (sessionExposed) { hasPlayed = false
removeSession(mediaSession) ServiceCompat.stopForeground(
sessionExposed = false this@AuxioService, ServiceCompat.STOP_FOREGROUND_REMOVE)
}
} }
} }
} }