I need to modify the title shown in the media notification based on the current playback position. According to the documentation, I can use MediaNotification.Provider
however the document also says this
Note: Starting with API 33 the System UI notification is populated from the data in the session.
Accordingly, customizations of the MediaNotification.Provider have effect before API 33 only.
For 33 and above, I can update metadata but cannot call setMediaItem
on the player again as that will disturb the current playback session (plays from the beginning).
Question 1: Using media3 default notification, how do I update title on the fly?
If my only option is build custom notification,
Question 2: How to disable default mediastyle notification? (currently I see two notifications)
Question 3: How to create my own layout and show / update data on that?
Here is the service:
class PlaybackService : MediaSessionService() {
private var mediaSession: MediaSession? = null
private lateinit var playerNotificationManager: PlayerNotificationManager
private lateinit var notificationManager: NotificationManagerCompat
override fun onCreate() {
super.onCreate()
val player = ExoPlayer.Builder(this)
.setMediaSourceFactory(...)
.build()
.apply {
addListener(object : Player.Listener {
...
})
playWhenReady = true
}
mediaSession = MediaSession.Builder(this, player)
.build()
notificationManager = NotificationManagerCompat.from(this)
createChannel()
playerNotificationManager = PlayerNotificationManager.Builder(this, NOTIFICATION_ID, NOTIFICATION_CHANNEL)
.setNotificationListener(object : PlayerNotificationManager.NotificationListener {
override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) {
// Handle notification being dismissed by the user
}
override fun onNotificationPosted(notificationId: Int, notification: Notification, ongoing: Boolean) {
// Handle notification being posted
startForeground(notificationId, notification)
}
})
.setMediaDescriptionAdapter(object : PlayerNotificationManager.MediaDescriptionAdapter {
override fun getCurrentContentTitle(player: Player): CharSequence {
return "My Title"
}
override fun createCurrentContentIntent(player: Player): PendingIntent? {
return null
}
override fun getCurrentContentText(player: Player): CharSequence {
return "My Description"
}
override fun getCurrentLargeIcon(player: Player, callback: PlayerNotificationManager.BitmapCallback): Bitmap? {
return null
}
})
.build()
playerNotificationManager.setPlayer(player)
///playerNotificationManager.setMediaSessionToken(mediaSession.token) <-- not sure if session token needs to be set
}
override fun onTaskRemoved(rootIntent: Intent?) {
mediaSession?.player?.stop()
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
super.onTaskRemoved(rootIntent)
}
override fun onDestroy() {
mediaSession?.run {
player.release()
release()
mediaSession = null
}
super.onDestroy()
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
return mediaSession
}
@TargetApi(Build.VERSION_CODES.O)
private fun createChannel() {
val channel = NotificationChannel(
NOTIFICATION_CHANNEL,
this.getString(R.string.playback_notification_channel),
NotificationManager.IMPORTANCE_LOW)
channel.enableLights(false)
channel.enableVibration(false)
channel.setShowBadge(false)
channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
notificationManager.createNotificationChannel(channel)
}
companion object {
private const val NOTIFICATION_CHANNEL = "player_channel"
private const val NOTIFICATION_ID = 100
}
}
Instead of creating PlayerNotificationManager, all we need to do is to override this method in MediaNotification.Provider
fun getNotificationContentText(MediaMetadata metadata): CharSequence
Once the above object is created, from MediaSessionService, need to call
setMediaNotificationProvider(provider)