[Android] OTG: Use a Flow for access

Geoffrey Métais git at videolan.org
Fri Feb 21 14:34:17 CET 2020


vlc-android | branch: master | Geoffrey Métais <geoffrey.metais at gmail.com> | Wed Feb 19 11:40:28 2020 +0100| [a4baf9748b7522c12ab5bae90615d85a065c5dd0] | committer: Geoffrey Métais

OTG: Use a Flow for access

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

 .../src/org/videolan/vlc/ExternalMonitor.kt        |  4 +--
 .../vlc/gui/browser/FileBrowserFragment.kt         | 23 ++++++++--------
 .../org/videolan/vlc/gui/helpers/hf/OtgAccess.kt   | 31 ++++++++++++----------
 3 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/application/vlc-android/src/org/videolan/vlc/ExternalMonitor.kt b/application/vlc-android/src/org/videolan/vlc/ExternalMonitor.kt
index a1057efe7..b8c491d14 100644
--- a/application/vlc-android/src/org/videolan/vlc/ExternalMonitor.kt
+++ b/application/vlc-android/src/org/videolan/vlc/ExternalMonitor.kt
@@ -42,7 +42,6 @@ import kotlinx.coroutines.*
 import kotlinx.coroutines.channels.BroadcastChannel
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.channels.Channel.Factory.BUFFERED
-import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
 import kotlinx.coroutines.channels.actor
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.consumeAsFlow
@@ -54,7 +53,6 @@ import org.videolan.tools.*
 import org.videolan.tools.livedata.LiveDataset
 import org.videolan.vlc.gui.helpers.UiTools
 import org.videolan.vlc.gui.helpers.hf.OtgAccess
-import videolan.org.commontools.LiveEvent
 import java.lang.ref.WeakReference
 
 private const val TAG = "VLC/ExternalMonitor"
@@ -104,7 +102,7 @@ object ExternalMonitor : BroadcastReceiver(), LifecycleObserver, CoroutineScope
                 }
             }
             UsbManager.ACTION_USB_DEVICE_DETACHED -> if (intent.hasExtra(UsbManager.EXTRA_DEVICE)) {
-                (OtgAccess.otgRoot as LiveEvent<Uri>).clear()
+                OtgAccess.otgRoot.offer(null)
                 val device = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)
                 devices.remove(device)
             }
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/browser/FileBrowserFragment.kt b/application/vlc-android/src/org/videolan/vlc/gui/browser/FileBrowserFragment.kt
index af34cc1e6..f75c0fee0 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/browser/FileBrowserFragment.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/browser/FileBrowserFragment.kt
@@ -30,12 +30,13 @@ import android.view.Menu
 import android.view.MenuInflater
 import android.view.View
 import androidx.fragment.app.Fragment
-import androidx.lifecycle.Observer
-import androidx.lifecycle.ViewModelProviders
 import androidx.lifecycle.lifecycleScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.ObsoleteCoroutinesApi
+import kotlinx.coroutines.flow.consumeAsFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.withContext
 import org.videolan.medialibrary.MLServiceLocator
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
@@ -47,8 +48,8 @@ import org.videolan.vlc.ExternalMonitor
 import org.videolan.vlc.R
 import org.videolan.vlc.gui.helpers.MedialibraryUtils
 import org.videolan.vlc.gui.helpers.hf.OtgAccess
+import org.videolan.vlc.gui.helpers.hf.requestOtgRoot
 import org.videolan.vlc.util.FileUtils
-import org.videolan.vlc.viewmodels.browser.BrowserModel
 import org.videolan.vlc.viewmodels.browser.TYPE_FILE
 import org.videolan.vlc.viewmodels.browser.getBrowserModel
 
@@ -115,18 +116,16 @@ open class FileBrowserFragment : BaseBrowserFragment() {
             val mw = item as MediaWrapper
             if ("otg://" == mw.location) {
                 val title = getString(R.string.otg_device_title)
-                val otgRoot = OtgAccess.otgRoot
-                val rootUri = otgRoot.value
+                val rootUri = OtgAccess.otgRoot.value
                 if (rootUri != null && ExternalMonitor.devices.size == 1) {
                     browseOtgDevice(rootUri, title)
                 } else {
-                    otgRoot.observeForever(object : Observer<Uri> {
-                        override fun onChanged(uri: Uri?) {
-                            OtgAccess.otgRoot.removeObserver(this)
-                            if (uri != null) browseOtgDevice(uri, title)
-                        }
-                    })
-                    OtgAccess.requestOtgRoot(requireActivity())
+                    lifecycleScope.launchWhenStarted {
+                        val otgRoot = OtgAccess.otgRoot.openSubscription().consumeAsFlow()
+                        val uri = otgRoot.filterNotNull().first()
+                        browseOtgDevice(uri, title)
+                    }
+                    requireActivity().requestOtgRoot()
                 }
                 return
             }
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/helpers/hf/OtgAccess.kt b/application/vlc-android/src/org/videolan/vlc/gui/helpers/hf/OtgAccess.kt
index 6ecedc817..6d352d623 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/helpers/hf/OtgAccess.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/helpers/hf/OtgAccess.kt
@@ -31,10 +31,10 @@ import android.util.Log
 import androidx.annotation.WorkerThread
 import androidx.documentfile.provider.DocumentFile
 import androidx.fragment.app.FragmentActivity
-import androidx.lifecycle.LiveData
+import kotlinx.coroutines.channels.ConflatedBroadcastChannel
 import org.videolan.medialibrary.MLServiceLocator
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
-import videolan.org.commontools.LiveEvent
+import org.videolan.tools.safeOffer
 
 const val SAF_REQUEST = 85
 const val TAG = "OtgAccess"
@@ -47,31 +47,34 @@ class OtgAccess : BaseHeadlessFragment() {
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        val safIntent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
-        try {
-            startActivityForResult(safIntent, SAF_REQUEST)
-        } catch (e: ActivityNotFoundException) {
-            exit()
+        if (savedInstanceState == null) {
+            val safIntent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
+            try {
+                startActivityForResult(safIntent, SAF_REQUEST)
+            } catch (e: ActivityNotFoundException) {
+                exit()
+            }
         }
     }
 
     override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
-        if (intent != null && requestCode == SAF_REQUEST) (otgRoot as LiveEvent).value = intent.data
+        if (intent != null && requestCode == SAF_REQUEST) otgRoot.safeOffer(intent.data)
         else super.onActivityResult(requestCode, resultCode, intent)
         exit()
     }
 
     companion object {
-        fun requestOtgRoot(activity: FragmentActivity?) {
-            activity?.supportFragmentManager?.beginTransaction()?.add(OtgAccess(), TAG)?.commitAllowingStateLoss()
-        }
-        var otgRoot : LiveData<Uri> = LiveEvent()
+        val otgRoot = ConflatedBroadcastChannel<Uri?>(null)
     }
 }
 
+fun FragmentActivity.requestOtgRoot() {
+    supportFragmentManager.beginTransaction().add(OtgAccess(), TAG).commitAllowingStateLoss()
+}
+
 @WorkerThread
 fun getDocumentFiles(context: Context, path: String) : List<MediaWrapper>? {
-    val rootUri = OtgAccess.otgRoot.value ?: return null
+    val rootUri = OtgAccess.otgRoot.valueOrNull ?: return null
 //    else Uri.Builder().scheme("content")
 //            .authority(OTG_CONTENT_AUTHORITY)
 //            .path(path.substringBefore(':'))
@@ -107,4 +110,4 @@ fun getDocumentFiles(context: Context, path: String) : List<MediaWrapper>? {
         }
     }
     return list
-}
\ No newline at end of file
+}



More information about the Android mailing list