diff --git a/platforms/android/app/src/main/AndroidManifest.xml b/platforms/android/app/src/main/AndroidManifest.xml
index f3e11030ca..f5a0365856 100644
--- a/platforms/android/app/src/main/AndroidManifest.xml
+++ b/platforms/android/app/src/main/AndroidManifest.xml
@@ -24,6 +24,17 @@
+
+
+
+
+
+
0 ? displayName.substring(0, dot) : displayName;
+ final String extension = dot > 0 ? displayName.substring(dot) : "";
+ for (int i = 1; i < 100; ++i) {
+ file = new File(parent, baseName + " (" + i + ")" + extension);
+ if (!file.exists()) {
+ return file;
+ }
+ }
+ return new File(parent, baseName + " (" + System.currentTimeMillis() + ")" + extension);
+ }
+
+ private static int modeToParcelMode(String mode) {
+ if ("r".equals(mode)) {
+ return ParcelFileDescriptor.MODE_READ_ONLY;
+ }
+ if ("w".equals(mode) || "wt".equals(mode)) {
+ return ParcelFileDescriptor.MODE_WRITE_ONLY |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE;
+ }
+ if ("wa".equals(mode)) {
+ return ParcelFileDescriptor.MODE_WRITE_ONLY |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_APPEND;
+ }
+ if ("rw".equals(mode)) {
+ return ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE;
+ }
+ if ("rwt".equals(mode)) {
+ return ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE;
+ }
+ return ParcelFileDescriptor.MODE_READ_ONLY;
+ }
+
+ private static String getMimeType(File file) {
+ final int dot = file.getName().lastIndexOf('.');
+ if (dot >= 0) {
+ final String extension = file.getName().substring(dot + 1).toLowerCase();
+ final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ if (mimeType != null) {
+ return mimeType;
+ }
+ }
+ return "application/octet-stream";
+ }
+
+ private static void deleteRecursively(File file) throws FileNotFoundException {
+ if (file.isDirectory()) {
+ final File[] children = file.listFiles();
+ if (children != null) {
+ for (File child : children) {
+ deleteRecursively(child);
+ }
+ }
+ }
+ if (!file.delete()) {
+ throw new FileNotFoundException("Unable to delete document: " + file);
+ }
+ }
+
+ private static boolean isInside(File parent, File child) {
+ try {
+ final String parentPath = canonicalPath(parent);
+ final String childPath = canonicalPath(child);
+ return childPath.equals(parentPath) || childPath.startsWith(parentPath + File.separator);
+ } catch (FileNotFoundException e) {
+ return false;
+ }
+ }
+
+ private static boolean sameFile(File a, File b) {
+ try {
+ return canonicalPath(a).equals(canonicalPath(b));
+ } catch (FileNotFoundException e) {
+ return false;
+ }
+ }
+
+ private static String canonicalPath(File file) throws FileNotFoundException {
+ try {
+ return file.getCanonicalPath();
+ } catch (IOException e) {
+ throw asFileNotFound("Unable to resolve path", e);
+ }
+ }
+
+ private static FileNotFoundException asFileNotFound(String message, IOException cause) {
+ final FileNotFoundException exception = new FileNotFoundException(message + ": " + cause.getMessage());
+ exception.initCause(cause);
+ return exception;
+ }
+}
diff --git a/platforms/android/app/src/main/res/values/strings.xml b/platforms/android/app/src/main/res/values/strings.xml
index 79d8812b82..752dae76bf 100644
--- a/platforms/android/app/src/main/res/values/strings.xml
+++ b/platforms/android/app/src/main/res/values/strings.xml
@@ -1,4 +1,6 @@
Dusk
+ Dusk Data
+ Saves, texture packs, settings, and logs