From fff3850096a6fcd7a97d8e7283af980514653ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 18 Jul 2021 22:28:30 +0200 Subject: [PATCH] Add ability to rename content URI files, fixing saving save states. buildfix --- Common/File/AndroidStorage.cpp | 13 ++++++++++++ Common/File/AndroidStorage.h | 2 ++ Common/File/FileUtil.cpp | 20 +++++++++++++------ Common/File/Path.h | 1 + .../src/org/ppsspp/ppsspp/PpssppActivity.java | 17 ++++++++++++++++ 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/Common/File/AndroidStorage.cpp b/Common/File/AndroidStorage.cpp index 6ea6983f5e..8321b4c50f 100644 --- a/Common/File/AndroidStorage.cpp +++ b/Common/File/AndroidStorage.cpp @@ -12,6 +12,7 @@ static jmethodID listContentUriDir; static jmethodID contentUriCreateFile; static jmethodID contentUriCreateDirectory; static jmethodID contentUriRemoveFile; +static jmethodID contentUriRenameFileTo; static jmethodID contentUriGetFileInfo; static jmethodID contentUriGetFreeStorageSpace; static jmethodID filePathGetFreeStorageSpace; @@ -33,6 +34,8 @@ void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj) { _dbg_assert_(contentUriCreateFile); contentUriRemoveFile = env->GetMethodID(env->GetObjectClass(obj), "contentUriRemoveFile", "(Ljava/lang/String;)Z"); _dbg_assert_(contentUriRemoveFile); + contentUriRenameFileTo = env->GetMethodID(env->GetObjectClass(obj), "contentUriRenameFileTo", "(Ljava/lang/String;Ljava/lang/String;)Z"); + _dbg_assert_(contentUriRenameFileTo); contentUriGetFileInfo = env->GetMethodID(env->GetObjectClass(obj), "contentUriGetFileInfo", "(Ljava/lang/String;)Ljava/lang/String;"); _dbg_assert_(contentUriGetFileInfo); contentUriGetFreeStorageSpace = env->GetMethodID(env->GetObjectClass(obj), "contentUriGetFreeStorageSpace", "(Ljava/lang/String;)J"); @@ -98,6 +101,16 @@ bool Android_RemoveFile(const std::string &fileUri) { return env->CallBooleanMethod(g_nativeActivity, contentUriRemoveFile, paramFileName); } +bool Android_RenameFileTo(const std::string &fileUri, const std::string &newName) { + if (!g_nativeActivity) { + return false; + } + auto env = getEnv(); + jstring paramFileUri = env->NewStringUTF(fileUri.c_str()); + jstring paramNewName = env->NewStringUTF(newName.c_str()); + return env->CallBooleanMethod(g_nativeActivity, contentUriRenameFileTo, paramFileUri, paramNewName); +} + static bool ParseFileInfo(const std::string &line, File::FileInfo *fileInfo) { std::vector parts; SplitString(line, '|', parts); diff --git a/Common/File/AndroidStorage.h b/Common/File/AndroidStorage.h index 71211824df..89c4442bf8 100644 --- a/Common/File/AndroidStorage.h +++ b/Common/File/AndroidStorage.h @@ -26,6 +26,7 @@ int Android_OpenContentUriFd(const std::string &uri, const Android_OpenContentUr bool Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName); bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName); bool Android_RemoveFile(const std::string &fileUri); +bool Android_RenameFileTo(const std::string &fileUri, const std::string &newName); bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info); int64_t Android_GetFreeSpaceByContentUri(const std::string &uri); int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath); @@ -44,6 +45,7 @@ inline bool Android_CreateDirectory(const std::string &parentTreeUri, const std: inline bool Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName) { return false; } inline bool Android_RemoveFile(const std::string &fileUri) { return false; } inline bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info) { return false; } +inline bool Android_RenameFileTo(const std::string &fileUri, const std::string &newName) { return false; } inline int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) { return -1; } inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; } inline std::vector Android_ListContentUri(const std::string &uri) { diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp index bdd64d96c5..c2328c914a 100644 --- a/Common/File/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -513,19 +513,27 @@ bool DeleteDir(const Path &path) { } // renames file srcFilename to destFilename, returns true on success -bool Rename(const Path &srcFilename, const Path &destFilename) -{ +bool Rename(const Path &srcFilename, const Path &destFilename) { if (srcFilename.Type() != destFilename.Type()) { - // Impossible. + // Impossible. You're gonna need to make a copy, and delete the original. Not the responsibility + // of Rename. return false; } + // We've already asserted that they're the same Type, so only need to check either src or dest. switch (srcFilename.Type()) { case PathType::NATIVE: - break; // OK + // OK, proceed with the regular code. + break; case PathType::CONTENT_URI: - ERROR_LOG_REPORT_ONCE(renameUriNotSupported, COMMON, "Moving files by Android URI is not yet supported"); - return false; + // Content URI: Can only rename if in the same folder. + if (srcFilename.GetDirectory() != destFilename.GetDirectory()) { + INFO_LOG(COMMON, "Content URI rename: Directories not matching, failing. %s --> %s", srcFilename.c_str(), destFilename.c_str()); + return false; + } + INFO_LOG(COMMON, "Content URI rename: %s --> %s", srcFilename.c_str(), destFilename.c_str()); + + return Android_RenameFileTo(srcFilename.ToString(), destFilename.GetFilename()); default: return false; } diff --git a/Common/File/Path.h b/Common/File/Path.h index 53fc8745e2..3b0c911203 100644 --- a/Common/File/Path.h +++ b/Common/File/Path.h @@ -79,6 +79,7 @@ public: // Navigates as far up as possible from this path. If not possible to navigate upwards, returns the same path. // Not actually always the root of the volume, especially on systems like Mac and Linux where things are often mounted. + // For Android directory trees, navigates to the root of the tree. Path GetRootVolume() const; std::string PathTo(const Path &child); diff --git a/android/src/org/ppsspp/ppsspp/PpssppActivity.java b/android/src/org/ppsspp/ppsspp/PpssppActivity.java index a09a5e759a..c5cc646d53 100644 --- a/android/src/org/ppsspp/ppsspp/PpssppActivity.java +++ b/android/src/org/ppsspp/ppsspp/PpssppActivity.java @@ -9,6 +9,7 @@ import android.os.Looper; import android.os.ParcelFileDescriptor; import android.util.Log; import android.os.storage.StorageManager; +import android.provider.DocumentsContract; import androidx.documentfile.provider.DocumentFile; import java.util.ArrayList; import java.util.UUID; @@ -217,6 +218,22 @@ public class PpssppActivity extends NativeActivity { } } + public boolean contentUriRenameFileTo(String fileUri, String newName) { + try { + Uri uri = Uri.parse(fileUri); + + // Due to a design flaw, we can't use DocumentFile.renameTo(). + // Instead we use the DocumentsContract API directly. + // See https://stackoverflow.com/questions/37168200/android-5-0-new-sd-card-access-api-documentfile-renameto-unsupportedoperation. + Uri newUri = DocumentsContract.renameDocument(getContentResolver(), uri, newName); + // Log.i(TAG, "New uri: " + newUri.toString()); + return true; + } catch (Exception e) { + Log.e(TAG, "contentUriRenameFile exception: " + e.toString()); + return false; + } + } + public String contentUriGetFileInfo(String fileName) { try { Uri uri = Uri.parse(fileName);