WIP re-implementation of Android Rename using native filesystem manipulation

This commit is contained in:
OpenSauce04 2025-12-14 22:34:45 +00:00
parent cb66169c59
commit c13a122527
6 changed files with 35 additions and 52 deletions

View File

@ -7,10 +7,12 @@ package org.citra.citra_emu
import android.Manifest.permission
import android.app.Dialog
import android.content.DialogInterface
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.Surface
@ -18,7 +20,9 @@ import android.view.View
import android.widget.TextView
import androidx.annotation.Keep
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.fragment.app.DialogFragment
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.citra.citra_emu.activities.EmulationActivity
import org.citra.citra_emu.utils.FileUtil
@ -629,6 +633,23 @@ object NativeLibrary {
FileUtil.getFilesName(path)
}
@Keep
@JvmStatic
fun getUserDirectory(): String {
val preferences: SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
val udUri = preferences.getString("CITRA_DIRECTORY", "")!!.toUri()
val udPathSegment = udUri.lastPathSegment!!
val udVirtualPath = udPathSegment.removePrefix("primary:")
if (udVirtualPath == udPathSegment) {
throw IllegalStateException("TODO: User directory must be in primary external storage, is instead: $udVirtualPath")
}
val userDirNativePath = Environment.getExternalStorageDirectory().absolutePath + "/" + udVirtualPath + "/"
return userDirNativePath
}
@Keep
@JvmStatic
fun getSize(path: String): Long =
@ -676,19 +697,6 @@ object NativeLibrary {
)
}
@Keep
@JvmStatic
fun renameFile(path: String, destinationFilename: String): Boolean =
if (FileUtil.isNativePath(path)) {
try {
CitraApplication.documentsTree.renameFile(path, destinationFilename)
} catch (e: Exception) {
false
}
} else {
FileUtil.renameFile(path, destinationFilename)
}
@Keep
@JvmStatic
fun deleteDocument(path: String): Boolean =

View File

@ -190,19 +190,6 @@ class DocumentsTree {
}
}
@Synchronized
fun renameFile(filepath: String, destinationFilename: String?): Boolean {
val node = resolvePath(filepath) ?: return false
try {
val filename = URLDecoder.decode(destinationFilename, FileUtil.DECODE_METHOD)
val newUri = DocumentsContract.renameDocument(context.contentResolver, node.uri!!, filename)
node.rename(filename, newUri)
return true
} catch (e: Exception) {
error("[DocumentsTree]: Cannot rename file, error: " + e.message)
}
}
@Synchronized
fun deleteDocument(filepath: String): Boolean {
val node = resolvePath(filepath) ?: return false

View File

@ -422,18 +422,6 @@ object FileUtil {
}
}
@JvmStatic
fun renameFile(path: String, destinationFilename: String): Boolean {
try {
val uri = Uri.parse(path)
DocumentsContract.renameDocument(context.contentResolver, uri, destinationFilename)
return true
} catch (e: Exception) {
Log.error("[FileUtil]: Cannot rename file, error: " + e.message)
}
return false
}
@JvmStatic
fun deleteDocument(path: String): Boolean {
try {

View File

@ -150,6 +150,14 @@ std::vector<std::string> GetFilesName(const std::string& filepath) {
return vector;
}
std::string GetUserDirectory() {
if (get_user_directory == nullptr)
throw std::runtime_error("Unable to locate user directory: Function with ID 'get_user_directory' is missing");
auto env = GetEnvForThread();
auto j_user_directory = (jstring)(env->CallStaticObjectMethod(native_library, get_user_directory));
return env->GetStringUTFChars(j_user_directory, nullptr);
}
bool CopyFile(const std::string& source, const std::string& destination_path,
const std::string& destination_filename) {
if (copy_file == nullptr)
@ -162,16 +170,6 @@ bool CopyFile(const std::string& source, const std::string& destination_path,
j_destination_path, j_destination_filename);
}
bool RenameFile(const std::string& source, const std::string& filename) {
if (rename_file == nullptr)
return false;
auto env = GetEnvForThread();
jstring j_source_path = env->NewStringUTF(source.c_str());
jstring j_destination_path = env->NewStringUTF(filename.c_str());
return env->CallStaticBooleanMethod(native_library, rename_file, j_source_path,
j_destination_path);
}
#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
F(FunctionName, ReturnValue, JMethodID, Caller)
#define F(FunctionName, ReturnValue, JMethodID, Caller) \

View File

@ -19,12 +19,12 @@
open_content_uri, "openContentUri", "(Ljava/lang/String;Ljava/lang/String;)I") \
V(GetFilesName, std::vector<std::string>, (const std::string& filepath), get_files_name, \
"getFilesName", "(Ljava/lang/String;)[Ljava/lang/String;") \
V(GetUserDirectory, std::string, (), get_user_directory, "getUserDirectory", \
"()Ljava/lang/String;") \
V(CopyFile, bool, \
(const std::string& source, const std::string& destination_path, \
const std::string& destination_filename), \
copy_file, "copyFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z") \
V(RenameFile, bool, (const std::string& source, const std::string& filename), rename_file, \
"renameFile", "(Ljava/lang/String;Ljava/lang/String;)Z")
copy_file, "copyFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z")
#define ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(V) \
V(IsDirectory, bool, is_directory, CallStaticBooleanMethod, "isDirectory", \
"(Ljava/lang/String;)Z") \

View File

@ -311,7 +311,9 @@ bool Rename(const std::string& srcFilename, const std::string& destFilename) {
Common::UTF8ToUTF16W(destFilename).c_str()) == 0)
return true;
#elif ANDROID
if (AndroidStorage::RenameFile(srcFilename, std::string(GetFilename(destFilename))))
const std::string userDirLocation = AndroidStorage::GetUserDirectory();
if (rename((userDirLocation + srcFilename).c_str(),
(userDirLocation + destFilename).c_str()) == 0)
return true;
#else
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)