diff --git a/app/app/src/main/java/io/github/doukutsu_rs/DoukutsuDocumentsProvider.java b/app/app/src/main/java/io/github/doukutsu_rs/DoukutsuDocumentsProvider.java index 9802e54..8b7d4ed 100644 --- a/app/app/src/main/java/io/github/doukutsu_rs/DoukutsuDocumentsProvider.java +++ b/app/app/src/main/java/io/github/doukutsu_rs/DoukutsuDocumentsProvider.java @@ -10,16 +10,20 @@ import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; +import android.provider.DocumentsContract.Path; import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; import android.util.Log; import android.webkit.MimeTypeMap; + import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; +import java.util.LinkedList; import static android.os.Build.VERSION.SDK_INT; @@ -175,6 +179,29 @@ public class DoukutsuDocumentsProvider extends DocumentsProvider { } } + @Override + @RequiresApi(Build.VERSION_CODES.O) + public Path findDocumentPath(@Nullable String parentDocumentId, String childDocumentId) throws FileNotFoundException { + if (parentDocumentId == null) { + parentDocumentId = getContext().getFilesDir().getAbsolutePath(); + } + + File childFile = new File(childDocumentId); + if (!childFile.exists()) { + throw new FileNotFoundException(childFile.getAbsolutePath()+" doesn't exist"); + } else if (!isChildDocument(parentDocumentId, childDocumentId)) { + throw new FileNotFoundException(childDocumentId+" is not child of "+parentDocumentId); + } + + LinkedList path = new LinkedList<>(); + while (childFile != null && isChildDocument(parentDocumentId, childFile.getAbsolutePath())) { + path.addFirst(childFile.getAbsolutePath()); + childFile = childFile.getParentFile(); + } + + return new Path(parentDocumentId, path); + } + @Override public String getDocumentType(String documentId) throws FileNotFoundException { File file = new File(documentId); diff --git a/app/app/src/main/java/io/github/doukutsu_rs/GameActivity.java b/app/app/src/main/java/io/github/doukutsu_rs/GameActivity.java index 01347af..2471e99 100644 --- a/app/app/src/main/java/io/github/doukutsu_rs/GameActivity.java +++ b/app/app/src/main/java/io/github/doukutsu_rs/GameActivity.java @@ -1,14 +1,17 @@ package io.github.doukutsu_rs; -import android.app.AlertDialog; import android.app.NativeActivity; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.res.Configuration; import android.hardware.SensorManager; +import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.provider.DocumentsContract; import android.view.OrientationEventListener; import android.view.WindowInsets; +import android.widget.Toast; import java.io.File; @@ -87,7 +90,27 @@ public class GameActivity extends NativeActivity { this.displayInsets[2] = Math.max(this.displayInsets[0], cutout.getSafeInsetRight()); this.displayInsets[3] = Math.max(this.displayInsets[0], cutout.getSafeInsetBottom()); } + } + } + public void openDir(String path) { + Uri uri = DocumentsContract.buildDocumentUri(BuildConfig.DOCUMENTS_AUTHORITY, path); + + File file = new File(path); + if (!file.isDirectory()) { + Toast.makeText(getApplicationContext(), R.string.dir_not_found, Toast.LENGTH_LONG).show(); + return; + } + + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setDataAndType(uri, DocumentsContract.Document.MIME_TYPE_DIR); + intent.setFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + + try { + startActivity(intent); + } catch(ActivityNotFoundException e) { + Toast.makeText(getApplicationContext(), R.string.no_app_found_to_open_dir, Toast.LENGTH_LONG).show(); } } } diff --git a/app/app/src/main/res/values/strings.xml b/app/app/src/main/res/values/strings.xml index b835211..f1bfda1 100644 --- a/app/app/src/main/res/values/strings.xml +++ b/app/app/src/main/res/values/strings.xml @@ -6,7 +6,7 @@ No data files found, would you like to download them? Bad HTTP response code: %d - + Downloading %1$s… %2$d%% (%3$d/%4$d KiB, %5$d KiB/s) Downloading %1$s… --%% (%2$d KiB, %3$d KiB/s) Unpacking: %s @@ -14,4 +14,7 @@ base game files + + Dir not found + No app found to open dir diff --git a/src/framework/backend_glutin.rs b/src/framework/backend_glutin.rs index de629ae..49564db 100644 --- a/src/framework/backend_glutin.rs +++ b/src/framework/backend_glutin.rs @@ -147,7 +147,6 @@ fn get_insets() -> GameResult<(f32, f32, f32, f32)> { let vm = JavaVM::from_raw(vm_ptr)?; let vm_env = vm.attach_current_thread()?; - //let class = vm_env.find_class("io/github/doukutsu_rs/MainActivity")?; let class = vm_env.new_global_ref(JObject::from_raw(ndk_glue::native_activity().activity()))?; let field = vm_env.get_field(class.as_obj(), "displayInsets", "[I")?.to_jni().l as jni::sys::jintArray; @@ -155,11 +154,11 @@ fn get_insets() -> GameResult<(f32, f32, f32, f32)> { vm_env.get_int_array_region(field, 0, &mut elements)?; vm_env.delete_local_ref(JObject::from_raw(field)); - + //Game always runs with horizontal orientation so top and bottom cutouts not needed and only wastes piece of the screen elements[1] = 0; elements[3] = 0; - + Ok((elements[0] as f32, elements[1] as f32, elements[2] as f32, elements[3] as f32)) } } diff --git a/src/game/filesystem_container.rs b/src/game/filesystem_container.rs index bd6776d..e788ecf 100644 --- a/src/game/filesystem_container.rs +++ b/src/game/filesystem_container.rs @@ -196,7 +196,21 @@ impl FilesystemContainer { return Ok(()); // can't open directories on switch #[cfg(target_os = "android")] - return Ok(()); // TODO: figure out how to do this on android + unsafe { + use jni::objects::{JObject, JValue}; + use jni::JavaVM; + + let vm_ptr = ndk_glue::native_activity().vm(); + let vm = JavaVM::from_raw(vm_ptr)?; + let vm_env = vm.attach_current_thread()?; + + let class = vm_env.new_global_ref(JObject::from_raw(ndk_glue::native_activity().activity()))?; + let method = vm_env.call_method(class.as_obj(), "openDir", "(Ljava/lang/String;)V", &[ + JValue::from(vm_env.new_string(path.to_str().unwrap()).unwrap()) + ])?; + + return Ok(()); + } #[cfg(not(any(target_os = "android", target_os = "horizon")))] open::that(path).map_err(|e| { diff --git a/src/menu/settings_menu.rs b/src/menu/settings_menu.rs index c6e67b8..7392c5a 100644 --- a/src/menu/settings_menu.rs +++ b/src/menu/settings_menu.rs @@ -392,7 +392,7 @@ impl SettingsMenu { ); self.links.push_entry(LinksMenuEntry::Link(GETPLUS_LINK), MenuEntry::Active("Get Cave Story+".to_owned())); - #[cfg(not(any(target_os = "android", target_os = "horizon")))] + #[cfg(not(any(target_os = "horizon")))] self.main.push_entry( MainMenuEntry::Advanced, MenuEntry::Active(state.loc.t("menus.options_menu.advanced").to_owned()),