From 533c76f4d65a4237fcf9b115f20d9a71fe23b306 Mon Sep 17 00:00:00 2001 From: Carlos Manuel Date: Sat, 23 May 2026 19:43:02 -0600 Subject: [PATCH] Add support for changing save location on Android (#1520) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enabled the Android UI path for changing the data folder - Added Android MANAGE_EXTERNAL_STORAGE permission - Added an Android flow to request “All files access” before opening the folder picker - Added code path to resume the folder selection flow after returning from Android settings - Improved the Android write-probe error message to point users at the required permission --- .../android/app/src/main/AndroidManifest.xml | 1 + .../com/twilitrealm/dusk/DuskActivity.java | 81 +++++++++++++++++++ src/dusk/data.cpp | 7 ++ src/dusk/data.hpp | 2 +- 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/platforms/android/app/src/main/AndroidManifest.xml b/platforms/android/app/src/main/AndroidManifest.xml index f5a0365856..cd687963e1 100644 --- a/platforms/android/app/src/main/AndroidManifest.xml +++ b/platforms/android/app/src/main/AndroidManifest.xml @@ -11,6 +11,7 @@ + { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | @@ -185,9 +204,71 @@ public class DuskActivity extends SDLActivity { finishFolderDialog(Activity.RESULT_CANCELED, null); } }); + } + + private boolean requiresManageStoragePermission() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R; + } + + private boolean hasManageStoragePermission() { + return !requiresManageStoragePermission() || Environment.isExternalStorageManager(); + } + + private boolean requestManageStoragePermission() { + if (!requiresManageStoragePermission()) { + return true; + } + + awaitingManageStoragePermission = true; + runOnUiThread(() -> { + if (tryStartManageStorageIntent( + new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) + .setData(Uri.parse("package:" + getPackageName()))) || + tryStartManageStorageIntent( + new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION))) + { + return; + } + + finishFolderDialogWithError("Unable to request Android file access permission"); + }); return true; } + private boolean tryStartManageStorageIntent(Intent intent) { + try { + startActivityForResult(intent, MANAGE_STORAGE_REQUEST_CODE); + return true; + } catch (ActivityNotFoundException e) { + Log.w(TAG, "Unable to open all-files access settings.", e); + return false; + } + } + + private void resumeFolderDialogAfterPermissionGrant() { + awaitingManageStoragePermission = false; + if (folderDialogUserdata == 0) { + return; + } + + if (hasManageStoragePermission()) { + openFolderDialog(); + return; + } + + finishFolderDialogWithError( + "Allow \"All files access\" for Dusklight before choosing a custom data folder"); + } + + private void finishFolderDialogWithError(String error) { + long userdata = folderDialogUserdata; + folderDialogUserdata = 0; + awaitingManageStoragePermission = false; + if (userdata != 0) { + nativeFolderDialogResult(userdata, null, error); + } + } + private void finishFolderDialog(int resultCode, Intent data) { long userdata = folderDialogUserdata; folderDialogUserdata = 0; diff --git a/src/dusk/data.cpp b/src/dusk/data.cpp index ce61965947..dc666dd236 100644 --- a/src/dusk/data.cpp +++ b/src/dusk/data.cpp @@ -525,7 +525,14 @@ bool validate_writable_data_path(const std::filesystem::path& path, std::string* try { io::FileStream::WriteAllText(probePath, "dusk"); } catch (const std::exception& e) { +#if defined(__ANDROID__) + set_error(errorOut, + fmt::format("{} could not write to the selected folder. On Android, allow " + "\"All files access\" for Dusklight and try again.", + AppName)); +#else set_error(errorOut, fmt::format("{} could not write to the selected folder.", AppName)); +#endif Log.warn("Failed write probe for custom data folder '{}': {}", io::fs_path_to_string(path), e.what()); return false; diff --git a/src/dusk/data.hpp b/src/dusk/data.hpp index c3ce495b46..bf20035a2d 100644 --- a/src/dusk/data.hpp +++ b/src/dusk/data.hpp @@ -15,7 +15,7 @@ #define DUSK_CAN_OPEN_DATA_FOLDER 0 #endif -#if (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || defined(__ANDROID__) +#if (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST) #define DUSK_CAN_CHANGE_DATA_FOLDER 0 #else #define DUSK_CAN_CHANGE_DATA_FOLDER 1