check file exists on android (#934)

* check file exists on android

* more

* more

* more
This commit is contained in:
Logan McNaughton 2026-05-22 09:43:20 +02:00 committed by GitHub
parent 66a74b5693
commit 82c22dc18e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 73 additions and 8 deletions

View File

@ -5,6 +5,8 @@
<uses-feature android:name="android.hardware.vulkan.version" android:required="true"
android:version="0x00401000" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@mipmap/ic_launcher"
android:label="Gopher64">

View File

@ -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) {

View File

@ -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<Vec<Control
continue;
}
if !device.supports_source(env, source_gamepad)? {
continue;
}
if !device.supports_source(env, source_joystick)? {
let supports_gamepad = device.supports_source(env, source_gamepad)?;
let supports_joystick = device.supports_source(env, source_joystick)?;
if !supports_gamepad && !supports_joystick {
continue;
}
@ -221,7 +228,7 @@ fn open_uri_on_jvm(env: &mut Env<'_>, path: &str) -> jni::errors::Result<()> {
let raw_activity_global = app.activity_as_ptr() as jni::sys::jobject;
let activity = unsafe { env.as_cast_raw::<Global<AndroidActivity>>(&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::<Global<AndroidActivity>>(&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,

View File

@ -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);
}