mirror of
https://github.com/gopher64/gopher64.git
synced 2026-07-11 01:25:20 +02:00
+7
-5
@@ -352,7 +352,9 @@ fn android_main(app: slint::android::AndroidApp) {
|
||||
slint::android::init_with_event_listener(app.clone(), move |event| match event {
|
||||
slint::android::android_activity::PollEvent::Main(main_event) => match main_event {
|
||||
slint::android::android_activity::MainEvent::TerminateWindow { .. } => {
|
||||
if let Some(weak_app_window) = android::WEAK_SLINT_WINDOW.blocking_lock().as_ref() {
|
||||
if let Ok(weak_app_window) = android::WEAK_SLINT_WINDOW.lock()
|
||||
&& let Some(weak_app_window) = weak_app_window.as_ref()
|
||||
{
|
||||
weak_app_window
|
||||
.upgrade_in_event_loop(move |handle| {
|
||||
ui::gui::save_settings(&handle);
|
||||
@@ -367,9 +369,9 @@ fn android_main(app: slint::android::AndroidApp) {
|
||||
})
|
||||
.unwrap();
|
||||
let app_window = ui::gui::AppWindow::new().unwrap();
|
||||
*android::WEAK_SLINT_WINDOW.blocking_lock() = Some(app_window.as_weak());
|
||||
*android::WEAK_SLINT_WINDOW.lock().unwrap() = Some(app_window.as_weak());
|
||||
|
||||
*android::ANDROID_APP.blocking_lock() = Some(app);
|
||||
*android::ANDROID_APP.lock().unwrap() = Some(app);
|
||||
|
||||
let dirs = ui::get_dirs();
|
||||
|
||||
@@ -380,6 +382,6 @@ fn android_main(app: slint::android::AndroidApp) {
|
||||
|
||||
ui::gui::app_window(&app_window, true);
|
||||
close_tx.send(()).unwrap();
|
||||
*android::WEAK_SLINT_WINDOW.blocking_lock() = None;
|
||||
*android::ANDROID_APP.blocking_lock() = None;
|
||||
*android::WEAK_SLINT_WINDOW.lock().unwrap() = None;
|
||||
*android::ANDROID_APP.lock().unwrap() = None;
|
||||
}
|
||||
|
||||
+197
-182
@@ -13,15 +13,15 @@ const REQUEST_SELECT_ROM: jint = 1;
|
||||
const CONFIGURE_INPUT_PROFILE: jint = 2;
|
||||
const RUN_ROM: jint = 3;
|
||||
|
||||
pub static ANDROID_APP: tokio::sync::Mutex<Option<slint::android::AndroidApp>> =
|
||||
tokio::sync::Mutex::const_new(None);
|
||||
pub static ANDROID_APP: std::sync::Mutex<Option<slint::android::AndroidApp>> =
|
||||
std::sync::Mutex::new(None);
|
||||
|
||||
pub static SELECT_ROM_TX: tokio::sync::Mutex<
|
||||
Option<tokio::sync::oneshot::Sender<Option<std::path::PathBuf>>>,
|
||||
> = tokio::sync::Mutex::const_new(None);
|
||||
|
||||
pub static WEAK_SLINT_WINDOW: tokio::sync::Mutex<Option<slint::Weak<ui::gui::AppWindow>>> =
|
||||
tokio::sync::Mutex::const_new(None);
|
||||
pub static WEAK_SLINT_WINDOW: std::sync::Mutex<Option<slint::Weak<ui::gui::AppWindow>>> =
|
||||
std::sync::Mutex::new(None);
|
||||
|
||||
bind_java_type! {
|
||||
DocumentsContract => "android.provider.DocumentsContract",
|
||||
@@ -182,9 +182,17 @@ pub fn spawn_configure_input_profile(
|
||||
dinput: bool,
|
||||
deadzone: i32,
|
||||
) {
|
||||
if let Some(vm) = get_vm() {
|
||||
if let Err(err) = vm.attach_current_thread(|env| {
|
||||
start_configure_input_profile_on_jvm(env, profile_name.to_string(), dinput, deadzone)
|
||||
if let Ok(app) = ANDROID_APP.lock()
|
||||
&& let Some(app) = app.as_ref()
|
||||
{
|
||||
if let Err(err) = get_vm(app).attach_current_thread(|env| {
|
||||
start_configure_input_profile_on_jvm(
|
||||
env,
|
||||
app,
|
||||
profile_name.to_string(),
|
||||
dinput,
|
||||
deadzone,
|
||||
)
|
||||
}) {
|
||||
eprintln!("JNI error while starting N64Activity: {err:?}");
|
||||
}
|
||||
@@ -193,43 +201,40 @@ pub fn spawn_configure_input_profile(
|
||||
|
||||
fn start_configure_input_profile_on_jvm(
|
||||
env: &mut Env<'_>,
|
||||
app: &slint::android::AndroidApp,
|
||||
profile_name: String,
|
||||
dinput: bool,
|
||||
deadzone: i32,
|
||||
) -> jni::errors::Result<()> {
|
||||
if let Some(app) = ANDROID_APP.blocking_lock().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 raw_activity_global = app.activity_as_ptr() as jni::sys::jobject;
|
||||
let activity = unsafe { env.as_cast_raw::<Global<AndroidActivity>>(&raw_activity_global)? };
|
||||
|
||||
let package_name = JString::from_str(env, "io.github.gopher64.gopher64")?;
|
||||
let class_name = JString::from_str(env, "io.github.gopher64.gopher64.N64Activity")?;
|
||||
let package_name = JString::from_str(env, "io.github.gopher64.gopher64")?;
|
||||
let class_name = JString::from_str(env, "io.github.gopher64.gopher64.N64Activity")?;
|
||||
|
||||
let args_key = JString::from_str(env, "args")?;
|
||||
let mut args = vec![
|
||||
JString::from_str(env, "--configure-input-profile")?,
|
||||
JString::from_str(env, &profile_name)?,
|
||||
JString::from_str(env, "--deadzone")?,
|
||||
JString::from_str(env, &deadzone.to_string())?,
|
||||
];
|
||||
if dinput {
|
||||
args.push(JString::from_str(env, "--use-dinput")?);
|
||||
}
|
||||
let empty_arg = JString::from_str(env, "")?;
|
||||
let j_args = JObjectArray::<JString>::new(env, args.len(), empty_arg)?;
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
j_args.set_element(env, i, arg)?;
|
||||
}
|
||||
let intent = AndroidIntent::new(env)?
|
||||
.set_class_name(env, &package_name, &class_name)?
|
||||
.put_extra_string_array(env, &args_key, &j_args)?;
|
||||
|
||||
activity
|
||||
.as_ref()
|
||||
.start_activity_for_result(env, &intent, CONFIGURE_INPUT_PROFILE)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(jni::errors::Error::UninitializedJavaVM)
|
||||
let args_key = JString::from_str(env, "args")?;
|
||||
let mut args = vec![
|
||||
JString::from_str(env, "--configure-input-profile")?,
|
||||
JString::from_str(env, &profile_name)?,
|
||||
JString::from_str(env, "--deadzone")?,
|
||||
JString::from_str(env, &deadzone.to_string())?,
|
||||
];
|
||||
if dinput {
|
||||
args.push(JString::from_str(env, "--use-dinput")?);
|
||||
}
|
||||
let empty_arg = JString::from_str(env, "")?;
|
||||
let j_args = JObjectArray::<JString>::new(env, args.len(), empty_arg)?;
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
j_args.set_element(env, i, arg)?;
|
||||
}
|
||||
let intent = AndroidIntent::new(env)?
|
||||
.set_class_name(env, &package_name, &class_name)?
|
||||
.put_extra_string_array(env, &args_key, &j_args)?;
|
||||
|
||||
activity
|
||||
.as_ref()
|
||||
.start_activity_for_result(env, &intent, CONFIGURE_INPUT_PROFILE)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_rom(
|
||||
@@ -238,9 +243,11 @@ pub fn run_rom(
|
||||
netplay: Option<ui::gui::NetplayDevice>,
|
||||
weak: slint::Weak<ui::gui::AppWindow>,
|
||||
) {
|
||||
if let Some(vm) = get_vm() {
|
||||
if let Err(err) = vm.attach_current_thread(|env| {
|
||||
start_run_rom_on_jvm(env, file_path, game_settings, netplay, weak)
|
||||
if let Ok(app) = ANDROID_APP.lock()
|
||||
&& let Some(app) = app.as_ref()
|
||||
{
|
||||
if let Err(err) = get_vm(app).attach_current_thread(|env| {
|
||||
start_run_rom_on_jvm(env, app, file_path, game_settings, netplay, weak)
|
||||
}) {
|
||||
eprintln!("JNI error while starting N64Activity: {err:?}");
|
||||
}
|
||||
@@ -249,93 +256,88 @@ pub fn run_rom(
|
||||
|
||||
fn start_run_rom_on_jvm(
|
||||
env: &mut Env<'_>,
|
||||
app: &slint::android::AndroidApp,
|
||||
file_path: std::path::PathBuf,
|
||||
game_settings: ui::GameSettings,
|
||||
netplay: Option<ui::gui::NetplayDevice>,
|
||||
weak: slint::Weak<ui::gui::AppWindow>,
|
||||
) -> jni::errors::Result<()> {
|
||||
if let Some(app) = ANDROID_APP.blocking_lock().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 raw_activity_global = app.activity_as_ptr() as jni::sys::jobject;
|
||||
let activity = unsafe { env.as_cast_raw::<Global<AndroidActivity>>(&raw_activity_global)? };
|
||||
|
||||
let package_name = JString::from_str(env, "io.github.gopher64.gopher64")?;
|
||||
let class_name = JString::from_str(env, "io.github.gopher64.gopher64.N64Activity")?;
|
||||
let package_name = JString::from_str(env, "io.github.gopher64.gopher64")?;
|
||||
let class_name = JString::from_str(env, "io.github.gopher64.gopher64.N64Activity")?;
|
||||
|
||||
let file_path_key = JString::from_str(env, "file_path")?;
|
||||
let file_path = file_path.to_str().unwrap();
|
||||
let cheats_path_key = JString::from_str(env, "cheats_path")?;
|
||||
let cheats_path = app
|
||||
.internal_data_path()
|
||||
.unwrap()
|
||||
.join("cache")
|
||||
.join("cheats.json");
|
||||
let file_path_key = JString::from_str(env, "file_path")?;
|
||||
let file_path = file_path.to_str().unwrap();
|
||||
let cheats_path_key = JString::from_str(env, "cheats_path")?;
|
||||
let cheats_path = app
|
||||
.internal_data_path()
|
||||
.unwrap()
|
||||
.join("cache")
|
||||
.join("cheats.json");
|
||||
|
||||
let args_key = JString::from_str(env, "args")?;
|
||||
let mut args = vec![
|
||||
JString::from_str(env, file_path)?,
|
||||
JString::from_str(env, "--fullscreen")?,
|
||||
JString::from_str(env, "--overclock")?,
|
||||
JString::from_str(env, &game_settings.overclock.to_string())?,
|
||||
JString::from_str(env, "--disable-expansion-pak")?,
|
||||
JString::from_str(env, &game_settings.disable_expansion_pak.to_string())?,
|
||||
];
|
||||
let args_key = JString::from_str(env, "args")?;
|
||||
let mut args = vec![
|
||||
JString::from_str(env, file_path)?,
|
||||
JString::from_str(env, "--fullscreen")?,
|
||||
JString::from_str(env, "--overclock")?,
|
||||
JString::from_str(env, &game_settings.overclock.to_string())?,
|
||||
JString::from_str(env, "--disable-expansion-pak")?,
|
||||
JString::from_str(env, &game_settings.disable_expansion_pak.to_string())?,
|
||||
];
|
||||
|
||||
if let Some(netplay) = netplay {
|
||||
args.push(JString::from_str(env, "--netplay-server-addr")?);
|
||||
args.push(JString::from_str(env, &netplay.server_addr)?);
|
||||
args.push(JString::from_str(env, "--netplay-player-number")?);
|
||||
args.push(JString::from_str(env, &netplay.player_number.to_string())?);
|
||||
args.push(JString::from_str(env, "--netplay-number-of-players")?);
|
||||
args.push(JString::from_str(
|
||||
env,
|
||||
&netplay.number_of_players.to_string(),
|
||||
)?);
|
||||
args.push(JString::from_str(env, "--netplay-input-delay")?);
|
||||
args.push(JString::from_str(env, &netplay.input_delay.to_string())?);
|
||||
args.push(JString::from_str(env, "--cheats")?);
|
||||
args.push(JString::from_str(env, cheats_path.to_str().unwrap())?);
|
||||
if let Some(netplay) = netplay {
|
||||
args.push(JString::from_str(env, "--netplay-server-addr")?);
|
||||
args.push(JString::from_str(env, &netplay.server_addr)?);
|
||||
args.push(JString::from_str(env, "--netplay-player-number")?);
|
||||
args.push(JString::from_str(env, &netplay.player_number.to_string())?);
|
||||
args.push(JString::from_str(env, "--netplay-number-of-players")?);
|
||||
args.push(JString::from_str(
|
||||
env,
|
||||
&netplay.number_of_players.to_string(),
|
||||
)?);
|
||||
args.push(JString::from_str(env, "--netplay-input-delay")?);
|
||||
args.push(JString::from_str(env, &netplay.input_delay.to_string())?);
|
||||
args.push(JString::from_str(env, "--cheats")?);
|
||||
args.push(JString::from_str(env, cheats_path.to_str().unwrap())?);
|
||||
|
||||
let f = std::fs::File::create(&cheats_path).unwrap();
|
||||
serde_json::to_writer_pretty(f, &game_settings.cheats).unwrap();
|
||||
}
|
||||
|
||||
let empty_arg = JString::from_str(env, "")?;
|
||||
let j_args = JObjectArray::<JString>::new(env, args.len(), empty_arg)?;
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
j_args.set_element(env, i, arg)?;
|
||||
}
|
||||
|
||||
let file_path_string = JString::from_str(env, file_path)?;
|
||||
let cheats_path_string = JString::from_str(env, cheats_path.to_str().unwrap())?;
|
||||
let intent = AndroidIntent::new(env)?
|
||||
.set_class_name(env, &package_name, &class_name)?
|
||||
.put_extra_string(env, &file_path_key, &file_path_string)?
|
||||
.put_extra_string(env, &cheats_path_key, &cheats_path_string)?
|
||||
.put_extra_string_array(env, &args_key, &j_args)?;
|
||||
|
||||
weak.upgrade_in_event_loop(move |handle| handle.set_game_running(true))
|
||||
.unwrap();
|
||||
|
||||
activity
|
||||
.as_ref()
|
||||
.start_activity_for_result(env, &intent, RUN_ROM)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(jni::errors::Error::UninitializedJavaVM)
|
||||
let f = std::fs::File::create(&cheats_path).unwrap();
|
||||
serde_json::to_writer_pretty(f, &game_settings.cheats).unwrap();
|
||||
}
|
||||
|
||||
let empty_arg = JString::from_str(env, "")?;
|
||||
let j_args = JObjectArray::<JString>::new(env, args.len(), empty_arg)?;
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
j_args.set_element(env, i, arg)?;
|
||||
}
|
||||
|
||||
let file_path_string = JString::from_str(env, file_path)?;
|
||||
let cheats_path_string = JString::from_str(env, cheats_path.to_str().unwrap())?;
|
||||
let intent = AndroidIntent::new(env)?
|
||||
.set_class_name(env, &package_name, &class_name)?
|
||||
.put_extra_string(env, &file_path_key, &file_path_string)?
|
||||
.put_extra_string(env, &cheats_path_key, &cheats_path_string)?
|
||||
.put_extra_string_array(env, &args_key, &j_args)?;
|
||||
|
||||
weak.upgrade_in_event_loop(move |handle| handle.set_game_running(true))
|
||||
.unwrap();
|
||||
|
||||
activity
|
||||
.as_ref()
|
||||
.start_activity_for_result(env, &intent, RUN_ROM)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_vm() -> Option<JavaVM> {
|
||||
if let Some(app) = ANDROID_APP.blocking_lock().as_ref() {
|
||||
Some(unsafe { JavaVM::from_raw(app.vm_as_ptr().cast()) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
fn get_vm(app: &slint::android::AndroidApp) -> JavaVM {
|
||||
unsafe { JavaVM::from_raw(app.vm_as_ptr().cast()) }
|
||||
}
|
||||
|
||||
pub fn decode_path(path: &str) -> String {
|
||||
if let Some(vm) = get_vm() {
|
||||
match vm.attach_current_thread(|env| decode_path_on_jvm(env, path)) {
|
||||
if let Ok(app) = ANDROID_APP.lock()
|
||||
&& let Some(app) = app.as_ref()
|
||||
{
|
||||
match get_vm(app).attach_current_thread(|env| decode_path_on_jvm(env, path)) {
|
||||
Ok(decoded_path) => decoded_path,
|
||||
Err(err) => {
|
||||
eprintln!("JNI error while decoding path: {err:?}");
|
||||
@@ -356,8 +358,10 @@ fn decode_path_on_jvm(env: &mut Env<'_>, path: &str) -> jni::errors::Result<Stri
|
||||
|
||||
/// Lists connected gamepads and joysticks using the Android framework.
|
||||
pub fn list_controllers() -> Vec<ControllerInfo> {
|
||||
if let Some(vm) = get_vm() {
|
||||
match vm.attach_current_thread(list_controllers_on_jvm) {
|
||||
if let Ok(app) = ANDROID_APP.lock()
|
||||
&& let Some(app) = app.as_ref()
|
||||
{
|
||||
match get_vm(app).attach_current_thread(list_controllers_on_jvm) {
|
||||
Ok(controllers) => controllers,
|
||||
Err(err) => {
|
||||
eprintln!("JNI error while listing controllers: {err:?}");
|
||||
@@ -416,48 +420,53 @@ fn list_controllers_on_jvm(env: &mut Env<'_>) -> jni::errors::Result<Vec<Control
|
||||
|
||||
/// Opens a URI in the user's default app via [`Intent::ACTION_VIEW`](https://developer.android.com/reference/android/content/Intent#ACTION_VIEW).
|
||||
pub fn open_uri(path: &str) {
|
||||
if let Some(vm) = get_vm() {
|
||||
if let Ok(app) = ANDROID_APP.lock()
|
||||
&& let Some(app) = app.as_ref()
|
||||
{
|
||||
let path = path.to_string();
|
||||
if let Err(err) = vm.attach_current_thread(|env| open_uri_on_jvm(env, &path)) {
|
||||
if let Err(err) = get_vm(app).attach_current_thread(|env| open_uri_on_jvm(env, app, &path))
|
||||
{
|
||||
eprintln!("JNI error while opening URI: {err:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn open_uri_on_jvm(env: &mut Env<'_>, path: &str) -> jni::errors::Result<()> {
|
||||
if let Some(app) = ANDROID_APP.blocking_lock().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)? };
|
||||
fn open_uri_on_jvm(
|
||||
env: &mut Env<'_>,
|
||||
app: &slint::android::AndroidApp,
|
||||
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)?;
|
||||
let uri = AndroidUri::parse(env, &uri_string)?;
|
||||
let uri_string = JString::from_str(env, path)?;
|
||||
let uri = AndroidUri::parse(env, &uri_string)?;
|
||||
|
||||
let action_view = AndroidIntent::ACTION_VIEW(env)?;
|
||||
let intent = AndroidIntent::with_action(env, &action_view)?.set_data(env, &uri)?;
|
||||
let action_view = AndroidIntent::ACTION_VIEW(env)?;
|
||||
let intent = AndroidIntent::with_action(env, &action_view)?.set_data(env, &uri)?;
|
||||
|
||||
activity.as_ref().start_activity(env, &intent)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(jni::errors::Error::UninitializedJavaVM)
|
||||
}
|
||||
activity.as_ref().start_activity(env, &intent)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn select_rom(rom_dir: slint::SharedString) -> Option<std::path::PathBuf> {
|
||||
if let Some(vm) = get_vm() {
|
||||
if let Err(err) =
|
||||
vm.attach_current_thread(|env| select_rom_on_jvm(env, rom_dir.to_string()))
|
||||
if let Ok(app) = ANDROID_APP.lock()
|
||||
&& let Some(app) = app.as_ref()
|
||||
{
|
||||
if let Err(err) = get_vm(app)
|
||||
.attach_current_thread(|env| select_rom_on_jvm(env, app, rom_dir.to_string()))
|
||||
{
|
||||
eprintln!("JNI error while opening URI: {err:?}");
|
||||
return None;
|
||||
}
|
||||
let (tx, rx) = tokio::sync::oneshot::channel::<Option<std::path::PathBuf>>();
|
||||
SELECT_ROM_TX.lock().await.replace(tx);
|
||||
|
||||
rx.await.unwrap_or(None)
|
||||
} else {
|
||||
eprintln!("Android app not initialized");
|
||||
None
|
||||
return None;
|
||||
}
|
||||
let (tx, rx) = tokio::sync::oneshot::channel::<Option<std::path::PathBuf>>();
|
||||
SELECT_ROM_TX.lock().await.replace(tx);
|
||||
|
||||
rx.await.unwrap_or(None)
|
||||
}
|
||||
|
||||
pub async fn select_gb_rom(_player: i32) -> Option<std::path::PathBuf> {
|
||||
@@ -468,32 +477,34 @@ pub async fn select_gb_ram(_player: i32) -> Option<std::path::PathBuf> {
|
||||
select_rom(slint::SharedString::new()).await
|
||||
}
|
||||
|
||||
fn select_rom_on_jvm(env: &mut Env<'_>, rom_dir: String) -> jni::errors::Result<()> {
|
||||
if let Some(app) = ANDROID_APP.blocking_lock().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)? };
|
||||
fn select_rom_on_jvm(
|
||||
env: &mut Env<'_>,
|
||||
app: &slint::android::AndroidApp,
|
||||
rom_dir: String,
|
||||
) -> 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 action = AndroidIntent::ACTION_OPEN_DOCUMENT(env)?;
|
||||
let category = AndroidIntent::CATEGORY_OPENABLE(env)?;
|
||||
let mime_type = JString::from_str(env, "*/*")?;
|
||||
let mut intent = AndroidIntent::with_action(env, &action)?
|
||||
.set_type(env, &mime_type)?
|
||||
.add_category(env, &category)?;
|
||||
if !rom_dir.is_empty() {
|
||||
let start_dir = JString::from_str(env, rom_dir)?;
|
||||
let extra_initial_uri = DocumentsContract::EXTRA_INITIAL_URI(env)?;
|
||||
intent = intent.put_extra_string(env, &extra_initial_uri, &start_dir)?;
|
||||
}
|
||||
|
||||
activity.start_activity_for_result(env, &intent, REQUEST_SELECT_ROM)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(jni::errors::Error::UninitializedJavaVM)
|
||||
let action = AndroidIntent::ACTION_OPEN_DOCUMENT(env)?;
|
||||
let category = AndroidIntent::CATEGORY_OPENABLE(env)?;
|
||||
let mime_type = JString::from_str(env, "*/*")?;
|
||||
let mut intent = AndroidIntent::with_action(env, &action)?
|
||||
.set_type(env, &mime_type)?
|
||||
.add_category(env, &category)?;
|
||||
if !rom_dir.is_empty() {
|
||||
let start_dir = JString::from_str(env, rom_dir)?;
|
||||
let extra_initial_uri = DocumentsContract::EXTRA_INITIAL_URI(env)?;
|
||||
intent = intent.put_extra_string(env, &extra_initial_uri, &start_dir)?;
|
||||
}
|
||||
|
||||
activity.start_activity_for_result(env, &intent, REQUEST_SELECT_ROM)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_dirs() -> ui::Dirs {
|
||||
if let Some(app) = ANDROID_APP.blocking_lock().as_ref() {
|
||||
if let Ok(app) = ANDROID_APP.lock()
|
||||
&& let Some(app) = app.as_ref()
|
||||
{
|
||||
ui::Dirs {
|
||||
config_dir: app.internal_data_path().unwrap().join("config"),
|
||||
data_dir: app.external_data_path().unwrap().join("data"),
|
||||
@@ -524,9 +535,11 @@ pub fn rom_exists(path: &str) -> bool {
|
||||
}
|
||||
|
||||
pub fn get_file_from_uri(path: &std::path::PathBuf) -> Option<std::fs::File> {
|
||||
if let Some(vm) = get_vm() {
|
||||
if let Ok(app) = ANDROID_APP.lock()
|
||||
&& let Some(app) = app.as_ref()
|
||||
{
|
||||
let path = path.to_str().unwrap().into();
|
||||
match vm.attach_current_thread(|env| get_file_from_uri_on_jvm(env, path)) {
|
||||
match get_vm(app).attach_current_thread(|env| get_file_from_uri_on_jvm(env, app, path)) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
eprintln!("JNI error while opening URI: {err:?}");
|
||||
@@ -541,30 +554,26 @@ pub fn get_file_from_uri(path: &std::path::PathBuf) -> Option<std::fs::File> {
|
||||
|
||||
fn get_file_from_uri_on_jvm(
|
||||
env: &mut Env<'_>,
|
||||
app: &slint::android::AndroidApp,
|
||||
path: String,
|
||||
) -> jni::errors::Result<Option<std::fs::File>> {
|
||||
if let Some(app) = ANDROID_APP.blocking_lock().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 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()
|
||||
{
|
||||
let owned_fd = unsafe { std::os::fd::OwnedFd::from_raw_fd(descriptor.detach_fd(env)?) };
|
||||
let file = std::fs::File::from(owned_fd);
|
||||
descriptor.close(env)?;
|
||||
return Ok(Some(file));
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
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()
|
||||
{
|
||||
let owned_fd = unsafe { std::os::fd::OwnedFd::from_raw_fd(descriptor.detach_fd(env)?) };
|
||||
let file = std::fs::File::from(owned_fd);
|
||||
descriptor.close(env)?;
|
||||
return Ok(Some(file));
|
||||
} else {
|
||||
eprintln!("Android app not initialized");
|
||||
return Err(jni::errors::Error::UninitializedJavaVM);
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,7 +602,9 @@ pub extern "system" fn Java_io_github_gopher64_gopher64_SlintActivity_nativeOnAc
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(app) = ANDROID_APP.blocking_lock().as_ref() {
|
||||
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)?
|
||||
@@ -614,7 +625,9 @@ pub extern "system" fn Java_io_github_gopher64_gopher64_SlintActivity_nativeOnAc
|
||||
}
|
||||
}
|
||||
CONFIGURE_INPUT_PROFILE => {
|
||||
if let Some(weak_app_window) = WEAK_SLINT_WINDOW.blocking_lock().as_ref() {
|
||||
if let Ok(weak_app_window) = WEAK_SLINT_WINDOW.lock()
|
||||
&& let Some(weak_app_window) = weak_app_window.as_ref()
|
||||
{
|
||||
let config = ui::config::Config::new();
|
||||
ui::gui::update_input_profiles(&weak_app_window, &config);
|
||||
}
|
||||
@@ -636,7 +649,9 @@ pub extern "system" fn Java_io_github_gopher64_gopher64_SlintActivity_nativeOnAc
|
||||
{
|
||||
let _ = std::fs::remove_file(cheats_path);
|
||||
}
|
||||
if let Some(weak_app_window) = WEAK_SLINT_WINDOW.blocking_lock().as_ref() {
|
||||
if let Ok(weak_app_window) = WEAK_SLINT_WINDOW.lock()
|
||||
&& let Some(weak_app_window) = weak_app_window.as_ref()
|
||||
{
|
||||
weak_app_window
|
||||
.upgrade_in_event_loop(move |handle| {
|
||||
ui::gui::update_recent_roms(&handle, file_path.into());
|
||||
|
||||
Reference in New Issue
Block a user