@@ -13,8 +13,12 @@ import android.content.BroadcastReceiver
1313import android.content.Context
1414import android.content.Intent
1515import android.content.IntentFilter
16+ import android.content.pm.ServiceInfo
17+ import android.os.Build
1618import android.os.Bundle
1719import androidx.annotation.OptIn
20+ import androidx.core.app.NotificationCompat
21+ import androidx.core.app.ServiceCompat
1822import androidx.media3.common.Player
1923import androidx.media3.common.Player.COMMAND_PLAY_PAUSE
2024import androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT
@@ -45,6 +49,7 @@ import com.owncloud.android.MainApp
4549import com.owncloud.android.R
4650import com.owncloud.android.datamodel.ReceiverFlag
4751import com.owncloud.android.lib.common.utils.Log_OC
52+ import com.owncloud.android.ui.notifications.NotificationUtils
4853import kotlinx.coroutines.CoroutineScope
4954import kotlinx.coroutines.Dispatchers
5055import kotlinx.coroutines.SupervisorJob
@@ -81,6 +86,7 @@ class BackgroundPlayerService :
8186 override fun onReceive (context : Context ? , intent : Intent ? ) {
8287 when (intent?.action) {
8388 RELEASE_MEDIA_SESSION_BROADCAST_ACTION -> release()
89+
8490 STOP_MEDIA_SESSION_BROADCAST_ACTION -> {
8591 if (isPlayerReady) {
8692 exoPlayer.stop()
@@ -92,6 +98,26 @@ class BackgroundPlayerService :
9298 }
9399 }
94100
101+ override fun onStartCommand (intent : Intent ? , flags : Int , startId : Int ): Int {
102+ val notification = NotificationCompat .Builder (this , NotificationUtils .NOTIFICATION_CHANNEL_MEDIA )
103+ .setSmallIcon(R .drawable.logo)
104+ .setContentTitle(getString(R .string.media_player_playing))
105+ .setSilent(true )
106+ .build()
107+
108+ ServiceCompat .startForeground(
109+ this ,
110+ DefaultMediaNotificationProvider .DEFAULT_NOTIFICATION_ID ,
111+ notification,
112+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
113+ ServiceInfo .FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
114+ } else {
115+ 0
116+ }
117+ )
118+ return super .onStartCommand(intent, flags, startId)
119+ }
120+
95121 @Suppress(" DEPRECATION" )
96122 override fun onCreate () {
97123 super .onCreate()
@@ -100,14 +126,14 @@ class BackgroundPlayerService :
100126
101127 seekForward = CommandButton .Builder ()
102128 .setDisplayName(getString(R .string.media_player_seek_forward))
103- .setIconResId(CommandButton .getIconResIdForIconConstant( CommandButton . ICON_SKIP_FORWARD_15 ) )
129+ .setIconResId(R .drawable.ic_skip_next )
104130 .setSessionCommand(seekForwardSessionCommand)
105131 .setExtras(Bundle ().apply { putInt(COMMAND_KEY_COMPACT_VIEW_INDEX , 2 ) })
106132 .build()
107133
108134 seekBackward = CommandButton .Builder ()
109135 .setDisplayName(getString(R .string.media_player_seek_backward))
110- .setIconResId(CommandButton .getIconResIdForIconConstant( CommandButton . ICON_SKIP_BACK_15 ) )
136+ .setIconResId(R .drawable.ic_skip_previous )
111137 .setSessionCommand(seekBackSessionCommand)
112138 .setExtras(Bundle ().apply { putInt(COMMAND_KEY_COMPACT_VIEW_INDEX , 0 ) })
113139 .build()
@@ -129,6 +155,7 @@ class BackgroundPlayerService :
129155 initExoPlayer()
130156 }
131157
158+ @Suppress(" TooGenericExceptionCaught" )
132159 private fun initExoPlayer () {
133160 serviceScope.launch {
134161 try {
@@ -151,15 +178,12 @@ class BackgroundPlayerService :
151178 }
152179 }
153180
154- private fun buildMediaSession (player : ExoPlayer ): MediaSession =
155- MediaSession .Builder (applicationContext, player)
156- .setId(BACKGROUND_MEDIA_SESSION_ID )
157- .setCustomLayout(listOf (seekBackward, seekForward))
158- .setCallback(object : MediaSession .Callback {
159- override fun onConnect (
160- session : MediaSession ,
161- controller : MediaSession .ControllerInfo
162- ): ConnectionResult = AcceptedResultBuilder (mediaSession ? : session)
181+ private fun buildMediaSession (player : ExoPlayer ): MediaSession = MediaSession .Builder (applicationContext, player)
182+ .setId(BACKGROUND_MEDIA_SESSION_ID )
183+ .setCustomLayout(listOf (seekBackward, seekForward))
184+ .setCallback(object : MediaSession .Callback {
185+ override fun onConnect (session : MediaSession , controller : MediaSession .ControllerInfo ): ConnectionResult =
186+ AcceptedResultBuilder (mediaSession ? : session)
163187 .setAvailablePlayerCommands(
164188 ConnectionResult .DEFAULT_PLAYER_COMMANDS .buildUpon()
165189 .remove(COMMAND_SEEK_TO_NEXT )
@@ -176,56 +200,52 @@ class BackgroundPlayerService :
176200 )
177201 .build()
178202
179- override fun onPostConnect (
180- session : MediaSession ,
181- controller : MediaSession .ControllerInfo
182- ) {
183- session.setCustomLayout(listOf (seekBackward, seekForward))
184- }
185-
186- override fun onCustomCommand (
187- session : MediaSession ,
188- controller : MediaSession .ControllerInfo ,
189- customCommand : SessionCommand ,
190- args : Bundle
191- ): ListenableFuture <SessionResult > = when (customCommand.customAction) {
192- SESSION_COMMAND_ACTION_SEEK_FORWARD -> {
193- session.player.seekForward()
194- Futures .immediateFuture(SessionResult (SessionResult .RESULT_SUCCESS ))
195- }
203+ override fun onPostConnect (session : MediaSession , controller : MediaSession .ControllerInfo ) {
204+ session.setCustomLayout(listOf (seekBackward, seekForward))
205+ }
196206
197- SESSION_COMMAND_ACTION_SEEK_BACK -> {
198- session.player.seekBack()
199- Futures .immediateFuture(SessionResult (SessionResult .RESULT_SUCCESS ))
200- }
207+ override fun onCustomCommand (
208+ session : MediaSession ,
209+ controller : MediaSession .ControllerInfo ,
210+ customCommand : SessionCommand ,
211+ args : Bundle
212+ ): ListenableFuture <SessionResult > = when (customCommand.customAction) {
213+ SESSION_COMMAND_ACTION_SEEK_FORWARD -> {
214+ session.player.seekForward()
215+ Futures .immediateFuture(SessionResult (SessionResult .RESULT_SUCCESS ))
216+ }
201217
202- else -> super .onCustomCommand(session, controller, customCommand, args)
218+ SESSION_COMMAND_ACTION_SEEK_BACK -> {
219+ session.player.seekBack()
220+ Futures .immediateFuture(SessionResult (SessionResult .RESULT_SUCCESS ))
203221 }
204- })
205- .build()
206222
207- private fun buildNotificationProvider () = object : DefaultMediaNotificationProvider (this ) {
208- val isPlaying = mediaSession?.player?.isPlaying ? : false
223+ else -> super .onCustomCommand(session, controller, customCommand, args)
224+ }
225+ })
226+ .build()
209227
228+ private fun buildNotificationProvider () = object : DefaultMediaNotificationProvider (this ) {
210229 @Suppress(" DEPRECATION" )
211230 override fun getMediaButtons (
212231 session : MediaSession ,
213232 playerCommands : Player .Commands ,
214233 customLayout : ImmutableList <CommandButton >,
215234 showPauseButton : Boolean
216235 ): ImmutableList <CommandButton > {
217- val playPauseButton =
218- CommandButton .Builder ()
219- .setDisplayName(
220- if (isPlaying) getString(R .string.media_player_pause)
221- else getString(R .string.media_player_play)
222- )
223- .setIconResId(
224- if (isPlaying) R .drawable.ic_pause else R .drawable.ic_play_arrow
225- )
226- .setPlayerCommand(COMMAND_PLAY_PAUSE )
227- .setExtras(Bundle ().apply { putInt(COMMAND_KEY_COMPACT_VIEW_INDEX , 1 ) })
228- .build()
236+ val isPlaying = mediaSession?.player?.isPlaying == true
237+ val playPauseButton = CommandButton .Builder ()
238+ .setDisplayName(
239+ if (isPlaying) {
240+ getString(R .string.media_player_pause)
241+ } else {
242+ getString(R .string.media_player_play)
243+ }
244+ )
245+ .setIconResId(if (isPlaying) R .drawable.ic_pause else R .drawable.ic_play_arrow)
246+ .setPlayerCommand(COMMAND_PLAY_PAUSE )
247+ .setExtras(Bundle ().apply { putInt(COMMAND_KEY_COMPACT_VIEW_INDEX , 1 ) })
248+ .build()
229249
230250 return ImmutableList .of(seekBackward, playPauseButton, seekForward)
231251 }
0 commit comments