diff --git a/android-project/app/src/main/AndroidManifest.xml b/android-project/app/src/main/AndroidManifest.xml index 4b84b02..e3061a1 100644 --- a/android-project/app/src/main/AndroidManifest.xml +++ b/android-project/app/src/main/AndroidManifest.xml @@ -5,6 +5,8 @@ + + diff --git a/src/device/controller/gbcart.rs b/src/device/controller/gbcart.rs index 8ee0cc5..318b460 100644 --- a/src/device/controller/gbcart.rs +++ b/src/device/controller/gbcart.rs @@ -80,6 +80,9 @@ pub fn save( elapsed_time: i64, ram_path: &std::string::String, ) { + if cfg!(target_os = "android") { + return; + } update_rtc_regs(gb_cart, elapsed_time); if let Ok(file) = std::fs::File::create(ram_path) { diff --git a/src/ui/android.rs b/src/ui/android.rs index 2cbdae7..129864f 100644 --- a/src/ui/android.rs +++ b/src/ui/android.rs @@ -68,13 +68,22 @@ bind_java_type! { }, } +bind_java_type! { + ParcelFileDescriptor => "android.os.ParcelFileDescriptor", + methods { + fn close() -> (), + }, +} + bind_java_type! { AndroidContentResolver => "android.content.ContentResolver", type_map = { AndroidUri => "android.net.Uri", + ParcelFileDescriptor => "android.os.ParcelFileDescriptor", }, methods { fn take_persistable_uri_permission(uri: AndroidUri, flags: jint) -> (), + fn open_file_descriptor(uri: AndroidUri, mode: JString) -> ParcelFileDescriptor, }, } @@ -160,11 +169,9 @@ fn list_controllers_on_jvm(env: &mut Env<'_>) -> jni::errors::Result, path: &str) -> jni::errors::Result<()> { let raw_activity_global = app.activity_as_ptr() as jni::sys::jobject; let activity = unsafe { env.as_cast_raw::>(&raw_activity_global)? }; - let uri_string = JString::from_str(env, path.to_string())?; + let uri_string = JString::from_str(env, path)?; let uri = AndroidUri::parse(env, &uri_string)?; let action_view = AndroidIntent::ACTION_VIEW(env)?; @@ -305,6 +312,50 @@ pub fn get_dirs() -> ui::Dirs { } } +pub fn rom_exists(path: &str) -> bool { + let path = path.to_string(); + + let vm = if let Ok(app) = ANDROID_APP.lock() + && let Some(app) = app.as_ref() + { + unsafe { JavaVM::from_raw(app.vm_as_ptr().cast()) } + } else { + eprintln!("Android app not initialized"); + return false; + }; + if let Err(err) = vm.attach_current_thread(|env| rom_exists_on_jvm(env, path)) { + eprintln!("JNI error while opening URI: {err:?}"); + return false; + } + true +} + +fn rom_exists_on_jvm(env: &mut Env<'_>, path: String) -> jni::errors::Result<()> { + if let Ok(app) = ANDROID_APP.lock() + && let Some(app) = app.as_ref() + { + let raw_activity_global = app.activity_as_ptr() as jni::sys::jobject; + let activity = unsafe { env.as_cast_raw::>(&raw_activity_global)? }; + let path = JString::from_str(env, path)?; + let mode = JString::from_str(env, "r")?; + let uri = AndroidUri::parse(env, &path)?; + + let content_resolver = activity.as_ref().get_content_resolver(env)?; + let parcel_file_descriptor = content_resolver.open_file_descriptor(env, &uri, &mode); + if let Ok(descriptor) = parcel_file_descriptor + && !descriptor.is_null() + { + descriptor.close(env)?; + return Ok(()); + } else { + return Err(jni::errors::Error::ObjectFreed); + } + } else { + eprintln!("Android app not initialized"); + return Err(jni::errors::Error::UninitializedJavaVM); + } +} + #[unsafe(no_mangle)] pub extern "system" fn Java_io_github_gopher64_gopher64_SlintActivity_nativeOnActivityResult< 'caller, diff --git a/src/ui/gui.rs b/src/ui/gui.rs index da541d5..8bb9ed9 100644 --- a/src/ui/gui.rs +++ b/src/ui/gui.rs @@ -1,4 +1,6 @@ use crate::ui; +#[cfg(target_os = "android")] +use crate::ui::android; use slint::Model; #[cfg(not(target_os = "android"))] use slint::winit_030::WinitWindowAccessor; @@ -93,13 +95,20 @@ fn file_dropped(app: &AppWindow) { }); } +fn rom_exists(path: &str) -> bool { + #[cfg(not(target_os = "android"))] + return std::fs::exists(path).unwrap_or(false); + #[cfg(target_os = "android")] + return android::rom_exists(path); +} + fn local_game_window(app: &AppWindow, config: &ui::config::Config) { app.set_recent_roms(slint::ModelRc::from(std::rc::Rc::new( slint::VecModel::from( config .recent_roms .iter() - .filter(|x| std::fs::exists(x).unwrap_or(false)) + .filter(|x| rom_exists(x)) .map(|x| { ( x.into(), @@ -585,7 +594,7 @@ pub fn run_rom( for rom in handle.get_recent_roms().iter() { if rom.0 != file_path.to_str().unwrap() && recent_roms.row_count() < 5 - && std::fs::exists(&rom.0).unwrap_or(false) + && rom_exists(&rom.0) { recent_roms.push(rom); }