From 445d12ac94596540f5eaca8adc7164e0e03efdac Mon Sep 17 00:00:00 2001 From: Julien Papasian Date: Sat, 5 Apr 2025 13:18:05 +0200 Subject: [PATCH 1/2] More friendly access to data/obb folder on Android 14+ --- .../commons/activities/BaseSimpleActivity.kt | 4 +- .../fossify/commons/extensions/Activity.kt | 124 +++++++++++++++--- commons/src/main/res/values/strings.xml | 4 + 3 files changed, 110 insertions(+), 22 deletions(-) diff --git a/commons/src/main/kotlin/org/fossify/commons/activities/BaseSimpleActivity.kt b/commons/src/main/kotlin/org/fossify/commons/activities/BaseSimpleActivity.kt index c1906678e6..f391eb812e 100644 --- a/commons/src/main/kotlin/org/fossify/commons/activities/BaseSimpleActivity.kt +++ b/commons/src/main/kotlin/org/fossify/commons/activities/BaseSimpleActivity.kt @@ -751,12 +751,12 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } } - fun handleAndroidSAFDialog(path: String, callback: (success: Boolean) -> Unit): Boolean { + fun handleAndroidSAFDialog(path: String, openInSystemAppAllowed: Boolean = false, callback: (success: Boolean) -> Unit): Boolean { hideKeyboard() return if (!packageName.startsWith("org.fossify")) { callback(true) false - } else if (isShowingAndroidSAFDialog(path)) { + } else if (isShowingAndroidSAFDialog(path, openInSystemAppAllowed)) { funAfterSAFPermission = callback true } else { diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt index b9c3f0b094..1035390d7f 100644 --- a/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt +++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt @@ -226,30 +226,58 @@ fun BaseSimpleActivity.isShowingSAFCreateDocumentDialogSdk30(path: String): Bool } } -fun BaseSimpleActivity.isShowingAndroidSAFDialog(path: String): Boolean { +fun BaseSimpleActivity.isShowingAndroidSAFDialog(path: String, openInSystemAppAllowed: Boolean = false): Boolean { return if (isRestrictedSAFOnlyRoot(path) && (getAndroidTreeUri(path).isEmpty() || !hasProperStoredAndroidTreeUri(path))) { runOnUiThread { if (!isDestroyed && !isFinishing) { - ConfirmationAdvancedDialog(this, "", R.string.confirm_storage_access_android_text, R.string.ok, R.string.cancel) { success -> - if (success) { - Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { - putExtra(EXTRA_SHOW_ADVANCED, true) - putExtra(DocumentsContract.EXTRA_INITIAL_URI, createAndroidDataOrObbUri(path)) - try { - startActivityForResult(this, OPEN_DOCUMENT_TREE_FOR_ANDROID_DATA_OR_OBB) - checkedDocumentPath = path - return@apply - } catch (e: Exception) { - type = "*/*" - } + if (isUpsideDownCakePlus() && !openInSystemAppAllowed) { + ConfirmationDialog( + this, + "", + R.string.confirm_storage_access_restricted_text, + positive = android.R.string.ok, + negative = 0 + ) {} + } else { + ConfirmationAdvancedDialog( + this, + "", + R.string.confirm_storage_access_restricted_text, + if (isUpsideDownCakePlus()) { + R.string.confirm_storage_access_restricted_text_open_system + } else { + R.string.confirm_storage_access_restricted_text_request_access + }, + R.string.cancel + ) { success -> + if (success) { + val uri = createAndroidDataOrObbUri(path) - try { - startActivityForResult(this, OPEN_DOCUMENT_TREE_FOR_ANDROID_DATA_OR_OBB) - checkedDocumentPath = path - } catch (e: ActivityNotFoundException) { - toast(R.string.system_service_disabled, Toast.LENGTH_LONG) - } catch (e: Exception) { - toast(R.string.unknown_error_occurred) + // On Android 14+, there is no longer any workaround to access the data/ and obb/ folders + // Open the system app instead + if (isUpsideDownCakePlus()) { + launchSystemFileManager(uri) + } else { + Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { + putExtra(EXTRA_SHOW_ADVANCED, true) + putExtra(DocumentsContract.EXTRA_INITIAL_URI, uri) + try { + startActivityForResult(this, OPEN_DOCUMENT_TREE_FOR_ANDROID_DATA_OR_OBB) + checkedDocumentPath = path + return@apply + } catch (e: Exception) { + type = "*/*" + } + + try { + startActivityForResult(this, OPEN_DOCUMENT_TREE_FOR_ANDROID_DATA_OR_OBB) + checkedDocumentPath = path + } catch (e: ActivityNotFoundException) { + toast(R.string.system_service_disabled, Toast.LENGTH_LONG) + } catch (e: Exception) { + toast(R.string.unknown_error_occurred) + } + } } } } @@ -262,6 +290,62 @@ fun BaseSimpleActivity.isShowingAndroidSAFDialog(path: String): Boolean { } } +/** + * Launch system file manager by testing different possible intents depending on the device + * Each intent is tested in a OR condition which allows to stop at the first successful one + */ +fun BaseSimpleActivity.launchSystemFileManager(uri: Uri) { + if ( + startIntentForUriAction( + uri, + "android.intent.action.VIEW", + ComponentName("com.google.android.documentsui", "com.android.documentsui.files.FilesActivity") + ) || + startIntentForUriAction( + uri, + "android.intent.action.VIEW", + ComponentName("com.android.documentsui", "com.android.documentsui.files.FilesActivity") + ) || + startIntentForUriAction( + uri, + "android.intent.action.VIEW", + ComponentName("com.android.documentsui", "com.android.documentsui.FilesActivity") + ) || + startIntentForUriAction(uri, "android.intent.action.VIEW", null) || + startIntentForUriAction(uri, "android.provider.action.BROWSE", null) || + startIntentForUriAction(uri, "android.provider.action.BROWSE_DOCUMENT_ROOT", null) + ) { + return + } else { + toast(R.string.confirm_storage_access_restricted_text_not_found) + } +} + +/** + * Start the intent + * @param uri URI to pass to the intent + * @param action Action of the intent + * @param componentName Optional ComponentName + * @return true if the intent was successful + */ +fun BaseSimpleActivity.startIntentForUriAction( + uri: Uri, + action: String, + componentName: ComponentName? +): Boolean { + val intent = Intent(action, uri) + if (componentName != null) { + intent.setComponent(componentName) + } + return try { + startActivity(intent) + true + } catch (e: java.lang.Exception) { + e.printStackTrace() + false + } +} + fun BaseSimpleActivity.isShowingOTGDialog(path: String): Boolean { return if (!isRPlus() && isPathOnOTG(path) && (baseConfig.OTGTreeUri.isEmpty() || !hasProperStoredTreeUri(true))) { showOTGPermissionDialog(path) diff --git a/commons/src/main/res/values/strings.xml b/commons/src/main/res/values/strings.xml index f49d70800a..481dd02cdc 100644 --- a/commons/src/main/res/values/strings.xml +++ b/commons/src/main/res/values/strings.xml @@ -290,6 +290,10 @@ If you don\'t see the SD card, try this Please allow the app accessing the selected storage on the next screen by pressing \'Use this folder\' at the bottom. Please allow access to \'<b>%s</b>\' on the next screen by pressing \'<b>Use this folder</b>\' at the bottom. + Due to system restrictions, this folder is not available. + Request access + Open in system app + A system file manager app could not be found. Please press \'<b>Save</b>\' at the bottom of the next screen to create the new folder. Confirm selection Loading… From f8d09eedcb8fa97a075b93fbcf0b72780d8e80d9 Mon Sep 17 00:00:00 2001 From: Julien Papasian Date: Sun, 6 Apr 2025 09:36:48 +0200 Subject: [PATCH 2/2] Restrict data/obb on Android 11+ --- .../fossify/commons/extensions/Activity.kt | 36 ++----------------- commons/src/main/res/values/strings.xml | 1 - 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt index 1035390d7f..fecb542989 100644 --- a/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt +++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt @@ -230,7 +230,7 @@ fun BaseSimpleActivity.isShowingAndroidSAFDialog(path: String, openInSystemAppAl return if (isRestrictedSAFOnlyRoot(path) && (getAndroidTreeUri(path).isEmpty() || !hasProperStoredAndroidTreeUri(path))) { runOnUiThread { if (!isDestroyed && !isFinishing) { - if (isUpsideDownCakePlus() && !openInSystemAppAllowed) { + if (!openInSystemAppAllowed) { ConfirmationDialog( this, "", @@ -243,42 +243,12 @@ fun BaseSimpleActivity.isShowingAndroidSAFDialog(path: String, openInSystemAppAl this, "", R.string.confirm_storage_access_restricted_text, - if (isUpsideDownCakePlus()) { - R.string.confirm_storage_access_restricted_text_open_system - } else { - R.string.confirm_storage_access_restricted_text_request_access - }, + R.string.confirm_storage_access_restricted_text_open_system, R.string.cancel ) { success -> if (success) { val uri = createAndroidDataOrObbUri(path) - - // On Android 14+, there is no longer any workaround to access the data/ and obb/ folders - // Open the system app instead - if (isUpsideDownCakePlus()) { - launchSystemFileManager(uri) - } else { - Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { - putExtra(EXTRA_SHOW_ADVANCED, true) - putExtra(DocumentsContract.EXTRA_INITIAL_URI, uri) - try { - startActivityForResult(this, OPEN_DOCUMENT_TREE_FOR_ANDROID_DATA_OR_OBB) - checkedDocumentPath = path - return@apply - } catch (e: Exception) { - type = "*/*" - } - - try { - startActivityForResult(this, OPEN_DOCUMENT_TREE_FOR_ANDROID_DATA_OR_OBB) - checkedDocumentPath = path - } catch (e: ActivityNotFoundException) { - toast(R.string.system_service_disabled, Toast.LENGTH_LONG) - } catch (e: Exception) { - toast(R.string.unknown_error_occurred) - } - } - } + launchSystemFileManager(uri) } } } diff --git a/commons/src/main/res/values/strings.xml b/commons/src/main/res/values/strings.xml index 481dd02cdc..2a892e816a 100644 --- a/commons/src/main/res/values/strings.xml +++ b/commons/src/main/res/values/strings.xml @@ -291,7 +291,6 @@ Please allow the app accessing the selected storage on the next screen by pressing \'Use this folder\' at the bottom. Please allow access to \'<b>%s</b>\' on the next screen by pressing \'<b>Use this folder</b>\' at the bottom. Due to system restrictions, this folder is not available. - Request access Open in system app A system file manager app could not be found. Please press \'<b>Save</b>\' at the bottom of the next screen to create the new folder.