Fix foreground service crash during Ogg duration extraction
Call startForeground() immediately in onStartCommand() with a placeholder notification before returning. This satisfies Android's foreground timeout requirement while the blocking Ogg duration extraction completes. Media3's MediaNotificationManager replaces the placeholder with the real notification once the player starts. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
6808012a53
commit
50a8c69ec6
1 changed files with 37 additions and 0 deletions
|
|
@ -1,12 +1,17 @@
|
|||
package `is`.dsg.placeboplayer.playback.service
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.session.DefaultMediaNotificationProvider
|
||||
import androidx.media3.session.MediaSession
|
||||
import androidx.media3.session.MediaSessionService
|
||||
import `is`.dsg.placeboplayer.MainActivity
|
||||
import `is`.dsg.placeboplayer.R
|
||||
import `is`.dsg.placeboplayer.data.repository.PlaybackRepositoryImpl
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.koin.android.ext.android.inject
|
||||
|
|
@ -62,6 +67,36 @@ class PlaybackMediaSessionService : MediaSessionService() {
|
|||
mediaSession?.let { addSession(it) }
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
// Immediately start foreground to satisfy Android's timeout requirement.
|
||||
// Media3's MediaNotificationManager will replace this with the real notification
|
||||
// once the player is prepared and playing.
|
||||
ensureNotificationChannel()
|
||||
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setSmallIcon(androidx.media3.session.R.drawable.media3_notification_small_icon)
|
||||
.setContentTitle(getString(R.string.app_name))
|
||||
.setSilent(true)
|
||||
.build()
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
private fun ensureNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val manager = getSystemService(NotificationManager::class.java)
|
||||
if (manager.getNotificationChannel(CHANNEL_ID) == null) {
|
||||
val channel = NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
"Playback",
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
)
|
||||
channel.setShowBadge(false)
|
||||
manager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MediaSession for this service.
|
||||
* Called by the system when a media controller connects.
|
||||
|
|
@ -116,5 +151,7 @@ class PlaybackMediaSessionService : MediaSessionService() {
|
|||
companion object {
|
||||
private const val TAG = "MediaSessionService"
|
||||
const val ACTION_SHOW_NOW_PLAYING = "is.dsg.placeboplayer.SHOW_NOW_PLAYING"
|
||||
private const val CHANNEL_ID = "default_channel_id"
|
||||
private const val NOTIFICATION_ID = 1001
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue