/
lib.rs
113 lines (106 loc) · 4.06 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Provides a stable api to rust crates for interfacing with the Android platform. It is
//! initialized by the runtime, usually [__ndk-glue__](https://crates.io/crates/ndk-glue),
//! but could also be initialized by Java or Kotlin code when embedding in an existing Android
//! project.
//!
//! ```no_run
//! # use jni::objects::JObject;
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let ctx = ndk_context::android_context();
//! let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }?;
//! let context = unsafe { JObject::from_raw(ctx.context().cast()) };
//! let env = vm.attach_current_thread()?;
//! let class_ctx = env.find_class("android/content/Context")?;
//! let audio_service = env.get_static_field(class_ctx, "AUDIO_SERVICE", "Ljava/lang/String;")?;
//! let audio_manager = env
//! .call_method(
//! context,
//! "getSystemService",
//! "(Ljava/lang/String;)Ljava/lang/Object;",
//! &[audio_service],
//! )?
//! .l()?;
//! # Ok(())
//! # }
//! ```
use std::ffi::c_void;
static mut ANDROID_CONTEXT: Option<AndroidContext> = None;
/// [`AndroidContext`] provides the pointers required to interface with the jni on Android
/// platforms.
#[derive(Clone, Copy, Debug)]
pub struct AndroidContext {
java_vm: *mut c_void,
context_jobject: *mut c_void,
}
impl AndroidContext {
/// A handle to the `JavaVM` object.
///
/// Usage with [__jni__](https://crates.io/crates/jni) crate:
/// ```no_run
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let ctx = ndk_context::android_context();
/// let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }?;
/// let env = vm.attach_current_thread();
/// # Ok(())
/// # }
/// ```
pub fn vm(self) -> *mut c_void {
self.java_vm
}
/// A handle to an [android.content.Context](https://developer.android.com/reference/android/content/Context).
/// In most cases this will be a ptr to an `Activity`, but this isn't guaranteed.
///
/// Usage with [__jni__](https://crates.io/crates/jni) crate:
/// ```no_run
/// # use jni::objects::JObject;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let ctx = ndk_context::android_context();
/// let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }?;
/// let context = unsafe { JObject::from_raw(ctx.context().cast()) };
/// let env = vm.attach_current_thread()?;
/// let class_ctx = env.find_class("android/content/Context")?;
/// let audio_service = env.get_static_field(class_ctx, "AUDIO_SERVICE", "Ljava/lang/String;")?;
/// let audio_manager = env
/// .call_method(
/// context,
/// "getSystemService",
/// "(Ljava/lang/String;)Ljava/lang/Object;",
/// &[audio_service],
/// )?
/// .l()?;
/// # Ok(())
/// # }
/// ```
pub fn context(self) -> *mut c_void {
self.context_jobject
}
}
/// Main entry point to this crate. Returns an [`AndroidContext`].
pub fn android_context() -> AndroidContext {
unsafe { ANDROID_CONTEXT.expect("android context was not initialized") }
}
/// Initializes the [`AndroidContext`]. [`AndroidContext`] is initialized by [__ndk-glue__](https://crates.io/crates/ndk-glue)
/// before `main` is called.
///
/// # Safety
///
/// The pointers must be valid and this function must be called exactly once before `main` is
/// called.
pub unsafe fn initialize_android_context(java_vm: *mut c_void, context_jobject: *mut c_void) {
let previous = ANDROID_CONTEXT.replace(AndroidContext {
java_vm,
context_jobject,
});
assert!(previous.is_none());
}
/// Removes the [`AndroidContext`]. It is released by [__ndk-glue__](https://crates.io/crates/ndk-glue)
/// when the activity is finished and destroyed.
///
/// # Safety
///
/// This function must only be called after [`initialize_android_context()`],
/// when the activity is subsequently destroyed according to Android.
pub unsafe fn release_android_context() {
let previous = ANDROID_CONTEXT.take();
assert!(previous.is_some());
}