makepad_android_state/lib.rs
1//! The crate responsible for holding Makepad's Android-specific context states.
2//!
3//! These two states are:
4//! 1. The JavaVM instance initialized by the JNI layer.
5//! * This cannot be set by foreign code outside this crate,
6//! as it is only ever set once during the lifetime of the app process.
7//! 2. The current Makepad Activity instance.
8//! * This *can* be set by foreign code outside this crate,
9//! as the underlying Android platform may tear down and reconstruct
10//! the activity instance multiple times during the app's lifetime.
11//! * However, for safety reasons, we only permit a single caller
12//! to obtain the private "set_activity" function, which ensures that
13//! only the internal Makepad framework can set the activity instance.
14//!
15//! ## Usage
16//! You probably want to use the [`robius-android-env`] crate instead of
17//! using this crate directly.
18//!
19//! External users of this crate should only care about two functions:
20//! 1. [`get_java_vm()`]: returns a pointer to the JavaVM instance,
21//! through which you can obtain the JNI environment.
22//! 2. [`get_activity()`]: returns a pointer to the current Makepad Activity instance.
23//!
24//! The other functions are intended for Makepad-internal use only,
25//! and will not be useful for external users.
26//!
27//! [`robius-android-env`]: https://github.com/project-robius/robius-android-env
28
29use std::sync::Mutex;
30use makepad_jni_sys as jni_sys;
31
32static mut ACTIVITY: jni_sys::jobject = std::ptr::null_mut();
33static mut VM: *mut jni_sys::JavaVM = std::ptr::null_mut();
34
35static SET_ACTIVITY_FN: Mutex<Option<unsafe fn(jni_sys::jobject)>> = {
36 unsafe fn set_activity(activity: jni_sys::jobject) {
37 ACTIVITY = activity;
38 }
39
40 std::sync::Mutex::new(Some(set_activity))
41};
42
43/// Returns a function that can be used to set the current Makepad Activity instance.
44///
45/// This will return `Some` only once, which guarantees that only the
46/// internal Makepad framework can obtain the function to set the activity instance.
47#[doc(hidden)]
48pub fn get_activity_setter_fn() -> Option<unsafe fn(jni_sys::jobject)> {
49 SET_ACTIVITY_FN.lock().unwrap().take()
50}
51
52#[no_mangle]
53#[doc(hidden)]
54pub unsafe extern "C" fn JNI_OnLoad(
55 vm: *mut jni_sys::JavaVM,
56 _: std::ffi::c_void,
57) -> jni_sys::jint {
58 VM = vm as *mut _ as _;
59
60 jni_sys::JNI_VERSION_1_6 as _
61}
62
63#[no_mangle]
64extern "C" fn jni_on_load(vm: *mut std::ffi::c_void) {
65 unsafe {
66 VM = vm as _;
67 }
68}
69
70/// Returns a raw pointer to the JavaVM instance initialized by the JNI layer.
71///
72/// If the JavaVM instance has not been initialized, this returns a null pointer.
73#[inline(always)]
74pub fn get_java_vm() -> *mut jni_sys::JavaVM {
75 // SAFETY: just returning a raw pointer.
76 unsafe { VM }
77}
78
79/// Returns a raw pointer to the main Makepad Activity instance.
80///
81/// Note that the caller should not cache or re-use the returned activity pointer,
82/// but should instead re-call this function whenever the activity instance is needed.
83/// This is because the activity instance may be destroyed and recreated behind the scenes
84/// upon certain system actions, e.g., when the device is rotated,
85/// the app is put into split screen, resized/moved, etc.
86///
87/// If the Activity instance has not been initialized, this returns a null pointer.
88#[inline(always)]
89pub fn get_activity() -> jni_sys::jobject {
90 // SAFETY: just returning a raw pointer.
91 unsafe { ACTIVITY }
92}