Skip to content

55th MAD RSC

THE PREPARE NOTE

class App : Application() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate() {
super.onCreate()
createChannel()
updateWidget()
startForegroundService(Intent(this, PlaybackService::class.java))
}
private fun updateWidget() {
val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
appScope.launch {
Widget().updateAll(applicationContext)
}
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createChannel() {
val channel = NotificationChannel(
"media_channel",
"Media Channel",
NotificationManager.IMPORTANCE_LOW
)
NotificationManagerCompat.from(this).createNotificationChannel(channel) }
}
<service
android:name=".PlaybackService"
android:exported="true"
android:foregroundServiceType="mediaPlayback">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
</intent-filter>
</service>
data class PlayerState(
var currentPosition: Long = 0L,
var duration: Long = 1000L,
var isPlaying: Boolean = false,
var volume: Float = 1.0f,
var currentIndex: Int = 0,
var repeatMode: Int = Player.REPEAT_MODE_OFF,
var metadata: MediaMetadata = MediaMetadata.Builder().build(),
var isStarted: Boolean = false,
)
class PlaybackService : MediaSessionService() {
private var isForegroundStarted = false
private var mediaSession: MediaSession? = null
private lateinit var player: ExoPlayer
private val serviceScope = CoroutineScope(Dispatchers.Main + Job())
private var controllerJob: Job? = null
companion object {
private val _playerState = MutableStateFlow(PlayerState())
val playerState: StateFlow<PlayerState> = _playerState
var playerInstance: ExoPlayer? = null
fun init(items: List<MediaItem>) {
playerInstance?.apply {
setMediaItems(items)
prepare()
play()
}
}
}
override fun onCreate() {
super.onCreate()
player = ExoPlayer.Builder(this).build()
playerInstance = player
player.addListener(object : Player.Listener {
override fun onEvents(player: Player, events: Player.Events) {
_playerState.value = _playerState.value.copy(
currentIndex = player.currentMediaItemIndex,
isPlaying = player.isPlaying,
duration = player.duration,
volume = player.volume,
repeatMode = player.repeatMode,
metadata = player.mediaMetadata
)
serviceScope.launch {
Widget().updateAll(applicationContext)
}
super.onEvents(player, events)
}
})
mediaSession = MediaSession.Builder(this, player).build()
startControllerConnection()
}
private fun startControllerConnection() {
controllerJob?.cancel()
controllerJob = CoroutineScope(Dispatchers.Main).launch {
val sessionToken = SessionToken(
this@PlaybackService,
ComponentName(this@PlaybackService, PlaybackService::class.java)
)
MediaController.Builder(this@PlaybackService, sessionToken).buildAsync()
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
if (!isForegroundStarted) {
val notification = createNotification()
startForeground(1, notification)
isForegroundStarted = true
}
return START_STICKY
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
return mediaSession
}
override fun onDestroy() {
mediaSession?.run {
player.release()
release()
}
playerInstance = null
super.onDestroy()
}
private fun createNotification(): Notification {
return NotificationCompat.Builder(this, "media_channel")
.setSmallIcon(android.R.drawable.ic_media_play)
.setContentTitle("title")
.setContentText("text")
.setOngoing(true)
.build()
}
}

for press the notification to open the app

mediaSession = MediaSession.Builder(this, player)
.setSessionActivity(pendingIntent)
.build()