service: handle non-native start

Restore the state by default when another app starts the service.

A simple first step to ensure service independence (no clue if it's
enough)
This commit is contained in:
Alexander Capehart 2024-04-12 13:57:11 -06:00
parent 800ebfe77e
commit 3a4ddb43b9
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 47 additions and 9 deletions

View file

@ -20,6 +20,7 @@ package org.oxycblt.auxio
import android.annotation.SuppressLint
import android.content.Intent
import android.os.IBinder
import androidx.core.app.ServiceCompat
import androidx.media3.session.MediaLibraryService
import androidx.media3.session.MediaSession
@ -41,6 +42,27 @@ class AuxioService : MediaLibraryService(), ForegroundListener {
indexingFragment.attach(this)
}
override fun onBind(intent: Intent?): IBinder? {
handleIntent(intent)
return super.onBind(intent)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// TODO: Start command occurring from a foreign service basically implies a detached
// service, we might need more handling here.
handleIntent(intent)
return super.onStartCommand(intent, flags, startId)
}
private fun handleIntent(intent: Intent?) {
val nativeStart = intent?.getBooleanExtra(INTENT_KEY_NATIVE_START, false) ?: false
if (!nativeStart) {
// Some foreign code started us, no guarantees about foreground stability. Figure
// out what to do.
mediaSessionFragment.handleNonNativeStart()
}
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
mediaSessionFragment.handleTaskRemoved()
@ -78,6 +100,11 @@ class AuxioService : MediaLibraryService(), ForegroundListener {
}
}
}
companion object {
// This is only meant for Auxio to internally ensure that it's state management will work.
const val INTENT_KEY_NATIVE_START = BuildConfig.APPLICATION_ID + ".service.NATIVE_START"
}
}
interface ForegroundListener {

View file

@ -69,7 +69,9 @@ class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
startService(Intent(this, AuxioService::class.java))
startService(
Intent(this, AuxioService::class.java)
.putExtra(AuxioService.INTENT_KEY_NATIVE_START, true))
if (!startIntentAction(intent)) {
// No intent action to do, just restore the previously saved state.

View file

@ -50,7 +50,9 @@ import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.image.service.MediaSessionBitmapLoader
import org.oxycblt.auxio.music.service.MediaItemBrowser
import org.oxycblt.auxio.playback.state.DeferredPlayback
import org.oxycblt.auxio.playback.state.PlaybackStateManager
import org.oxycblt.auxio.util.logD
class MediaSessionServiceFragment
@Inject
@ -103,14 +105,11 @@ constructor(
}
}
fun release() {
waitJob.cancel()
mediaSession.release()
actionHandler.release()
exoHolder.release()
playbackManager.removeListener(this)
mediaSession.release()
foregroundListener = null
fun handleNonNativeStart() {
// At minimum we want to ensure an active playback state.
// TODO: Possibly also force to go foreground?
logD("Handling non-native start.")
playbackManager.playDeferred(DeferredPlayback.RestoreState)
}
fun hasNotification(): Boolean = exoHolder.sessionOngoing
@ -124,6 +123,16 @@ constructor(
post(wrapMediaNotification(notification))
}
fun release() {
waitJob.cancel()
mediaSession.release()
actionHandler.release()
exoHolder.release()
playbackManager.removeListener(this)
mediaSession.release()
foregroundListener = null
}
private fun wrapMediaNotification(notification: MediaNotification): MediaNotification {
// Pulled from MediaNotificationManager: Need to specify MediaSession token manually
// in notification