summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharles Lombardo <clombardo169@gmail.com>2023-03-11 06:37:04 +0100
committerbunnei <bunneidev@gmail.com>2023-06-03 09:05:41 +0200
commit7b54c2b2e25adb81c95d54941f55bae76770cdb9 (patch)
tree28032417460af44cd98210e098ab394cffdcd66b
parentandroid: Convert FileBrowserHelper to Kotlin (diff)
downloadyuzu-7b54c2b2e25adb81c95d54941f55bae76770cdb9.tar
yuzu-7b54c2b2e25adb81c95d54941f55bae76770cdb9.tar.gz
yuzu-7b54c2b2e25adb81c95d54941f55bae76770cdb9.tar.bz2
yuzu-7b54c2b2e25adb81c95d54941f55bae76770cdb9.tar.lz
yuzu-7b54c2b2e25adb81c95d54941f55bae76770cdb9.tar.xz
yuzu-7b54c2b2e25adb81c95d54941f55bae76770cdb9.tar.zst
yuzu-7b54c2b2e25adb81c95d54941f55bae76770cdb9.zip
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java296
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt292
2 files changed, 292 insertions, 296 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java
deleted file mode 100644
index 8665704cc..000000000
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java
+++ /dev/null
@@ -1,296 +0,0 @@
-package org.yuzu.yuzu_emu.utils;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract;
-
-import androidx.annotation.Nullable;
-import androidx.documentfile.provider.DocumentFile;
-
-import org.yuzu.yuzu_emu.model.MinimalDocumentFile;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.List;
-
-public class FileUtil {
- static final String PATH_TREE = "tree";
- static final String DECODE_METHOD = "UTF-8";
- static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
- static final String TEXT_PLAIN = "text/plain";
-
- /**
- * Create a file from directory with filename.
- * @param context Application context
- * @param directory parent path for file.
- * @param filename file display name.
- * @return boolean
- */
- @Nullable
- public static DocumentFile createFile(Context context, String directory, String filename) {
- try {
- Uri directoryUri = Uri.parse(directory);
- DocumentFile parent = DocumentFile.fromTreeUri(context, directoryUri);
- if (parent == null) return null;
- filename = URLDecoder.decode(filename, DECODE_METHOD);
- String mimeType = APPLICATION_OCTET_STREAM;
- if (filename.endsWith(".txt")) {
- mimeType = TEXT_PLAIN;
- }
- DocumentFile exists = parent.findFile(filename);
- if (exists != null) return exists;
- return parent.createFile(mimeType, filename);
- } catch (Exception e) {
- Log.error("[FileUtil]: Cannot create file, error: " + e.getMessage());
- }
- return null;
- }
-
- /**
- * Create a directory from directory with filename.
- * @param context Application context
- * @param directory parent path for directory.
- * @param directoryName directory display name.
- * @return boolean
- */
- @Nullable
- public static DocumentFile createDir(Context context, String directory, String directoryName) {
- try {
- Uri directoryUri = Uri.parse(directory);
- DocumentFile parent = DocumentFile.fromTreeUri(context, directoryUri);
- if (parent == null) return null;
- directoryName = URLDecoder.decode(directoryName, DECODE_METHOD);
- DocumentFile isExist = parent.findFile(directoryName);
- if (isExist != null) return isExist;
- return parent.createDirectory(directoryName);
- } catch (Exception e) {
- Log.error("[FileUtil]: Cannot create file, error: " + e.getMessage());
- }
- return null;
- }
-
- /**
- * Open content uri and return file descriptor to JNI.
- * @param context Application context
- * @param path Native content uri path
- * @param openmode will be one of "r", "r", "rw", "wa", "rwa"
- * @return file descriptor
- */
- public static int openContentUri(Context context, String path, String openmode) {
- try {
- Uri uri = Uri.parse(path);
- ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, openmode);
- if (parcelFileDescriptor == null) {
- Log.error("[FileUtil]: Cannot get the file descriptor from uri: " + path);
- return -1;
- }
- return parcelFileDescriptor.detachFd();
- }
- catch (Exception e) {
- Log.error("[FileUtil]: Cannot open content uri, error: " + e.getMessage());
- }
- return -1;
- }
-
- /**
- * Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow
- * This function will be faster than DoucmentFile.listFiles
- * @param context Application context
- * @param uri Directory uri.
- * @return CheapDocument lists.
- */
- public static MinimalDocumentFile[] listFiles(Context context, Uri uri) {
- final ContentResolver resolver = context.getContentResolver();
- final String[] columns = new String[]{
- DocumentsContract.Document.COLUMN_DOCUMENT_ID,
- DocumentsContract.Document.COLUMN_DISPLAY_NAME,
- DocumentsContract.Document.COLUMN_MIME_TYPE,
- };
- Cursor c = null;
- final List<MinimalDocumentFile> results = new ArrayList<>();
- try {
- String docId;
- if (isRootTreeUri(uri)) {
- docId = DocumentsContract.getTreeDocumentId(uri);
- } else {
- docId = DocumentsContract.getDocumentId(uri);
- }
- final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, docId);
- c = resolver.query(childrenUri, columns, null, null, null);
- while(c.moveToNext()) {
- final String documentId = c.getString(0);
- final String documentName = c.getString(1);
- final String documentMimeType = c.getString(2);
- final Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(uri, documentId);
- MinimalDocumentFile document = new MinimalDocumentFile(documentName, documentMimeType, documentUri);
- results.add(document);
- }
- } catch (Exception e) {
- Log.error("[FileUtil]: Cannot list file error: " + e.getMessage());
- } finally {
- closeQuietly(c);
- }
- return results.toArray(new MinimalDocumentFile[0]);
- }
-
- /**
- * Check whether given path exists.
- * @param path Native content uri path
- * @return bool
- */
- public static boolean Exists(Context context, String path) {
- Cursor c = null;
- try {
- Uri mUri = Uri.parse(path);
- final String[] columns = new String[] { DocumentsContract.Document.COLUMN_DOCUMENT_ID };
- c = context.getContentResolver().query(mUri, columns, null, null, null);
- return c.getCount() > 0;
- } catch (Exception e) {
- Log.info("[FileUtil] Cannot find file from given path, error: " + e.getMessage());
- } finally {
- closeQuietly(c);
- }
- return false;
- }
-
- /**
- * Check whether given path is a directory
- * @param path content uri path
- * @return bool
- */
- public static boolean isDirectory(Context context, String path) {
- final ContentResolver resolver = context.getContentResolver();
- final String[] columns = new String[] {
- DocumentsContract.Document.COLUMN_MIME_TYPE
- };
- boolean isDirectory = false;
- Cursor c = null;
- try {
- Uri mUri = Uri.parse(path);
- c = resolver.query(mUri, columns, null, null, null);
- c.moveToNext();
- final String mimeType = c.getString(0);
- isDirectory = mimeType.equals(DocumentsContract.Document.MIME_TYPE_DIR);
- } catch (Exception e) {
- Log.error("[FileUtil]: Cannot list files, error: " + e.getMessage());
- } finally {
- closeQuietly(c);
- }
- return isDirectory;
- }
-
- /**
- * Get file display name from given path
- * @param path content uri path
- * @return String display name
- */
- public static String getFilename(Context context, String path) {
- final ContentResolver resolver = context.getContentResolver();
- final String[] columns = new String[] {
- DocumentsContract.Document.COLUMN_DISPLAY_NAME
- };
- String filename = "";
- Cursor c = null;
- try {
- Uri mUri = Uri.parse(path);
- c = resolver.query(mUri, columns, null, null, null);
- c.moveToNext();
- filename = c.getString(0);
- } catch (Exception e) {
- Log.error("[FileUtil]: Cannot get file size, error: " + e.getMessage());
- } finally {
- closeQuietly(c);
- }
- return filename;
- }
-
- public static String[] getFilesName(Context context, String path) {
- Uri uri = Uri.parse(path);
- List<String> files = new ArrayList<>();
- for (MinimalDocumentFile file: FileUtil.listFiles(context, uri)) {
- files.add(file.getFilename());
- }
- return files.toArray(new String[0]);
- }
-
- /**
- * Get file size from given path.
- * @param path content uri path
- * @return long file size
- */
- public static long getFileSize(Context context, String path) {
- final ContentResolver resolver = context.getContentResolver();
- final String[] columns = new String[] {
- DocumentsContract.Document.COLUMN_SIZE
- };
- long size = 0;
- Cursor c =null;
- try {
- Uri mUri = Uri.parse(path);
- c = resolver.query(mUri, columns, null, null, null);
- c.moveToNext();
- size = c.getLong(0);
- } catch (Exception e) {
- Log.error("[FileUtil]: Cannot get file size, error: " + e.getMessage());
- } finally {
- closeQuietly(c);
- }
- return size;
- }
-
- public static boolean copyUriToInternalStorage(Context context, Uri sourceUri, String destinationParentPath, String destinationFilename) {
- InputStream input = null;
- FileOutputStream output = null;
- try {
- input = context.getContentResolver().openInputStream(sourceUri);
- output = new FileOutputStream(destinationParentPath + "/" + destinationFilename);
- byte[] buffer = new byte[1024];
- int len;
- while ((len = input.read(buffer)) != -1) {
- output.write(buffer, 0, len);
- }
- output.flush();
- return true;
- } catch (Exception e) {
- Log.error("[FileUtil]: Cannot copy file, error: " + e.getMessage());
- } finally {
- if (input != null) {
- try {
- input.close();
- } catch (IOException e) {
- Log.error("[FileUtil]: Cannot close input file, error: " + e.getMessage());
- }
- }
- if (output != null) {
- try {
- output.close();
- } catch (IOException e) {
- Log.error("[FileUtil]: Cannot close output file, error: " + e.getMessage());
- }
- }
- }
- return false;
- }
-
- public static boolean isRootTreeUri(Uri uri) {
- final List<String> paths = uri.getPathSegments();
- return paths.size() == 2 && PATH_TREE.equals(paths.get(0));
- }
-
- public static void closeQuietly(AutoCloseable closeable) {
- if (closeable != null) {
- try {
- closeable.close();
- } catch (RuntimeException rethrown) {
- throw rethrown;
- } catch (Exception ignored) {
- }
- }
- }
-}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
new file mode 100644
index 000000000..47fae0933
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
@@ -0,0 +1,292 @@
+package org.yuzu.yuzu_emu.utils
+
+import android.content.Context
+import android.database.Cursor
+import android.net.Uri
+import android.provider.DocumentsContract
+import androidx.documentfile.provider.DocumentFile
+import org.yuzu.yuzu_emu.model.MinimalDocumentFile
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.InputStream
+import java.net.URLDecoder
+
+object FileUtil {
+ const val PATH_TREE = "tree"
+ const val DECODE_METHOD = "UTF-8"
+ const val APPLICATION_OCTET_STREAM = "application/octet-stream"
+ const val TEXT_PLAIN = "text/plain"
+
+ /**
+ * Create a file from directory with filename.
+ * @param context Application context
+ * @param directory parent path for file.
+ * @param filename file display name.
+ * @return boolean
+ */
+ fun createFile(context: Context?, directory: String?, filename: String): DocumentFile? {
+ var decodedFilename = filename
+ try {
+ val directoryUri = Uri.parse(directory)
+ val parent = DocumentFile.fromTreeUri(context!!, directoryUri) ?: return null
+ decodedFilename = URLDecoder.decode(decodedFilename, DECODE_METHOD)
+ var mimeType = APPLICATION_OCTET_STREAM
+ if (decodedFilename.endsWith(".txt")) {
+ mimeType = TEXT_PLAIN
+ }
+ val exists = parent.findFile(decodedFilename)
+ return exists ?: parent.createFile(mimeType, decodedFilename)
+ } catch (e: Exception) {
+ Log.error("[FileUtil]: Cannot create file, error: " + e.message)
+ }
+ return null
+ }
+
+ /**
+ * Create a directory from directory with filename.
+ * @param context Application context
+ * @param directory parent path for directory.
+ * @param directoryName directory display name.
+ * @return boolean
+ */
+ fun createDir(context: Context?, directory: String?, directoryName: String?): DocumentFile? {
+ var decodedDirectoryName = directoryName
+ try {
+ val directoryUri = Uri.parse(directory)
+ val parent = DocumentFile.fromTreeUri(context!!, directoryUri) ?: return null
+ decodedDirectoryName = URLDecoder.decode(decodedDirectoryName, DECODE_METHOD)
+ val isExist = parent.findFile(decodedDirectoryName)
+ return isExist ?: parent.createDirectory(decodedDirectoryName)
+ } catch (e: Exception) {
+ Log.error("[FileUtil]: Cannot create file, error: " + e.message)
+ }
+ return null
+ }
+
+ /**
+ * Open content uri and return file descriptor to JNI.
+ * @param context Application context
+ * @param path Native content uri path
+ * @param openMode will be one of "r", "r", "rw", "wa", "rwa"
+ * @return file descriptor
+ */
+ @JvmStatic
+ fun openContentUri(context: Context, path: String, openMode: String?): Int {
+ try {
+ val uri = Uri.parse(path)
+ val parcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, openMode!!)
+ if (parcelFileDescriptor == null) {
+ Log.error("[FileUtil]: Cannot get the file descriptor from uri: $path")
+ return -1
+ }
+ val fileDescriptor = parcelFileDescriptor.detachFd()
+ parcelFileDescriptor.close()
+ return fileDescriptor
+ } catch (e: Exception) {
+ Log.error("[FileUtil]: Cannot open content uri, error: " + e.message)
+ }
+ return -1
+ }
+
+ /**
+ * Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow
+ * This function will be faster than DoucmentFile.listFiles
+ * @param context Application context
+ * @param uri Directory uri.
+ * @return CheapDocument lists.
+ */
+ fun listFiles(context: Context, uri: Uri): Array<MinimalDocumentFile> {
+ val resolver = context.contentResolver
+ val columns = arrayOf(
+ DocumentsContract.Document.COLUMN_DOCUMENT_ID,
+ DocumentsContract.Document.COLUMN_DISPLAY_NAME,
+ DocumentsContract.Document.COLUMN_MIME_TYPE
+ )
+ var c: Cursor? = null
+ val results: MutableList<MinimalDocumentFile> = ArrayList()
+ try {
+ val docId: String = if (isRootTreeUri(uri)) {
+ DocumentsContract.getTreeDocumentId(uri)
+ } else {
+ DocumentsContract.getDocumentId(uri)
+ }
+ val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, docId)
+ c = resolver.query(childrenUri, columns, null, null, null)
+ while (c!!.moveToNext()) {
+ val documentId = c.getString(0)
+ val documentName = c.getString(1)
+ val documentMimeType = c.getString(2)
+ val documentUri = DocumentsContract.buildDocumentUriUsingTree(uri, documentId)
+ val document = MinimalDocumentFile(documentName, documentMimeType, documentUri)
+ results.add(document)
+ }
+ } catch (e: Exception) {
+ Log.error("[FileUtil]: Cannot list file error: " + e.message)
+ } finally {
+ closeQuietly(c)
+ }
+ return results.toTypedArray()
+ }
+
+ /**
+ * Check whether given path exists.
+ * @param path Native content uri path
+ * @return bool
+ */
+ fun exists(context: Context, path: String?): Boolean {
+ var c: Cursor? = null
+ try {
+ val mUri = Uri.parse(path)
+ val columns = arrayOf(DocumentsContract.Document.COLUMN_DOCUMENT_ID)
+ c = context.contentResolver.query(mUri, columns, null, null, null)
+ return c!!.count > 0
+ } catch (e: Exception) {
+ Log.info("[FileUtil] Cannot find file from given path, error: " + e.message)
+ } finally {
+ closeQuietly(c)
+ }
+ return false
+ }
+
+ /**
+ * Check whether given path is a directory
+ * @param path content uri path
+ * @return bool
+ */
+ fun isDirectory(context: Context, path: String): Boolean {
+ val resolver = context.contentResolver
+ val columns = arrayOf(
+ DocumentsContract.Document.COLUMN_MIME_TYPE
+ )
+ var isDirectory = false
+ var c: Cursor? = null
+ try {
+ val mUri = Uri.parse(path)
+ c = resolver.query(mUri, columns, null, null, null)
+ c!!.moveToNext()
+ val mimeType = c.getString(0)
+ isDirectory = mimeType == DocumentsContract.Document.MIME_TYPE_DIR
+ } catch (e: Exception) {
+ Log.error("[FileUtil]: Cannot list files, error: " + e.message)
+ } finally {
+ closeQuietly(c)
+ }
+ return isDirectory
+ }
+
+ /**
+ * Get file display name from given path
+ * @param path content uri path
+ * @return String display name
+ */
+ fun getFilename(context: Context, path: String): String {
+ val resolver = context.contentResolver
+ val columns = arrayOf(
+ DocumentsContract.Document.COLUMN_DISPLAY_NAME
+ )
+ var filename = ""
+ var c: Cursor? = null
+ try {
+ val mUri = Uri.parse(path)
+ c = resolver.query(mUri, columns, null, null, null)
+ c!!.moveToNext()
+ filename = c.getString(0)
+ } catch (e: Exception) {
+ Log.error("[FileUtil]: Cannot get file size, error: " + e.message)
+ } finally {
+ closeQuietly(c)
+ }
+ return filename
+ }
+
+ fun getFilesName(context: Context, path: String): Array<String> {
+ val uri = Uri.parse(path)
+ val files: MutableList<String> = ArrayList()
+ for (file in listFiles(context, uri)) {
+ files.add(file.filename)
+ }
+ return files.toTypedArray()
+ }
+
+ /**
+ * Get file size from given path.
+ * @param path content uri path
+ * @return long file size
+ */
+ @JvmStatic
+ fun getFileSize(context: Context, path: String): Long {
+ val resolver = context.contentResolver
+ val columns = arrayOf(
+ DocumentsContract.Document.COLUMN_SIZE
+ )
+ var size: Long = 0
+ var c: Cursor? = null
+ try {
+ val mUri = Uri.parse(path)
+ c = resolver.query(mUri, columns, null, null, null)
+ c!!.moveToNext()
+ size = c.getLong(0)
+ } catch (e: Exception) {
+ Log.error("[FileUtil]: Cannot get file size, error: " + e.message)
+ } finally {
+ closeQuietly(c)
+ }
+ return size
+ }
+
+ @JvmStatic
+ fun copyUriToInternalStorage(
+ context: Context,
+ sourceUri: Uri?,
+ destinationParentPath: String,
+ destinationFilename: String
+ ): Boolean {
+ var input: InputStream? = null
+ var output: FileOutputStream? = null
+ try {
+ input = context.contentResolver.openInputStream(sourceUri!!)
+ output = FileOutputStream("$destinationParentPath/$destinationFilename")
+ val buffer = ByteArray(1024)
+ var len: Int
+ while (input!!.read(buffer).also { len = it } != -1) {
+ output.write(buffer, 0, len)
+ }
+ output.flush()
+ return true
+ } catch (e: Exception) {
+ Log.error("[FileUtil]: Cannot copy file, error: " + e.message)
+ } finally {
+ if (input != null) {
+ try {
+ input.close()
+ } catch (e: IOException) {
+ Log.error("[FileUtil]: Cannot close input file, error: " + e.message)
+ }
+ }
+ if (output != null) {
+ try {
+ output.close()
+ } catch (e: IOException) {
+ Log.error("[FileUtil]: Cannot close output file, error: " + e.message)
+ }
+ }
+ }
+ return false
+ }
+
+ fun isRootTreeUri(uri: Uri): Boolean {
+ val paths = uri.pathSegments
+ return paths.size == 2 && PATH_TREE == paths[0]
+ }
+
+ fun closeQuietly(closeable: AutoCloseable?) {
+ if (closeable != null) {
+ try {
+ closeable.close()
+ } catch (rethrown: RuntimeException) {
+ throw rethrown
+ } catch (ignored: Exception) {
+ }
+ }
+ }
+}