fix: post placeholder foreground notification immediately on play

startForegroundService() requires startForeground() within ~5 seconds.
The async coroutine (DB queries, old job join) delayed the Media3
notification pipeline past this deadline. Now we:
- Create the media session in onCreate() instead of lazily
- Post a minimal "Connecting…" notification synchronously in
  onStartCommand before launching the async play coroutine
- Media3 replaces it with the proper media notification once the
  adapter state updates to Playing

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-18 06:41:24 -04:00
parent f65b0db0f4
commit 5126ad6366

View File

@@ -1,5 +1,7 @@
package xyz.cottongin.radio247.service
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
@@ -10,6 +12,8 @@ import android.net.NetworkRequest
import android.os.Bundle
import android.os.PowerManager
import android.util.Log
import androidx.core.app.NotificationCompat
import xyz.cottongin.radio247.R
import com.google.common.util.concurrent.SettableFuture
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
@@ -55,6 +59,8 @@ class ConnectionFailedException(cause: Throwable) : Exception("Connection failed
class RadioPlaybackService : MediaLibraryService() {
companion object {
private const val TAG = "RadioPlayback"
private const val FOREGROUND_CHANNEL_ID = "radio_playback"
private const val FOREGROUND_NOTIFICATION_ID = 1
const val ACTION_PLAY = "xyz.cottongin.radio247.PLAY"
const val ACTION_STOP = "xyz.cottongin.radio247.STOP"
const val ACTION_PAUSE = "xyz.cottongin.radio247.PAUSE"
@@ -118,6 +124,24 @@ class RadioPlaybackService : MediaLibraryService() {
override fun onCreate() {
super.onCreate()
ensureForegroundChannel()
ensureMediaSession()
}
private fun ensureForegroundChannel() {
val channel = NotificationChannel(
FOREGROUND_CHANNEL_ID, "Radio Playback", NotificationManager.IMPORTANCE_LOW
)
getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
}
private fun postPlaceholderForeground() {
val notification = NotificationCompat.Builder(this, FOREGROUND_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("Connecting…")
.setSilent(true)
.build()
startForeground(FOREGROUND_NOTIFICATION_ID, notification)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@@ -126,6 +150,7 @@ class RadioPlaybackService : MediaLibraryService() {
ACTION_PLAY -> {
val stationId = intent.getLongExtra(EXTRA_STATION_ID, -1L)
if (stationId >= 0) {
postPlaceholderForeground()
launchPlay(stationId)
} else {
stopSelf()
@@ -194,7 +219,6 @@ class RadioPlaybackService : MediaLibraryService() {
}
acquireLocks()
ensureMediaSession()
playerAdapter?.updateStation(station)
playerAdapter?.updatePlaybackState(PlaybackState.Connecting(station))