Skip to content
Snippets Groups Projects
Commit 6d5775ff authored by Nicolas Pomepuy's avatar Nicolas Pomepuy
Browse files

Fix and improve OTG permission asking

(cherry picked from commit 15cbd981)
parent 1ce9f609
No related branches found
No related tags found
1 merge request!782Backport to 3.3.x
......@@ -763,4 +763,6 @@
<string name="air_action_volume_down">Volume down</string>
<string name="air_action_next">Next item in playback</string>
<string name="air_action_previous">Previous item in playback</string>
<string name="allow_otg">Allow OTG access</string>
<string name="allow_otg_description">Please select your OTG drive to allow access to VLC.</string>
</resources>
......@@ -114,27 +114,6 @@ open class FileBrowserFragment : BaseBrowserFragment() {
viewModel.browseRoot()
}
override fun onClick(v: View, position: Int, item: MediaLibraryItem) {
if (item.itemType == MediaLibraryItem.TYPE_MEDIA) {
val mw = item as MediaWrapper
if ("otg://" == mw.location) {
val title = getString(R.string.otg_device_title)
val rootUri = OtgAccess.otgRoot.value
if (rootUri != null && ExternalMonitor.devices.size == 1) {
browseOtgDevice(rootUri, title)
} else {
lifecycleScope.launchWhenStarted {
val uri = OtgAccess.otgRoot.filterNotNull().first()
browseOtgDevice(uri, title)
}
requireActivity().requestOtgRoot()
}
return
}
}
super.onClick(v, position, item)
}
override fun onCtxAction(position: Int, option: Long) {
val mw = this.adapter.getItem(position) as MediaWrapper?
when (option) {
......@@ -175,10 +154,4 @@ open class FileBrowserFragment : BaseBrowserFragment() {
}
}
private fun browseOtgDevice(uri: Uri, title: String) {
val mw = MLServiceLocator.getAbstractMediaWrapper(uri)
mw.type = MediaWrapper.TYPE_DIR
mw.title = title
handler.post { browse(mw, true) }
}
}
......@@ -28,11 +28,13 @@ import android.content.Intent
import android.os.Bundle
import android.view.*
import androidx.appcompat.view.ActionMode
import androidx.core.net.toUri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.*
import org.videolan.medialibrary.interfaces.media.MediaWrapper
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.medialibrary.media.MediaWrapperImpl
import org.videolan.resources.*
import org.videolan.tools.NetworkMonitor
import org.videolan.tools.isStarted
......@@ -48,6 +50,8 @@ import org.videolan.vlc.gui.helpers.UiTools.addToPlaylist
import org.videolan.vlc.gui.helpers.UiTools.addToPlaylistAsync
import org.videolan.vlc.gui.helpers.UiTools.showMediaInfo
import org.videolan.vlc.gui.helpers.hf.OTG_SCHEME
import org.videolan.vlc.gui.helpers.hf.OtgAccess
import org.videolan.vlc.gui.helpers.hf.requestOtgRoot
import org.videolan.vlc.gui.view.EmptyLoadingState
import org.videolan.vlc.gui.view.EmptyLoadingStateView
import org.videolan.vlc.gui.view.TitleListView
......@@ -75,6 +79,8 @@ class MainBrowserFragment : BaseFragment(), View.OnClickListener, CtxActionRecei
private val containerAdapterAssociation = HashMap<MainBrowserContainer, Pair<BaseBrowserAdapter, ViewModel>>()
private var requiringOtg = false
override fun hasFAB() = true
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
......@@ -198,6 +204,19 @@ class MainBrowserFragment : BaseFragment(), View.OnClickListener, CtxActionRecei
networkViewModel.browseRoot()
}
override fun onResume() {
super.onResume()
if (requiringOtg && OtgAccess.otgRoot.value != null) {
val intent = Intent(requireActivity().applicationContext, SecondaryActivity::class.java)
val otgMedia = MediaWrapperImpl("otg://".toUri())
otgMedia.title = getString(R.string.otg_device_title)
intent.putExtra(KEY_MEDIA, otgMedia)
intent.putExtra("fragment", SecondaryActivity.FILE_BROWSER)
startActivity(intent)
}
requiringOtg = false
}
private fun updateNetworkEmptyView(emptyLoading: EmptyLoadingStateView) {
if (networkMonitor.connected) {
if (networkViewModel.isEmpty()) {
......@@ -283,6 +302,16 @@ class MainBrowserFragment : BaseFragment(), View.OnClickListener, CtxActionRecei
invalidateActionMode()
}
} else {
if (item.itemType == MediaLibraryItem.TYPE_MEDIA) {
if ("otg://" == item.location) {
val rootUri = OtgAccess.otgRoot.value
if (rootUri == null) {
requiringOtg = true
requireActivity().requestOtgRoot()
return
}
}
}
val intent = Intent(requireActivity().applicationContext, SecondaryActivity::class.java)
intent.putExtra(KEY_MEDIA, item)
intent.putExtra("fragment", SecondaryActivity.FILE_BROWSER)
......
......@@ -27,18 +27,21 @@ import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.DocumentsContract
import android.util.Log
import androidx.annotation.WorkerThread
import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.FragmentActivity
import kotlinx.coroutines.flow.MutableStateFlow
import org.videolan.medialibrary.MLServiceLocator
import org.videolan.medialibrary.interfaces.media.MediaWrapper
import org.videolan.vlc.R
const val SAF_REQUEST = 85
const val TAG = "OtgAccess"
const val OTG_CONTENT_AUTHORITY = "com.android.externalstorage.documents"
const val OTG_SCHEME = "otg"
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
......@@ -46,13 +49,25 @@ class OtgAccess : BaseHeadlessFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
val safIntent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
try {
startActivityForResult(safIntent, SAF_REQUEST)
} catch (e: ActivityNotFoundException) {
exit()
}
AlertDialog.Builder(requireActivity())
.setTitle(resources.getString(R.string.allow_otg))
.setMessage(resources.getString(R.string.allow_otg_description))
.setPositiveButton(R.string.ok) { _, _ ->
val safIntent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
try {
startActivityForResult(safIntent, SAF_REQUEST)
} catch (e: ActivityNotFoundException) {
exit()
}
}
.setOnCancelListener {
exit()
}
.show()
}
}
......@@ -74,10 +89,6 @@ fun FragmentActivity.requestOtgRoot() {
@WorkerThread
fun getDocumentFiles(context: Context, path: String) : List<MediaWrapper>? {
val rootUri = OtgAccess.otgRoot.value ?: return null
// else Uri.Builder().scheme("content")
// .authority(OTG_CONTENT_AUTHORITY)
// .path(path.substringBefore(':'))
// .build()
var documentFile = DocumentFile.fromTreeUri(context, rootUri)
val parts = path.substringAfterLast(':').split("/".toRegex()).dropLastWhile { it.isEmpty() }
......
......@@ -23,6 +23,8 @@ package org.videolan.vlc.providers
import android.content.Context
import android.net.Uri
import androidx.core.net.toUri
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import org.videolan.libvlc.interfaces.IMedia
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.medialibrary.media.Storage
......@@ -33,6 +35,8 @@ import org.videolan.vlc.repository.DirectoryRepository
import java.io.File
import java.util.*
@ExperimentalCoroutinesApi
@ObsoleteCoroutinesApi
class StorageProvider(context: Context, dataset: LiveDataset<MediaLibraryItem>, url: String?, showHiddenFiles: Boolean): FileBrowserProvider(context, dataset, url, false, showHiddenFiles) {
override suspend fun browseRootImpl() {
......
package org.videolan.vlc.repository
import android.content.Context
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.*
import org.videolan.libvlc.util.AndroidUtil
import org.videolan.medialibrary.MLServiceLocator
import org.videolan.medialibrary.interfaces.media.MediaWrapper
......@@ -17,6 +15,8 @@ import org.videolan.vlc.database.MediaDatabase
import org.videolan.vlc.util.FileUtils
import java.io.File
@ExperimentalCoroutinesApi
@ObsoleteCoroutinesApi
class DirectoryRepository (private val customDirectoryDao: CustomDirectoryDao) : IOScopedObject() {
fun addCustomDirectory(path: String): Job = launch {
......@@ -27,7 +27,7 @@ class DirectoryRepository (private val customDirectoryDao: CustomDirectoryDao) :
try {
customDirectoryDao.getAll()
} catch (e: Exception) {
emptyList<org.videolan.vlc.mediadb.models.CustomDirectory>()
emptyList()
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment