1use jni::{JavaVM, jni_sig, jni_str, objects::JObject};
4use std::{ffi::c_void, sync::Mutex};
5
6static mut ANDROID_APPLICATION_CONTEXT: Option<AndroidContext> = None;
7static ANDROID_CONTEXTS: Mutex<Vec<AndroidContext>> = Mutex::new(vec![]);
10
11#[derive(Clone, Copy, Debug)]
14pub struct AndroidContext {
15 java_vm: *mut c_void,
16 context_jobject: *mut c_void,
17}
18unsafe impl Send for AndroidContext {}
19unsafe impl Sync for AndroidContext {}
20
21pub fn add_activity(java_vm: *mut c_void, activity_ptr: *mut c_void) {
22 let vm = unsafe { JavaVM::from_raw(java_vm.cast()) };
23 vm.attach_current_thread(|env| -> jni::errors::Result<()> {
24 let activity = unsafe { JObject::from_raw(env, activity_ptr.cast()) };
25 let app_context = env
26 .call_method(
27 activity,
28 jni_str!("getApplicationContext"),
29 jni_sig!(() -> android.context.Context),
30 &[],
31 )?
32 .l()?;
33
34 if let Some(c) = unsafe { ANDROID_APPLICATION_CONTEXT } {
35 assert_eq!(c.java_vm, java_vm);
36 assert_eq!(c.context_jobject, app_context.as_raw().cast());
37 } else {
38 unsafe {
39 ANDROID_APPLICATION_CONTEXT = Some(AndroidContext {
40 java_vm,
41 context_jobject: app_context.as_raw().cast(),
42 })
43 };
44 }
45
46 Ok(())
47 })
48 .unwrap();
49
50 ANDROID_CONTEXTS.lock().unwrap().push(AndroidContext {
52 java_vm,
53 context_jobject: activity_ptr,
54 });
55}
56
57pub fn remove_activity(activity_ptr: *mut c_void) {
58 let mut contexts = ANDROID_CONTEXTS.lock().unwrap();
59 let index = contexts
60 .iter()
61 .position(|c| c.context_jobject == activity_ptr)
62 .expect("Android activity does not exist");
63 contexts.remove(index);
64}
65
66pub fn android_app_context() -> AndroidContext {
70 unsafe { ANDROID_APPLICATION_CONTEXT }.expect("No Android applications were ever registered")
71}
72
73pub fn activities() -> Vec<AndroidContext> {
77 ANDROID_CONTEXTS.lock().unwrap().clone()
78}