mirror of
https://github.com/gopher64/gopher64.git
synced 2026-11-03 13:00:44 +01:00
don't hold android app reference (#922)
* don't hold android app reference * more * more
This commit is contained in:
1 parent
e852439b6a
commit
28b1424357
5 files changed
+37
-34
No files matched your search
Generated
+1
@@ -2249,6 +2249,7 @@ dependencies = [
|
||||
"futures",
|
||||
"jni 0.22.4",
|
||||
"mimalloc",
|
||||
"ndk-context",
|
||||
"open",
|
||||
"postcard",
|
||||
"rand 0.10.1",
|
||||
|
||||
@@ -47,6 +47,7 @@ open = { version = "5.3", optional = true }
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
slint = { version = "1.16", default-features = false, features = ["compat-1-2", "std", "backend-android-activity-06", "accessibility"], optional = true }
|
||||
jni = "0.22"
|
||||
ndk-context = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
winresource = "0.1"
|
||||
|
||||
+10
-1
@@ -9,6 +9,9 @@ mod ui;
|
||||
use clap::Parser;
|
||||
use std::io::Error;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
use ui::android;
|
||||
|
||||
/// N64 emulator
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version=env!("GIT_DESCRIBE"), about, long_about = None, arg_required_else_help = if cfg!(feature = "gui") { false } else { true })]
|
||||
@@ -308,7 +311,13 @@ pub async fn run() -> std::io::Result<()> {
|
||||
async fn android_main(app: slint::android::AndroidApp) {
|
||||
slint::android::init(app.clone()).unwrap();
|
||||
|
||||
ui::ANDROID_APP.set(app).unwrap();
|
||||
if let Err(_) = android::DIRS.set(ui::Dirs {
|
||||
config_dir: app.internal_data_path().unwrap().join("config"),
|
||||
data_dir: app.external_data_path().unwrap().join("data"),
|
||||
cache_dir: app.internal_data_path().unwrap().join("cache"),
|
||||
}) {
|
||||
println!("Android dirs already set");
|
||||
}
|
||||
|
||||
let dirs = ui::get_dirs();
|
||||
|
||||
|
||||
@@ -17,10 +17,6 @@ pub mod video;
|
||||
#[cfg(feature = "gui")]
|
||||
pub mod vru;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub static ANDROID_APP: std::sync::OnceLock<slint::android::AndroidApp> =
|
||||
std::sync::OnceLock::new();
|
||||
|
||||
pub static WEB_CLIENT: std::sync::LazyLock<reqwest::Client> = std::sync::LazyLock::new(|| {
|
||||
reqwest::Client::builder()
|
||||
.user_agent(format!(
|
||||
@@ -32,6 +28,7 @@ pub static WEB_CLIENT: std::sync::LazyLock<reqwest::Client> = std::sync::LazyLoc
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Dirs {
|
||||
pub config_dir: std::path::PathBuf,
|
||||
pub data_dir: std::path::PathBuf,
|
||||
@@ -153,12 +150,8 @@ pub fn get_dirs() -> Dirs {
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn get_dirs() -> Dirs {
|
||||
if let Some(android_app) = ANDROID_APP.get() {
|
||||
Dirs {
|
||||
config_dir: android_app.internal_data_path().unwrap().join("config"),
|
||||
data_dir: android_app.external_data_path().unwrap().join("data"),
|
||||
cache_dir: android_app.internal_data_path().unwrap().join("cache"),
|
||||
}
|
||||
if let Some(android_dirs) = android::DIRS.get() {
|
||||
android_dirs.clone()
|
||||
} else {
|
||||
panic!("Android app not initialized");
|
||||
}
|
||||
|
||||
+22
-23
@@ -3,9 +3,10 @@ use jni::refs::Global;
|
||||
use jni::{Env, JavaVM, bind_java_type};
|
||||
|
||||
use crate::ui;
|
||||
pub static DIRS: std::sync::OnceLock<ui::Dirs> = std::sync::OnceLock::new();
|
||||
|
||||
bind_java_type! {
|
||||
AndroidActivity => "android.app.Activity",
|
||||
AndroidContext => "android.content.Context",
|
||||
type_map = {
|
||||
AndroidIntent => "android.content.Intent",
|
||||
},
|
||||
@@ -22,12 +23,15 @@ bind_java_type! {
|
||||
fields {
|
||||
#[allow(non_snake_case)]
|
||||
static ACTION_VIEW: JString,
|
||||
#[allow(non_snake_case)]
|
||||
static FLAG_ACTIVITY_NEW_TASK: jint,
|
||||
},
|
||||
constructors {
|
||||
fn new(action: JString),
|
||||
},
|
||||
methods {
|
||||
fn set_data(uri: AndroidUri) -> AndroidIntent,
|
||||
fn add_flags(flags: jint) -> AndroidIntent,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -68,12 +72,9 @@ pub struct ControllerInfo {
|
||||
|
||||
/// Lists connected gamepads and joysticks using the Android framework.
|
||||
pub fn list_controllers() -> Vec<ControllerInfo> {
|
||||
let Some(app) = ui::ANDROID_APP.get() else {
|
||||
eprintln!("Android app not initialized; cannot list controllers");
|
||||
return Vec::new();
|
||||
};
|
||||
let ctx = ndk_context::android_context();
|
||||
|
||||
let vm = unsafe { JavaVM::from_raw(app.vm_as_ptr().cast()) };
|
||||
let vm = unsafe { JavaVM::from_raw(ctx.vm().cast()) };
|
||||
|
||||
match vm.attach_current_thread(list_controllers_on_jvm) {
|
||||
Ok(controllers) => controllers,
|
||||
@@ -145,35 +146,33 @@ 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) {
|
||||
let Some(app) = ui::ANDROID_APP.get() else {
|
||||
eprintln!("Android app not initialized; cannot open URI");
|
||||
return;
|
||||
};
|
||||
let ctx = ndk_context::android_context();
|
||||
|
||||
let path = path.to_string();
|
||||
app.clone().run_on_java_main_thread(Box::new(move || {
|
||||
let vm = unsafe { JavaVM::from_raw(app.vm_as_ptr().cast()) };
|
||||
if let Err(err) = vm.attach_current_thread(|env| open_uri_on_java_main(env, &app, &path)) {
|
||||
eprintln!("JNI error while opening URI: {err:?}");
|
||||
}
|
||||
}));
|
||||
|
||||
let vm = unsafe { JavaVM::from_raw(ctx.vm().cast()) };
|
||||
if let Err(err) = vm.attach_current_thread(|env| open_uri_on_jvm(env, ctx.context(), &path)) {
|
||||
eprintln!("JNI error while opening URI: {err:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn open_uri_on_java_main(
|
||||
fn open_uri_on_jvm(
|
||||
env: &mut Env<'_>,
|
||||
app: &slint::android::AndroidApp,
|
||||
context: *mut std::ffi::c_void,
|
||||
path: &str,
|
||||
) -> jni::errors::Result<()> {
|
||||
let activity_ptr = app.activity_as_ptr().cast();
|
||||
let activity = unsafe { env.as_cast_raw::<Global<AndroidActivity>>(&activity_ptr)? };
|
||||
let context_ptr = context.cast();
|
||||
let context = unsafe { env.as_cast_raw::<Global<AndroidContext>>(&context_ptr)? };
|
||||
|
||||
let uri_string = JString::from_str(env, path.to_string())?;
|
||||
let uri = AndroidUri::parse(env, &uri_string)?;
|
||||
|
||||
let action_view = AndroidIntent::ACTION_VIEW(env)?;
|
||||
let intent = AndroidIntent::new(env, &action_view)?;
|
||||
intent.set_data(env, &uri)?;
|
||||
let flag = AndroidIntent::FLAG_ACTIVITY_NEW_TASK(env)?;
|
||||
let intent = AndroidIntent::new(env, &action_view)?
|
||||
.set_data(env, &uri)?
|
||||
.add_flags(env, flag)?;
|
||||
|
||||
activity.as_ref().start_activity(env, &intent)?;
|
||||
context.as_ref().start_activity(env, &intent)?;
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user