Skip to content

Commit

Permalink
Add ability to rename content URI files, fixing saving save states.
Browse files Browse the repository at this point in the history
buildfix
  • Loading branch information
hrydgard committed Jul 19, 2021
1 parent 6daa18c commit fff3850
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 6 deletions.
13 changes: 13 additions & 0 deletions Common/File/AndroidStorage.cpp
Expand Up @@ -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;
Expand All @@ -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");
Expand Down Expand Up @@ -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<std::string> parts;
SplitString(line, '|', parts);
Expand Down
2 changes: 2 additions & 0 deletions Common/File/AndroidStorage.h
Expand Up @@ -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);
Expand All @@ -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<File::FileInfo> Android_ListContentUri(const std::string &uri) {
Expand Down
20 changes: 14 additions & 6 deletions Common/File/FileUtil.cpp
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions Common/File/Path.h
Expand Up @@ -79,6 +79,7 @@ class Path {

// 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);
Expand Down
17 changes: 17 additions & 0 deletions android/src/org/ppsspp/ppsspp/PpssppActivity.java
Expand Up @@ -9,6 +9,7 @@
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;
Expand Down Expand Up @@ -217,6 +218,22 @@ public boolean contentUriRemoveFile(String fileName) {
}
}

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);
Expand Down

0 comments on commit fff3850

Please sign in to comment.