[Android] Implement the new scheduler in the playback service

Nicolas Pomepuy git at videolan.org
Tue Jul 25 14:57:29 UTC 2023


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Thu Jul 20 10:34:05 2023 +0200| [a2d167d1df260dcd8a3f45e4146dd1147dba3405] | committer: Duncan McNamara

Implement the new scheduler in the playback service

> https://code.videolan.org/videolan/vlc-android/commit/a2d167d1df260dcd8a3f45e4146dd1147dba3405
---

 .../src/org/videolan/vlc/PlaybackService.kt        | 84 ++++++++++------------
 1 file changed, 36 insertions(+), 48 deletions(-)

diff --git a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
index af4c1c4447..c346cc7d68 100644
--- a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
+++ b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
@@ -19,7 +19,6 @@
 
 package org.videolan.vlc
 
-import android.annotation.SuppressLint
 import android.annotation.TargetApi
 import android.app.*
 import android.appwidget.AppWidgetManager
@@ -89,8 +88,9 @@ import kotlin.math.abs
 
 private const val TAG = "VLC/PlaybackService"
 
-class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineScope {
+class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineScope, SchedulerCallback {
     override val coroutineContext = Dispatchers.IO + SupervisorJob()
+    lateinit var scheduler: LifecycleAwareScheduler
 
     private var position: Long = -1L
     private val dispatcher = ServiceLifecycleDispatcher(this)
@@ -131,6 +131,10 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
     private var lastParentId = ""
     private var widget = 0
 
+    var currentToast: Toast? = null
+    var lastErrorTime = 0L
+    var nbErrors = 0
+
     /**
      * Last widget position update timestamp
      */
@@ -208,7 +212,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
                 audioFocusHelper.changeAudioFocus(true)
                 if (!wakeLock.isHeld) wakeLock.acquire()
                 showNotification()
-                handler.nbErrors = 0
+                nbErrors = 0
             }
             MediaPlayer.Event.Paused -> {
                 if (BuildConfig.DEBUG) Log.i(TAG, "MediaPlayer.Event.Paused")
@@ -245,8 +249,6 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
         cbActor.trySend(CbMediaPlayerEvent(event))
     }
 
-    private val handler = PlaybackServiceHandler(this)
-
     val sessionPendingIntent: PendingIntent
         get() {
             return when {
@@ -604,6 +606,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
 
     @RequiresApi(Build.VERSION_CODES.O)
     override fun onCreate() {
+        scheduler = LifecycleAwareScheduler(this)
         dispatcher.onServicePreSuperOnCreate()
         setupScope()
         forceForeground()
@@ -737,7 +740,6 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
         serviceFlow.value = null
         dispatcher.onServicePreSuperOnDestroy()
         super.onDestroy()
-        handler.removeCallbacksAndMessages(null)
         browserCallback.removeCallbacks()
         if (!settings.getBoolean(AUDIO_RESUME_PLAYBACK, true)) (getSystemService(NOTIFICATION_SERVICE)as NotificationManager).cancel(3)
         if (this::mediaSession.isInitialized) mediaSession.release()
@@ -842,38 +844,6 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
             publishState()
     }
 
-    private class PlaybackServiceHandler(owner: PlaybackService) : WeakHandler<PlaybackService>(owner) {
-
-        var currentToast: Toast? = null
-        var lastErrorTime = 0L
-        var nbErrors = 0
-
-        @SuppressLint("ShowToast")
-        override fun handleMessage(msg: Message) {
-            val service = owner ?: return
-            when (msg.what) {
-                SHOW_TOAST -> {
-                    val bundle = msg.data
-                    var text = bundle.getString("text")
-                    val duration = bundle.getInt("duration")
-                    val isError = bundle.getBoolean("isError")
-                    if (isError) {
-                        when {
-                            nbErrors > 2 && System.currentTimeMillis() - lastErrorTime < 500 -> return
-                            nbErrors >= 2 -> text = service.getString(R.string.playback_multiple_errors)
-                        }
-                        currentToast?.cancel()
-                        nbErrors++
-                        lastErrorTime = System.currentTimeMillis()
-                    }
-                    currentToast = Toast.makeText(AppContextProvider.appContext, text, duration)
-                    currentToast?.show()
-                }
-                END_MEDIASESSION -> if (service::mediaSession.isInitialized) service.mediaSession.isActive = false
-            }
-        }
-    }
-
     fun showNotification(): Boolean {
         notificationShowing = true
         return cbActor.trySend(ShowNotification).isSuccess
@@ -1074,7 +1044,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
 
     private fun publishState(position: Long? = null) {
         if (!this::mediaSession.isInitialized) return
-        if (AndroidDevices.isAndroidTv) handler.removeMessages(END_MEDIASESSION)
+        if (AndroidDevices.isAndroidTv) scheduler.cancelAction(END_MEDIASESSION)
         val pscb = PlaybackStateCompat.Builder()
         var actions = PLAYBACK_BASE_ACTIONS
         val hasMedia = playlistManager.hasCurrentMedia()
@@ -1092,7 +1062,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
                     val progress = if (length <= 0L) 0f else time / length.toFloat()
                     if (progress < 0.95f) {
                         state = PlaybackStateCompat.STATE_PAUSED
-                        handler.sendEmptyMessageDelayed(END_MEDIASESSION, 900_000L)
+                        scheduler.scheduleAction(END_MEDIASESSION, 900_000L)
                     }
                 }
             }
@@ -1291,12 +1261,8 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
     }
 
     fun showToast(text: String, duration: Int, isError: Boolean = false) {
-        val msg = handler.obtainMessage().apply {
-            what = SHOW_TOAST
-            data = bundleOf("text" to text, "duration" to duration, "isError" to isError)
-        }
-        handler.removeMessages(SHOW_TOAST)
-        handler.sendMessage(msg)
+        scheduler.cancelAction(SHOW_TOAST)
+        scheduler.startAction(SHOW_TOAST, bundleOf("text" to text, "duration" to duration, "isError" to isError))
     }
 
     @MainThread
@@ -1692,6 +1658,28 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
     @MainThread
     fun setVideoAspectRatio(aspect: String?) = playlistManager.player.setVideoAspectRatio(aspect)
 
+    override fun onTaskTriggered(id: String, data:Bundle) {
+        when (id) {
+            SHOW_TOAST -> {
+                var text = data.getString("text")
+                val duration = data.getInt("duration")
+                val isError = data.getBoolean("isError")
+                if (isError) {
+                    when {
+                        nbErrors > 2 && System.currentTimeMillis() - lastErrorTime < 500 -> return
+                        nbErrors >= 2 -> text = getString(R.string.playback_multiple_errors)
+                    }
+                    currentToast?.cancel()
+                    nbErrors++
+                    lastErrorTime = System.currentTimeMillis()
+                }
+                currentToast = Toast.makeText(applicationContext, text, duration)
+                currentToast?.show()
+            }
+            END_MEDIASESSION -> if (::mediaSession.isInitialized) mediaSession.isActive = false
+        }
+    }
+
     override fun getLifecycle(): Lifecycle = dispatcher.lifecycle
 
     /*
@@ -1798,8 +1786,8 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc
         val headSetDetection = LiveEvent<Boolean>()
         val equalizer = LiveEvent<MediaPlayer.Equalizer>()
 
-        private const val SHOW_TOAST = 1
-        private const val END_MEDIASESSION = 2
+        private const val SHOW_TOAST = "show_toast"
+        private const val END_MEDIASESSION = "end_mediasession"
 
         val playerSleepTime by lazy(LazyThreadSafetyMode.NONE) { MutableLiveData<Calendar?>().apply { value = null } }
 



More information about the Android mailing list