Skip to content

Commit

Permalink
Merge pull request #551 from seedvault-app/bugfix/fix-no-manage-docum…
Browse files Browse the repository at this point in the history
…ents-permission

Support a lack of MANAGE_DOCUMENTS permission
  • Loading branch information
stevesoltys committed Sep 14, 2023
2 parents da5205c + 1e69831 commit 77fed00
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -56,19 +59,19 @@ 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)
finishAfterTransition()
} else {
onInvalidLocation(errorMsg)
}
})
}

if (savedInstanceState == null) {
if (canUseStorageRootsFragment()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<string name="storage_fragment_restore_title">Where to find your backups?</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_user_selected_location_title">User-chosen location</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_available_bytes"><xliff:g example="1 GB" id="size">%1$s</xliff:g> free</string>
Expand Down

0 comments on commit 77fed00

Please sign in to comment.