use std::{
cell::RefCell,
ops::Deref,
rc::Rc,
sync::{atomic::AtomicBool, Arc},
};
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<Platform> for AppRef<'a> {
fn terminate(&self) {
}
fn proxy(&self) -> Option<AppProxy> {
with_app(|vars| {
if let Some(sender) = vars.sender.clone() {
Some(AppProxy(vars.proxy.clone(), sender))
} else {
None
}
})
}
}
pub struct AppHandle(&'static JEnv, JRc<android::app::Application>);
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<ndkm::Assets> {
with_app(|app| app.assets.clone())
}
}
impl types::AppHandle<Platform> for AppHandle {
fn singleton() -> Option<Self> {
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(<Platform as types::Platform>::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<dyn types::AppDelegate<Platform>>;
pub struct App {
delegate: Option<RcDynAppDelegate>,
assets: Option<ndkm::Assets>,
_assets_java: Option<JRc<android::content::res::AssetManager>>,
application: Option<JRc<android::app::Application>>,
proxy: Arc<AtomicBool>,
sender: Option<ndkm::Sender<i64>>,
recver: Option<(Rc<AppCmd>, ndkm::LooperGuard<AppCmd>)>,
}
thread_local! {
static CACHE:RefCell<App> = RefCell::new(App {
delegate: None,
assets: None,
_assets_java:None,
application:None,
proxy:Arc::new(AtomicBool::new(false)),
sender:None,
recver:None,
});
}
pub(super) fn set_delegate(delegate: RcDynAppDelegate) {
CACHE.with_borrow_mut(|cache| cache.delegate = Some(delegate))
}
fn with_app_mut<T>(mut fun: impl FnMut(&mut App) -> Option<T>) -> Option<T> {
CACHE.with_borrow_mut(|app| fun(app))
}
fn with_app<T>(mut fun: impl FnMut(&App) -> Option<T>) -> Option<T> {
CACHE.with_borrow(|app| fun(app))
}