use std::{cell::RefCell, ops::Deref, rc::Rc}; use jnim::*; use super::android; use super::Platform; mod proxy; pub use proxy::*; #[derive(Clone, Copy)] pub struct AppRef<'a>(pub &'a ()); impl<'a> types::AppRef for AppRef<'a> { fn terminate(&self) { // not surport // or send terminate message } fn proxy(&self) -> Option { with_app(|vars| { if let Some(sender) = vars.sender.clone() { Some(AppProxy(sender)) } else { None } }) } } pub struct AppHandle(&'static JEnv, JRc); impl Deref for AppHandle { type Target = android::app::Application; fn deref(&self) -> &Self::Target { &self.1 } } impl AppHandle { pub fn env(&self) -> &'static JEnv { self.0 } pub fn assets() -> Option { with_app(|app| app.assets.clone()) } pub fn assets_java(env: &JEnv) -> Option> { with_app(|app| { if let Some(aj) = &app.assets_java { return aj.clone(env); } None }) } } impl types::AppHandle for AppHandle { fn singleton() -> Option { with_app(|app| { let env: &'static JEnv = JEnv::env(None)?; let app = app.application.as_ref()?; Some(AppHandle(env, app.global(env)?)) }) } fn with(&self, mut fun: impl FnMut(::AppRef<'_>)) { fun(AppRef(&())) } } pub fn application_launched() { with_app_mut(|vars| { let (sender, recver) = ndkm::pipe(); let fd = recver.fd_read; let cmd = Rc::new(AppCmd(recver)); let recver = ndkm::Looper::current()?.add(fd, &cmd).ok()?; vars.recver = Some((cmd, recver)); vars.sender = Some(sender); Some(()) }); with_app(|app| { app.delegate.as_ref()?.on_launch(AppRef(&())); Some(()) }); } pub fn application_terminate() { with_app(|app| { app.delegate.as_ref()?.on_terminate(AppRef(&())); Some(()) }); with_app_mut(|vars| { vars.sender = None; vars.recver = None; vars.delegate = None; vars.assets = None; vars.assets_java = None; Some(()) }); } pub(crate) fn bind_global_if_need(env: &JEnv, application: Option<&android::app::Application>) { let Some(application) = application else { return; }; with_app_mut(|app| { if app.application.is_none() { app.application = application.global(env); let assets_java = application.get_assets(env)?; app.assets_java = assets_java.global(env); let assets = Some(ndkm::Assets::from_java(env.as_sys(), assets_java.as_sys())); app.assets = assets; } Some(()) }); } pub type RcDynAppDelegate = Rc>; pub struct App { delegate: Option, assets: Option, assets_java: Option>, application: Option>, sender: Option>, recver: Option<(Rc, ndkm::LooperGuard)>, } thread_local! { static CACHE:RefCell = RefCell::new(App { delegate: None, assets: None, assets_java:None, application:None, sender:None, recver:None, }); } pub(super) fn set_delegate(delegate: RcDynAppDelegate) { CACHE.with_borrow_mut(|cache| cache.delegate = Some(delegate)) } fn with_app_mut(mut fun: impl FnMut(&mut App) -> Option) -> Option { CACHE.with_borrow_mut(|app| fun(app)) } fn with_app(mut fun: impl FnMut(&App) -> Option) -> Option { CACHE.with_borrow(|app| fun(app)) }