Improving support for missing MANAGE_DOCUMENTS permission

This commit is contained in:
Torsten Grote 2023-09-13 12:06:57 +02:00 committed by Steve Soltys
parent 208dbd6a60
commit 1e69831244
4 changed files with 27 additions and 18 deletions

View file

@ -31,12 +31,13 @@ class StorageActivity : BackupActivity() {
*/ */
private val openDocumentTree = registerForActivityResult(OpenPersistableDocumentTree()) { uri -> private val openDocumentTree = registerForActivityResult(OpenPersistableDocumentTree()) { uri ->
if (uri != null) { if (uri != null) {
Log.e(TAG, "OpenDocumentTree: $uri")
val authority = uri.authority ?: throw AssertionError("No authority in $uri") val authority = uri.authority ?: throw AssertionError("No authority in $uri")
// we are most likely not allowed to resolve storage roots,
// but being the optimists we are, we are still trying...
val storageRoot = StorageRootResolver.getStorageRoots(this, authority).getOrNull(0) val storageRoot = StorageRootResolver.getStorageRoots(this, authority).getOrNull(0)
if (storageRoot == null) { if (storageRoot == null) {
viewModel.onSafOptionChosen( val fakeRoot = StorageRootResolver.getFakeStorageRootForUri(this, uri)
StorageRootResolver.getFakeStorageRootForUri(this, uri)) viewModel.onSafOptionChosen(fakeRoot)
viewModel.onUriPermissionResultReceived(uri) viewModel.onUriPermissionResultReceived(uri)
} else { } else {
viewModel.onSafOptionChosen(storageRoot) viewModel.onSafOptionChosen(storageRoot)
@ -58,11 +59,11 @@ class StorageActivity : BackupActivity() {
} }
viewModel.isSetupWizard = isSetupWizard() viewModel.isSetupWizard = isSetupWizard()
viewModel.locationSet.observeEvent(this, { viewModel.locationSet.observeEvent(this) {
showFragment(StorageCheckFragment.newInstance(getCheckFragmentTitle()), true) showFragment(StorageCheckFragment.newInstance(getCheckFragmentTitle()), true)
}) }
viewModel.locationChecked.observeEvent(this, { result -> viewModel.locationChecked.observeEvent(this) { result ->
val errorMsg = result.errorMsg val errorMsg = result.errorMsg
if (errorMsg == null) { if (errorMsg == null) {
setResult(RESULT_OK) setResult(RESULT_OK)
@ -70,7 +71,7 @@ class StorageActivity : BackupActivity() {
} else { } else {
onInvalidLocation(errorMsg) onInvalidLocation(errorMsg)
} }
}) }
if (savedInstanceState == null) { if (savedInstanceState == null) {
if (canUseStorageRootsFragment()) { if (canUseStorageRootsFragment()) {

View file

@ -95,9 +95,9 @@ internal class StorageOptionsFragment : Fragment(), StorageOptionClickedListener
listView.adapter = adapter listView.adapter = adapter
viewModel.storageOptions.observe(viewLifecycleOwner, { roots -> viewModel.storageOptions.observe(viewLifecycleOwner) { roots ->
onRootsLoaded(roots) onRootsLoaded(roots)
}) }
} }
override fun onStart() { override fun onStart() {

View file

@ -1,5 +1,6 @@
package com.stevesoltys.seedvault.ui.storage package com.stevesoltys.seedvault.ui.storage
import android.Manifest.permission.MANAGE_DOCUMENTS
import android.content.Context import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
@ -58,18 +59,22 @@ internal object StorageRootResolver {
return roots return roots
} }
/**
* Used for getting a SafOption when we lack [MANAGE_DOCUMENTS],
* since we are not allowed to use [getStorageRoots] in this case.
*/
fun getFakeStorageRootForUri(context: Context, uri: Uri): SafOption { fun getFakeStorageRootForUri(context: Context, uri: Uri): SafOption {
val authority = uri.authority ?: throw AssertionError("No authority in $uri")
return SafOption( return SafOption(
authority = AUTHORITY_STORAGE, authority = authority,
rootId = "fake", rootId = ROOT_ID_DEVICE,
documentId = "fake", documentId = DocumentsContract.getTreeDocumentId(uri),
// TODO: Use something other than the USB icon? icon = getIcon(context, authority, ROOT_ID_DEVICE, 0),
icon = getIcon(context, AUTHORITY_STORAGE, "usb", 0),
title = context.getString(R.string.storage_user_selected_location_title), title = context.getString(R.string.storage_user_selected_location_title),
summary = context.getString(R.string.storage_user_selected_location_summary), summary = "Please open a bug if you see this",
availableBytes = null, availableBytes = null,
isUsb = false, // TODO: Check this if possible instead of forcing false isUsb = false, // FIXME not supported without MANAGE_DOCUMENTS permission
requiresNetwork = false, // TODO: Check this if possible instead of forcing false requiresNetwork = authority != AUTHORITY_STORAGE && authority != AUTHORITY_DOWNLOADS,
) )
} }
@ -123,15 +128,19 @@ internal object StorageRootResolver {
authority == AUTHORITY_STORAGE && rootId == ROOT_ID_DEVICE -> { authority == AUTHORITY_STORAGE && rootId == ROOT_ID_DEVICE -> {
context.getDrawable(R.drawable.ic_phone_android) context.getDrawable(R.drawable.ic_phone_android)
} }
authority == AUTHORITY_STORAGE && rootId != ROOT_ID_HOME -> { authority == AUTHORITY_STORAGE && rootId != ROOT_ID_HOME -> {
context.getDrawable(R.drawable.ic_usb) context.getDrawable(R.drawable.ic_usb)
} }
authority == AUTHORITY_NEXTCLOUD -> { authority == AUTHORITY_NEXTCLOUD -> {
context.getDrawable(R.drawable.nextcloud) context.getDrawable(R.drawable.nextcloud)
} }
authority == AUTHORITY_DAVX5 -> { authority == AUTHORITY_DAVX5 -> {
context.getDrawable(R.drawable.davx5) context.getDrawable(R.drawable.davx5)
} }
else -> null else -> null
} }
} }

View file

@ -59,7 +59,6 @@
<string name="storage_fragment_warning">People with access to your storage location can learn which apps you use, but do not get access to the apps\' data.</string> <string name="storage_fragment_warning">People with access to your storage location can learn which apps you use, but do not get access to the apps\' data.</string>
<string name="storage_fragment_warning_delete">Existing backups in this location will be deleted.</string> <string name="storage_fragment_warning_delete">Existing backups in this location will be deleted.</string>
<string name="storage_user_selected_location_title">User-chosen location</string> <string name="storage_user_selected_location_title">User-chosen location</string>
<string name="storage_user_selected_location_summary">Chosen using the folder browser</string>
<string name="storage_fake_drive_title">USB flash drive</string> <string name="storage_fake_drive_title">USB flash drive</string>
<string name="storage_fake_drive_summary">Needs to be plugged in</string> <string name="storage_fake_drive_summary">Needs to be plugged in</string>
<string name="storage_available_bytes"><xliff:g example="1 GB" id="size">%1$s</xliff:g> free</string> <string name="storage_available_bytes"><xliff:g example="1 GB" id="size">%1$s</xliff:g> free</string>