diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageActivity.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageActivity.kt index b2cd0326..ca743c6f 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageActivity.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageActivity.kt @@ -31,11 +31,14 @@ class StorageActivity : BackupActivity() { */ private val openDocumentTree = registerForActivityResult(OpenPersistableDocumentTree()) { uri -> if (uri != null) { - Log.e(TAG, "OpenDocumentTree: $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) if (storageRoot == null) { - viewModel.onUriPermissionResultReceived(null) + val fakeRoot = StorageRootResolver.getFakeStorageRootForUri(this, uri) + viewModel.onSafOptionChosen(fakeRoot) + viewModel.onUriPermissionResultReceived(uri) } else { viewModel.onSafOptionChosen(storageRoot) viewModel.onUriPermissionResultReceived(uri) @@ -56,11 +59,11 @@ class StorageActivity : BackupActivity() { } viewModel.isSetupWizard = isSetupWizard() - viewModel.locationSet.observeEvent(this, { + viewModel.locationSet.observeEvent(this) { showFragment(StorageCheckFragment.newInstance(getCheckFragmentTitle()), true) - }) + } - viewModel.locationChecked.observeEvent(this, { result -> + viewModel.locationChecked.observeEvent(this) { result -> val errorMsg = result.errorMsg if (errorMsg == null) { setResult(RESULT_OK) @@ -68,7 +71,7 @@ class StorageActivity : BackupActivity() { } else { onInvalidLocation(errorMsg) } - }) + } if (savedInstanceState == null) { if (canUseStorageRootsFragment()) { diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageOptionsFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageOptionsFragment.kt index 62146332..fc84248c 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageOptionsFragment.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageOptionsFragment.kt @@ -95,9 +95,9 @@ internal class StorageOptionsFragment : Fragment(), StorageOptionClickedListener listView.adapter = adapter - viewModel.storageOptions.observe(viewLifecycleOwner, { roots -> + viewModel.storageOptions.observe(viewLifecycleOwner) { roots -> onRootsLoaded(roots) - }) + } } override fun onStart() { diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageRootResolver.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageRootResolver.kt index 4d615e6a..9db71b6f 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageRootResolver.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageRootResolver.kt @@ -1,8 +1,10 @@ package com.stevesoltys.seedvault.ui.storage +import android.Manifest.permission.MANAGE_DOCUMENTS import android.content.Context import android.database.Cursor import android.graphics.drawable.Drawable +import android.net.Uri import android.os.UserHandle import android.provider.DocumentsContract import android.provider.DocumentsContract.Root.COLUMN_AVAILABLE_BYTES @@ -57,6 +59,25 @@ internal object StorageRootResolver { 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 { + val authority = uri.authority ?: throw AssertionError("No authority in $uri") + return SafOption( + authority = authority, + rootId = ROOT_ID_DEVICE, + documentId = DocumentsContract.getTreeDocumentId(uri), + icon = getIcon(context, authority, ROOT_ID_DEVICE, 0), + title = context.getString(R.string.storage_user_selected_location_title), + summary = "Please open a bug if you see this", + availableBytes = null, + isUsb = false, // FIXME not supported without MANAGE_DOCUMENTS permission + requiresNetwork = authority != AUTHORITY_STORAGE && authority != AUTHORITY_DOWNLOADS, + ) + } + private fun getStorageRoot(context: Context, authority: String, cursor: Cursor): SafOption? { val flags = cursor.getInt(COLUMN_FLAGS) val supportsCreate = flags and FLAG_SUPPORTS_CREATE != 0 @@ -107,15 +128,19 @@ internal object StorageRootResolver { authority == AUTHORITY_STORAGE && rootId == ROOT_ID_DEVICE -> { context.getDrawable(R.drawable.ic_phone_android) } + authority == AUTHORITY_STORAGE && rootId != ROOT_ID_HOME -> { context.getDrawable(R.drawable.ic_usb) } + authority == AUTHORITY_NEXTCLOUD -> { context.getDrawable(R.drawable.nextcloud) } + authority == AUTHORITY_DAVX5 -> { context.getDrawable(R.drawable.davx5) } + else -> null } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9b936b2d..502ba39c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,6 +58,7 @@ Where to find your backups? People with access to your storage location can learn which apps you use, but do not get access to the apps\' data. Existing backups in this location will be deleted. + User-chosen location USB flash drive Needs to be plugged in %1$s free