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.Manifest.permission
import android.app.Dialog import android.app.Dialog
import android.content.DialogInterface import android.content.DialogInterface
import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Configuration import android.content.res.Configuration
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import android.text.Html import android.text.Html
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.view.Surface import android.view.Surface
@ -18,7 +20,9 @@ import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.annotation.Keep import androidx.annotation.Keep
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.citra.citra_emu.activities.EmulationActivity import org.citra.citra_emu.activities.EmulationActivity
import org.citra.citra_emu.utils.FileUtil import org.citra.citra_emu.utils.FileUtil
@ -629,6 +633,23 @@ object NativeLibrary {
FileUtil.getFilesName(path) 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 @Keep
@JvmStatic @JvmStatic
fun getSize(path: String): Long = 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 @Keep
@JvmStatic @JvmStatic
fun deleteDocument(path: String): Boolean = 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 @Synchronized
fun deleteDocument(filepath: String): Boolean { fun deleteDocument(filepath: String): Boolean {
val node = resolvePath(filepath) ?: return false 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 @JvmStatic
fun deleteDocument(path: String): Boolean { fun deleteDocument(path: String): Boolean {
try { try {

View File

@ -150,6 +150,14 @@ std::vector<std::string> GetFilesName(const std::string& filepath) {
return vector; 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, bool CopyFile(const std::string& source, const std::string& destination_path,
const std::string& destination_filename) { const std::string& destination_filename) {
if (copy_file == nullptr) 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); 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) \ #define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
F(FunctionName, ReturnValue, JMethodID, Caller) F(FunctionName, ReturnValue, JMethodID, Caller)
#define 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") \ open_content_uri, "openContentUri", "(Ljava/lang/String;Ljava/lang/String;)I") \
V(GetFilesName, std::vector<std::string>, (const std::string& filepath), get_files_name, \ V(GetFilesName, std::vector<std::string>, (const std::string& filepath), get_files_name, \
"getFilesName", "(Ljava/lang/String;)[Ljava/lang/String;") \ "getFilesName", "(Ljava/lang/String;)[Ljava/lang/String;") \
V(GetUserDirectory, std::string, (), get_user_directory, "getUserDirectory", \
"()Ljava/lang/String;") \
V(CopyFile, bool, \ V(CopyFile, bool, \
(const std::string& source, const std::string& destination_path, \ (const std::string& source, const std::string& destination_path, \
const std::string& destination_filename), \ const std::string& destination_filename), \
copy_file, "copyFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z") \ 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")
#define ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(V) \ #define ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(V) \
V(IsDirectory, bool, is_directory, CallStaticBooleanMethod, "isDirectory", \ V(IsDirectory, bool, is_directory, CallStaticBooleanMethod, "isDirectory", \
"(Ljava/lang/String;)Z") \ "(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) Common::UTF8ToUTF16W(destFilename).c_str()) == 0)
return true; return true;
#elif ANDROID #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; return true;
#else #else
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)