diff --git a/Common/File/AndroidStorage.cpp b/Common/File/AndroidStorage.cpp index d8d6468b91..78d457aabf 100644 --- a/Common/File/AndroidStorage.cpp +++ b/Common/File/AndroidStorage.cpp @@ -279,7 +279,9 @@ const char *Android_ErrorToString(StorageError error) { #else -// This string should never appear except on Android. +// These strings should never appear except on Android. +// Very hacky. std::string g_extFilesDir = "(IF YOU SEE THIS THERE'S A BUG)"; +std::string g_externalDir = "(IF YOU SEE THIS THERE'S A BUG (2))"; #endif diff --git a/Common/File/AndroidStorage.h b/Common/File/AndroidStorage.h index 131c0125d2..2a890d33b4 100644 --- a/Common/File/AndroidStorage.h +++ b/Common/File/AndroidStorage.h @@ -30,12 +30,13 @@ inline StorageError StorageErrorFromInt(int ival) { } } +extern std::string g_extFilesDir; +extern std::string g_externalDir; + #if PPSSPP_PLATFORM(ANDROID) && !defined(__LIBRETRO__) #include -extern std::string g_extFilesDir; - void Android_StorageSetNativeActivity(jobject nativeActivity); bool Android_IsContentUri(const std::string &uri); @@ -59,8 +60,6 @@ void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj); #else -extern std::string g_extFilesDir; - // Stub out the Android Storage wrappers, so that we can avoid ifdefs everywhere. inline bool Android_IsContentUri(const std::string &uri) { return false; } diff --git a/Common/File/Path.cpp b/Common/File/Path.cpp index 2af4374937..3ffd64549d 100644 --- a/Common/File/Path.cpp +++ b/Common/File/Path.cpp @@ -10,16 +10,6 @@ #include "android/jni/AndroidContentURI.h" Path::Path(const std::string &str) { - if (str.empty()) { - type_ = PathType::UNDEFINED; - } else if (startsWith(str, "http://") || startsWith(str, "https://")) { - type_ = PathType::HTTP; - } else if (Android_IsContentUri(str)) { - type_ = PathType::CONTENT_URI; - } else { - type_ = PathType::NATIVE; - } - Init(str); } @@ -31,7 +21,35 @@ Path::Path(const std::wstring &str) { #endif void Path::Init(const std::string &str) { - path_ = str; + if (str.empty()) { + type_ = PathType::UNDEFINED; + path_.clear(); + } else if (startsWith(str, "http://") || startsWith(str, "https://")) { + type_ = PathType::HTTP; + path_ = str; + } else if (Android_IsContentUri(str)) { + // Content URIs on non scoped-storage (and possibly other cases?) can contain + // "raw:/" URIs inside. This happens when picking the Download folder using the folder browser + // on Android 9. + // Here's an example: + // content://com.android.providers.downloads.documents/tree/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fp/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fp + // + // Since this is a legacy use case, I think it's safe enough to just detect this + // and flip it to a NATIVE url and hope for the best. + AndroidContentURI uri(str); + if (startsWith(uri.FilePath(), "raw:/")) { + INFO_LOG(SYSTEM, "Raw path detected: %s", uri.FilePath().c_str()); + path_ = uri.FilePath().substr(4); + type_ = PathType::NATIVE; + } else { + // A normal content URI path. + type_ = PathType::CONTENT_URI; + path_ = str; + } + } else { + type_ = PathType::NATIVE; + path_ = str; + } #if PPSSPP_PLATFORM(WINDOWS) // Flip all the slashes around. We flip them back on ToWString(). diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 18c8398060..6b1e97e368 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -903,9 +903,6 @@ void GameSettingsScreen::CreateViews() { systemSettings->Add(new ItemHeader(sy->T("PSP Memory Stick"))); - systemSettings->Add(new CheckBox(&g_Config.bMemStickInserted, sy->T("Memory Stick inserted"))); - systemSettings->Add(new PopupSliderChoice(&g_Config.iMemStickSizeGB, 1, 32, sy->T("Change Memory Stick Size", "Memory Stick Size (GB)"), screenManager(), "GB")); - #if PPSSPP_PLATFORM(ANDROID) memstickDisplay_ = g_Config.memStickDirectory.ToVisualString(); auto memstickPath = systemSettings->Add(new ChoiceWithValueDisplay(&memstickDisplay_, sy->T("Change Memory Stick folder", "Memory Stick folder"), (const char *)nullptr)); @@ -955,6 +952,9 @@ void GameSettingsScreen::CreateViews() { } } #endif + systemSettings->Add(new CheckBox(&g_Config.bMemStickInserted, sy->T("Memory Stick inserted"))); + systemSettings->Add(new PopupSliderChoice(&g_Config.iMemStickSizeGB, 1, 32, sy->T("Change Memory Stick Size", "Memory Stick Size (GB)"), screenManager(), "GB")); + systemSettings->Add(new ItemHeader(sy->T("General"))); #if PPSSPP_PLATFORM(ANDROID) diff --git a/UI/MemStickScreen.cpp b/UI/MemStickScreen.cpp index 5b51cbba9a..f2eae807b8 100644 --- a/UI/MemStickScreen.cpp +++ b/UI/MemStickScreen.cpp @@ -102,7 +102,6 @@ static std::string FormatSpaceString(int64_t space) { MemStickScreen::MemStickScreen(bool initialSetup) : initialSetup_(initialSetup) { - pendingMemStickFolder_ = g_Config.memStickDirectory; } void MemStickScreen::CreateViews() { @@ -129,6 +128,14 @@ void MemStickScreen::CreateViews() { leftColumn->Add(new TextView(iz->T("MemoryStickDescription", "Choose PSP data storage (Memory Stick)"), ALIGN_LEFT, false)); + // For legacy Android systems, so you can switch back to the old ways if you move to SD or something. + // TODO: Gonna need a scroll view. +#if PPSSPP_PLATFORM(ANDROID) + if (!System_GetPropertyBool(SYSPROP_ANDROID_SCOPED_STORAGE)) { + leftColumn->Add(new Choice(iz->T("Use PSP folder at root of storage")))->OnClick.Handle(this, &MemStickScreen::OnUseStorageRoot); + } +#endif + leftColumn->Add(new Choice(iz->T("Create or Choose a PSP folder")))->OnClick.Handle(this, &MemStickScreen::OnBrowse); leftColumn->Add(new TextView(iz->T("ChooseFolderDesc", "* Data will stay even if you uninstall PPSSPP.\n* Data can be shared with PPSSPP Gold\n* Easy USB access"), ALIGN_LEFT, false)); @@ -145,19 +152,37 @@ void MemStickScreen::CreateViews() { } UI::EventReturn MemStickScreen::OnUseInternalStorage(UI::EventParams ¶ms) { - pendingMemStickFolder_ = Path(g_extFilesDir); + Path pendingMemStickFolder = Path(g_extFilesDir); if (initialSetup_) { // There's not gonna be any files here in this case since it's a fresh install. // Let's just accept it and move on. No need to move files either. - if (SwitchMemstickFolderTo(pendingMemStickFolder_)) { + if (SwitchMemstickFolderTo(pendingMemStickFolder)) { TriggerFinish(DialogResult::DR_OK); } else { // This can't really happen?? Not worth making an error message. } } else { // Always ask for confirmation when called from the UI. Likely there's already some data. - screenManager()->push(new ConfirmMemstickMoveScreen(pendingMemStickFolder_, false)); + screenManager()->push(new ConfirmMemstickMoveScreen(pendingMemStickFolder, false)); + } + return UI::EVENT_DONE; +} + +UI::EventReturn MemStickScreen::OnUseStorageRoot(UI::EventParams ¶ms) { + Path pendingMemStickFolder = Path(g_externalDir); + + if (initialSetup_) { + // There's not gonna be any files here in this case since it's a fresh install. + // Let's just accept it and move on. No need to move files either. + if (SwitchMemstickFolderTo(pendingMemStickFolder)) { + TriggerFinish(DialogResult::DR_OK); + } else { + // This can't really happen?? Not worth making an error message. + } + } else { + // Always ask for confirmation when called from the UI. Likely there's already some data. + screenManager()->push(new ConfirmMemstickMoveScreen(pendingMemStickFolder, false)); } return UI::EVENT_DONE; } @@ -179,9 +204,9 @@ void MemStickScreen::sendMessage(const char *message, const char *value) { INFO_LOG(SYSTEM, "Got folder: '%s'", filename.c_str()); // Browse finished. Let's pop up the confirmation dialog. - pendingMemStickFolder_ = Path(filename); - bool existingFiles = FolderSeemsToBeUsed(pendingMemStickFolder_); - screenManager()->push(new ConfirmMemstickMoveScreen(pendingMemStickFolder_, initialSetup_)); + Path pendingMemStickFolder = Path(filename); + bool existingFiles = FolderSeemsToBeUsed(pendingMemStickFolder); + screenManager()->push(new ConfirmMemstickMoveScreen(pendingMemStickFolder, initialSetup_)); } } } diff --git a/UI/MemStickScreen.h b/UI/MemStickScreen.h index 7b9f843562..d058d3c490 100644 --- a/UI/MemStickScreen.h +++ b/UI/MemStickScreen.h @@ -58,9 +58,8 @@ private: // Event handlers UI::EventReturn OnBrowse(UI::EventParams &e); UI::EventReturn OnUseInternalStorage(UI::EventParams ¶ms); + UI::EventReturn OnUseStorageRoot(UI::EventParams ¶ms); - // TODO: probably not necessary to store here, we just forward to the confirmation dialog. - Path pendingMemStickFolder_; SettingInfoMessage *settingInfo_ = nullptr; bool initialSetup_; diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index f7baea793d..795ec23f4e 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -128,7 +128,8 @@ std::string langRegion; std::string mogaVersion; std::string boardName; -std::string g_extFilesDir; +std::string g_externalDir; // Original external dir (root of Android storage). +std::string g_extFilesDir; // App private external dir. std::vector g_additionalStorageDirs; @@ -637,6 +638,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init std::string additionalStorageDirsString = GetJavaString(env, jadditionalStorageDirs); std::string externalFilesDir = GetJavaString(env, jexternalFilesDir); + g_externalDir = externalStorageDir; g_extFilesDir = externalFilesDir; if (!additionalStorageDirsString.empty()) {