[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