[Android] Workaround for IllegalStateException on Pie

Geoffrey Métais git at videolan.org
Mon Nov 25 13:14:08 CET 2019


vlc-android | branch: 3.2.x | Geoffrey Métais <geoffrey at videolan.org> | Mon Nov 25 11:52:15 2019 +0100| [a9bbfbdaae198317692ad3d3eea066503f15a139] | committer: Nicolas Pomepuy

Workaround for IllegalStateException on Pie

Android 9 has a bug, sometimes, service cannot be started as soon as app
is:
https://issuetracker.google.com/issues/113122354

This fix creates a suspend function which will wait for the app to go
foreground, and use it to launch the service only when we can

(cherry picked from commit 3d7f70e694abecab048b6a393bcff529374eb945)

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

 .../java/org/videolan/tools/KotlinExtensions.kt    | 25 ++++++++++++++++++++++
 .../src/org/videolan/vlc/RendererDelegate.kt       | 10 ++++++---
 vlc-android/src/org/videolan/vlc/StartActivity.kt  | 21 ++++++++++++------
 .../providers/medialibrary/MedialibraryProvider.kt |  6 +++++-
 .../src/org/videolan/vlc/util/Kextensions.kt       | 12 -----------
 5 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/tools/src/main/java/org/videolan/tools/KotlinExtensions.kt b/tools/src/main/java/org/videolan/tools/KotlinExtensions.kt
index 92a44f2c8..29e726cfd 100644
--- a/tools/src/main/java/org/videolan/tools/KotlinExtensions.kt
+++ b/tools/src/main/java/org/videolan/tools/KotlinExtensions.kt
@@ -1,5 +1,7 @@
 package org.videolan.tools
 
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningAppProcessInfo
 import android.content.ClipData
 import android.content.ClipboardManager
 import android.content.Context
@@ -78,3 +80,26 @@ fun Context.copy(label: String, text: String) {
     val clipboard = applicationContext.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
     clipboard.primaryClip = ClipData.newPlainText(label, text)
 }
+
+suspend fun retry(
+        times: Int = 3,
+        delayTime: Long = 500L,
+        block: suspend () -> Boolean): Boolean {
+    repeat(times - 1) {
+        if (block()) return true
+        if (delayTime > 0L) delay(delayTime)
+    }
+    return block() // last attempt
+}
+
+suspend fun Context.awaitAppIsForegroung(): Boolean {
+    val activityManager = applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
+            ?: return false
+    repeat(times = 2) {
+        if (activityManager.isAppForeground()) return true
+        else yield() //dispatch next try
+    }
+    return activityManager.isAppForeground()
+}
+
+private fun ActivityManager.isAppForeground() = runningAppProcesses[0].importance <= RunningAppProcessInfo.IMPORTANCE_FOREGROUND
\ No newline at end of file
diff --git a/vlc-android/src/org/videolan/vlc/RendererDelegate.kt b/vlc-android/src/org/videolan/vlc/RendererDelegate.kt
index 11dd9d60b..945979f2b 100644
--- a/vlc-android/src/org/videolan/vlc/RendererDelegate.kt
+++ b/vlc-android/src/org/videolan/vlc/RendererDelegate.kt
@@ -22,7 +22,11 @@ package org.videolan.vlc
 import kotlinx.coroutines.*
 import org.videolan.libvlc.RendererDiscoverer
 import org.videolan.libvlc.RendererItem
-import org.videolan.vlc.util.*
+import org.videolan.tools.retry
+import org.videolan.vlc.util.AppScope
+import org.videolan.vlc.util.LiveDataset
+import org.videolan.vlc.util.VLCInstance
+import org.videolan.vlc.util.isAppStarted
 import java.util.*
 
 @ObsoleteCoroutinesApi
@@ -41,9 +45,9 @@ object RendererDelegate : RendererDiscoverer.EventListener {
 
     suspend fun start() {
         if (started) return
-        val libVlc = VLCApplication.appContext?.let {
+        val libVlc = VLCApplication.appContext.let {
             withContext(Dispatchers.IO) { VLCInstance.get(it) }
-        } ?: return
+        }
         started = true
         for (discoverer in RendererDiscoverer.list(libVlc)) {
             val rd = RendererDiscoverer(libVlc, discoverer.name)
diff --git a/vlc-android/src/org/videolan/vlc/StartActivity.kt b/vlc-android/src/org/videolan/vlc/StartActivity.kt
index 2129e6941..72e5e90f8 100644
--- a/vlc-android/src/org/videolan/vlc/StartActivity.kt
+++ b/vlc-android/src/org/videolan/vlc/StartActivity.kt
@@ -26,16 +26,17 @@ package org.videolan.vlc
 import android.content.Context
 import android.content.Intent
 import android.net.Uri
+import android.os.Build
 import android.os.Bundle
 import android.provider.MediaStore
 import android.text.TextUtils
 import android.util.Log
 import androidx.core.content.ContextCompat
 import androidx.fragment.app.FragmentActivity
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.ObsoleteCoroutinesApi
+import kotlinx.coroutines.*
 import org.videolan.libvlc.util.AndroidUtil
 import org.videolan.medialibrary.MLServiceLocator
+import org.videolan.tools.awaitAppIsForegroung
 import org.videolan.vlc.gui.BetaWelcomeActivity
 import org.videolan.vlc.gui.MainActivity
 import org.videolan.vlc.gui.SearchActivity
@@ -54,7 +55,7 @@ private const val SEND_CRASH_RESULT = 0
 private const val TAG = "VLC/StartActivity"
 @ExperimentalCoroutinesApi
 @ObsoleteCoroutinesApi
-class StartActivity : FragmentActivity() {
+class StartActivity : FragmentActivity(), CoroutineScope by MainScope() {
 
     private val idFromShortcut: Int
         get() {
@@ -195,15 +196,21 @@ class StartActivity : FragmentActivity() {
         }
     }
 
-    private fun startPlaybackFromApp(intent: Intent) {
+    private fun startPlaybackFromApp(intent: Intent) = launch(start = CoroutineStart.UNDISPATCHED) {
+        // workaround for a Android 9 bug
+        // https://issuetracker.google.com/issues/113122354
+        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P && !awaitAppIsForegroung()) {
+            finish()
+            return at launch
+        }
         if (intent.type?.startsWith("video") == true) {
             try {
-                startActivity(intent.setClass(this, VideoPlayerActivity::class.java))
+                startActivity(intent.setClass(this at StartActivity, VideoPlayerActivity::class.java))
             } catch (ex: SecurityException) {
-                intent.data.let { MediaUtils.openMediaNoUi(it) }
+                intent.data?.let { MediaUtils.openMediaNoUi(it) }
             }
         } else
-            intent.data.let { MediaUtils.openMediaNoUi(it) }
+            intent.data?.let { MediaUtils.openMediaNoUi(it) }
         finish()
     }
 
diff --git a/vlc-android/src/org/videolan/vlc/providers/medialibrary/MedialibraryProvider.kt b/vlc-android/src/org/videolan/vlc/providers/medialibrary/MedialibraryProvider.kt
index ac265255a..21eecbbdd 100644
--- a/vlc-android/src/org/videolan/vlc/providers/medialibrary/MedialibraryProvider.kt
+++ b/vlc-android/src/org/videolan/vlc/providers/medialibrary/MedialibraryProvider.kt
@@ -31,8 +31,12 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.launch
 import org.videolan.medialibrary.interfaces.AbstractMedialibrary
 import org.videolan.medialibrary.media.MediaLibraryItem
+import org.videolan.tools.retry
 import org.videolan.vlc.providers.HeaderProvider
-import org.videolan.vlc.util.*
+import org.videolan.vlc.util.MEDIALIBRARY_PAGE_SIZE
+import org.videolan.vlc.util.ModelsHelper
+import org.videolan.vlc.util.Settings
+import org.videolan.vlc.util.SortModule
 import org.videolan.vlc.viewmodels.SortableModel
 
 abstract class MedialibraryProvider<T : MediaLibraryItem>(val context: Context, val scope: SortableModel) : HeaderProvider(),
diff --git a/vlc-android/src/org/videolan/vlc/util/Kextensions.kt b/vlc-android/src/org/videolan/vlc/util/Kextensions.kt
index 001336560..6512ecba4 100644
--- a/vlc-android/src/org/videolan/vlc/util/Kextensions.kt
+++ b/vlc-android/src/org/videolan/vlc/util/Kextensions.kt
@@ -60,18 +60,6 @@ inline fun <reified T : ViewModel> Fragment.getModelWithActivity() = ViewModelPr
 inline fun <reified T : ViewModel> Fragment.getModel() = ViewModelProviders.of(this).get(T::class.java)
 inline fun <reified T : ViewModel> FragmentActivity.getModel() = ViewModelProviders.of(this).get(T::class.java)
 
-suspend fun retry (
-        times: Int = 3,
-        delayTime: Long = 500L,
-        block: suspend () -> Boolean): Boolean
-{
-    repeat(times - 1) {
-        if (block()) return true
-        delay(delayTime)
-    }
-    return block() // last attempt
-}
-
 fun Media?.canExpand() = this != null && (type == Media.Type.Directory || type == Media.Type.Playlist)
 fun AbstractMediaWrapper?.isMedia() = this != null && (type == AbstractMediaWrapper.TYPE_AUDIO || type == AbstractMediaWrapper.TYPE_VIDEO)
 fun AbstractMediaWrapper?.isBrowserMedia() = this != null && (isMedia() || type == AbstractMediaWrapper.TYPE_DIR || type == AbstractMediaWrapper.TYPE_PLAYLIST)



More information about the Android mailing list