55package ch.srgssr.pillarbox.demo.ui.player
66
77import android.app.Application
8+ import android.app.PendingIntent
9+ import android.content.Intent
810import android.util.Log
911import android.util.Rational
1012import androidx.lifecycle.AndroidViewModel
13+ import androidx.lifecycle.application
1114import androidx.media3.common.C
1215import androidx.media3.common.MediaMetadata
1316import androidx.media3.common.PlaybackException
1417import androidx.media3.common.PlaybackParameters
1518import androidx.media3.common.Player
1619import androidx.media3.common.Timeline
1720import androidx.media3.common.VideoSize
21+ import androidx.media3.common.util.NotificationUtil
22+ import androidx.media3.session.R
23+ import androidx.media3.ui.PlayerNotificationManager
1824import ch.srgssr.pillarbox.demo.shared.data.DemoItem
1925import ch.srgssr.pillarbox.demo.shared.di.PlayerModule
2026import ch.srgssr.pillarbox.player.PillarboxPlayer
2127import ch.srgssr.pillarbox.player.asset.timeRange.Chapter
2228import ch.srgssr.pillarbox.player.asset.timeRange.Credit
2329import ch.srgssr.pillarbox.player.extension.setHandleAudioFocus
2430import ch.srgssr.pillarbox.player.extension.toRational
31+ import ch.srgssr.pillarbox.player.notification.PillarboxMediaDescriptionAdapter
32+ import ch.srgssr.pillarbox.player.session.PillarboxMediaSession
33+ import ch.srgssr.pillarbox.player.utils.PendingIntentUtils
2534import ch.srgssr.pillarbox.player.utils.StringUtil
2635import kotlinx.coroutines.flow.MutableStateFlow
2736
37+ private const val NotificationId = 2025
38+
2839/* *
29- * Simple player view model than handle a PillarboxPlayer [player]
40+ * Simple player view model that handles a PillarboxPlayer [player].
41+ * Playback notification is displayed when the player is in the foreground.
42+ * When the Activity goes to the background, the playback is stopped and the notification removed.
3043 */
3144class SimplePlayerViewModel (application : Application ) : AndroidViewModel(application), PillarboxPlayer.Listener {
3245 /* *
3346 * Player as PillarboxPlayer
3447 */
3548 val player = PlayerModule .provideDefaultPlayer(application)
3649
50+ private val mediaSession = PillarboxMediaSession .Builder (application, player)
51+ .setSessionActivity(pendingIntent())
52+ .build()
53+ private val notificationManager: PlayerNotificationManager
54+
3755 /* *
3856 * Picture in picture enabled
3957 */
@@ -45,6 +63,12 @@ class SimplePlayerViewModel(application: Application) : AndroidViewModel(applica
4563 var pictureInPictureRatio = MutableStateFlow (Rational (1 , 1 ))
4664
4765 init {
66+ notificationManager = PlayerNotificationManager .Builder (application, NotificationId , " Pillarbox now playing" )
67+ .setChannelImportance(NotificationUtil .IMPORTANCE_LOW )
68+ .setChannelNameResourceId(R .string.default_notification_channel_name)
69+ .setMediaDescriptionAdapter(PillarboxMediaDescriptionAdapter (context = application, pendingIntent = pendingIntent()))
70+ .build()
71+ notificationManager.setUseChronometer(false )
4872 player.addListener(this )
4973 /*
5074 * Seems to have no effect if not use with a foreground service to handle background playback.
@@ -62,6 +86,32 @@ class SimplePlayerViewModel(application: Application) : AndroidViewModel(applica
6286 * Playback will resume depending on the "importance" of the interruption (call, playback)
6387 */
6488 player.setHandleAudioFocus(true )
89+ notificationManager.setMediaSessionToken(mediaSession.token)
90+ }
91+
92+ /* *
93+ * Resume playback.
94+ */
95+ fun resumePlayback () {
96+ displayNotification()
97+ player.prepare()
98+ player.play()
99+ }
100+
101+ /* *
102+ * Stop playback.
103+ */
104+ fun stopPlayback () {
105+ player.stop()
106+ hideNotification()
107+ }
108+
109+ private fun displayNotification () {
110+ notificationManager.setPlayer(player)
111+ }
112+
113+ private fun hideNotification () {
114+ notificationManager.setPlayer(null )
65115 }
66116
67117 /* *
@@ -79,6 +129,8 @@ class SimplePlayerViewModel(application: Application) : AndroidViewModel(applica
79129 override fun onCleared () {
80130 super .onCleared()
81131 Log .d(TAG , " onCleared => releasing the player" )
132+ notificationManager.setPlayer(null )
133+ mediaSession.release()
82134 player.release()
83135 player.removeListener(this )
84136 }
@@ -143,6 +195,17 @@ class SimplePlayerViewModel(application: Application) : AndroidViewModel(applica
143195 Log .i(TAG , " onCreditChanged $credit " )
144196 }
145197
198+ private fun pendingIntent (): PendingIntent {
199+ val intent = Intent (application, SimplePlayerActivity ::class .java)
200+ val flags = PendingIntentUtils .appendImmutableFlagIfNeeded(PendingIntent .FLAG_UPDATE_CURRENT )
201+ return PendingIntent .getActivity(
202+ application,
203+ 0 ,
204+ intent,
205+ flags
206+ )
207+ }
208+
146209 private companion object {
147210 private const val TAG = " PillarboxDemo"
148211 }
0 commit comments