[Android] Improve headless fragments callback system

Geoffrey Métais git at videolan.org
Tue Aug 7 18:48:33 CEST 2018


vlc-android | branch: master | Geoffrey Métais <geoffrey.metais at gmail.com> | Tue Aug  7 18:48:11 2018 +0200| [eb8586ad11f1529148ddc63b82b0f502a3e6bb9b] | committer: Geoffrey Métais

Improve headless fragments callback system

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

 .../vlc/gui/helpers/hf/BaseHeadlessFragment.kt     | 25 +++++++++++++---------
 .../gui/helpers/hf/StoragePermissionsDelegate.kt   | 12 ++++++++---
 .../vlc/gui/helpers/hf/WriteExternalDelegate.kt    | 19 ++++++++--------
 3 files changed, 34 insertions(+), 22 deletions(-)

diff --git a/vlc-android/src/org/videolan/vlc/gui/helpers/hf/BaseHeadlessFragment.kt b/vlc-android/src/org/videolan/vlc/gui/helpers/hf/BaseHeadlessFragment.kt
index d6c6a07bd..6fe26b9b2 100644
--- a/vlc-android/src/org/videolan/vlc/gui/helpers/hf/BaseHeadlessFragment.kt
+++ b/vlc-android/src/org/videolan/vlc/gui/helpers/hf/BaseHeadlessFragment.kt
@@ -25,12 +25,16 @@ package org.videolan.vlc.gui.helpers.hf
 
 import android.content.Context
 import android.os.Bundle
-import android.os.Handler
 import android.support.v4.app.Fragment
 import android.support.v4.app.FragmentActivity
+import kotlinx.coroutines.experimental.android.UI
+import kotlinx.coroutines.experimental.channels.Channel
+import kotlinx.coroutines.experimental.channels.SendChannel
+import kotlinx.coroutines.experimental.launch
 
 open class BaseHeadlessFragment : Fragment() {
     protected var mActivity: FragmentActivity? = null
+    var channel: SendChannel<Unit>? = null
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -51,17 +55,18 @@ open class BaseHeadlessFragment : Fragment() {
         if (mActivity?.isFinishing == false) mActivity!!.supportFragmentManager.beginTransaction().remove(this).commitAllowingStateLoss()
     }
 
+    fun executePendingAction() {
+        channel?.let { it.offer(Unit) }
+        channel = null
+    }
+
     companion object {
-        internal var callback: Runnable? = null
 
-        internal fun executeCallback() {
-            callback?.let {
-                try {
-                    Handler().postDelayed(it, 500);
-                } catch (ignored: Exception) {
-                } finally {
-                    callback = null
-                }
+        internal fun waitForIt(channel: Channel<Unit>, cb: Runnable) {
+            launch(UI.immediate) {
+                channel.receive()
+                channel.close()
+                cb.run()
             }
         }
     }
diff --git a/vlc-android/src/org/videolan/vlc/gui/helpers/hf/StoragePermissionsDelegate.kt b/vlc-android/src/org/videolan/vlc/gui/helpers/hf/StoragePermissionsDelegate.kt
index 4a3770f64..2c1488a05 100644
--- a/vlc-android/src/org/videolan/vlc/gui/helpers/hf/StoragePermissionsDelegate.kt
+++ b/vlc-android/src/org/videolan/vlc/gui/helpers/hf/StoragePermissionsDelegate.kt
@@ -30,6 +30,7 @@ import android.os.Build
 import android.os.Bundle
 import android.support.v4.app.Fragment
 import android.support.v4.app.FragmentActivity
+import kotlinx.coroutines.experimental.channels.Channel
 import org.videolan.libvlc.util.AndroidUtil
 import org.videolan.vlc.startMedialibrary
 import org.videolan.vlc.util.Constants
@@ -90,7 +91,7 @@ class StoragePermissionsDelegate : BaseHeadlessFragment() {
                         exit()
                 }
             }
-            Permissions.PERMISSION_WRITE_STORAGE_TAG -> executeCallback()
+            Permissions.PERMISSION_WRITE_STORAGE_TAG -> executePendingAction()
         }
     }
 
@@ -102,15 +103,20 @@ class StoragePermissionsDelegate : BaseHeadlessFragment() {
             if (activity.isFinishing) return
             val fm = activity.supportFragmentManager
             var fragment: Fragment? = fm.findFragmentByTag(TAG)
-            callback = cb
+            val channel = if (cb != null) Channel<Unit>(1) else null
             if (fragment == null) {
                 val args = Bundle()
                 args.putBoolean("write", write)
                 fragment = StoragePermissionsDelegate()
                 fragment.arguments = args
+                channel?.let { fragment.channel = it }
+
                 fm.beginTransaction().add(fragment, TAG).commitAllowingStateLoss()
-            } else
+            } else {
+                channel?.let { (fragment as StoragePermissionsDelegate).channel = it }
                 (fragment as StoragePermissionsDelegate).requestStorageAccess(write)
+            }
+            channel?.let { waitForIt(it, cb!!) }
         }
     }
 }
diff --git a/vlc-android/src/org/videolan/vlc/gui/helpers/hf/WriteExternalDelegate.kt b/vlc-android/src/org/videolan/vlc/gui/helpers/hf/WriteExternalDelegate.kt
index 25fc5f103..371ad0bda 100644
--- a/vlc-android/src/org/videolan/vlc/gui/helpers/hf/WriteExternalDelegate.kt
+++ b/vlc-android/src/org/videolan/vlc/gui/helpers/hf/WriteExternalDelegate.kt
@@ -12,6 +12,7 @@ import android.support.v4.provider.DocumentFile
 import android.support.v7.app.AlertDialog
 import android.support.v7.preference.PreferenceManager
 import android.text.TextUtils
+import kotlinx.coroutines.experimental.channels.Channel
 import org.videolan.libvlc.util.AndroidUtil
 import org.videolan.vlc.R
 import org.videolan.vlc.VLCApplication
@@ -32,14 +33,12 @@ class WriteExternalDelegate : BaseHeadlessFragment() {
         val builder = AlertDialog.Builder(activity!!)
         builder.setMessage(R.string.sdcard_permission_dialog_message)
                 .setTitle(R.string.sdcard_permission_dialog_title)
-                .setPositiveButton(R.string.ok, { _, _ ->
+                .setPositiveButton(R.string.ok) { _, _ ->
                     val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
                     arguments?.getString(KEY_STORAGE_PATH)?.let { intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.parse(it)) }
                     startActivityForResult(intent, REQUEST_CODE_STORAGE_ACCES)
-                })
-                .setNeutralButton(getString(R.string.dialog_sd_wizard), { _, _ ->
-                    showHelpDialog()
-                }).create().show()
+                }
+                .setNeutralButton(getString(R.string.dialog_sd_wizard)) { _, _ -> showHelpDialog() }.create().show()
     }
 
     private fun showHelpDialog() {
@@ -52,6 +51,7 @@ class WriteExternalDelegate : BaseHeadlessFragment() {
         }
     }
 
+    @TargetApi(Build.VERSION_CODES.KITKAT)
     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
         super.onActivityResult(requestCode, resultCode, data)
         if (data !== null && requestCode == REQUEST_CODE_STORAGE_ACCES) {
@@ -59,7 +59,7 @@ class WriteExternalDelegate : BaseHeadlessFragment() {
                 val context = context ?: return
                 val treeUri = data.data
                 PreferenceManager.getDefaultSharedPreferences(VLCApplication.getAppContext()).edit()
-                        .putString("tree_uri_"+ storage, treeUri.toString()).apply()
+                        .putString("tree_uri_$storage", treeUri.toString()).apply()
                 val treeFile = DocumentFile.fromTreeUri(context, treeUri)
                 val contentResolver = context.contentResolver
 
@@ -76,11 +76,10 @@ class WriteExternalDelegate : BaseHeadlessFragment() {
                 // else set permission
                 contentResolver.takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                 permissions = contentResolver.persistedUriPermissions
-                executeCallback()
+                executePendingAction()
                 return
             }
         }
-        callback = null
     }
 
     companion object {
@@ -93,10 +92,12 @@ class WriteExternalDelegate : BaseHeadlessFragment() {
         fun askForExtWrite(activity: FragmentActivity?, uri: Uri, cb: Runnable? = null) {
             if (activity === null) return
             val fragment = WriteExternalDelegate()
-            callback = cb
+            val channel = if (cb != null) Channel<Unit>(1) else null
             storage = FileUtils.getMediaStorage(uri) ?: return
             fragment.arguments = Bundle(1).apply { putString(KEY_STORAGE_PATH, storage) }
+            channel?.let { fragment.channel = it }
             activity.supportFragmentManager.beginTransaction().add(fragment, TAG).commitAllowingStateLoss()
+            channel?.let { waitForIt(it, cb!!) }
         }
 
         fun needsWritePermission(uri: Uri) : Boolean {



More information about the Android mailing list