Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ndk-context. #223

Merged
merged 17 commits into from
Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"ndk",
"ndk-context",
"ndk-macro",
"ndk-build",
"ndk-examples",
Expand Down
6 changes: 6 additions & 0 deletions ndk-context/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "ndk-context"
version = "0.1.0"
edition = "2021"

[dependencies]
86 changes: 86 additions & 0 deletions ndk-context/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//! 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.
MarijnS95 marked this conversation as resolved.
Show resolved Hide resolved
//!
//! ```no_run
//! let ctx = ndk_context::android_context();
//! let vm = unsafe { jni::JavaVM::from_raw(ctx.vm() as *mut jni::sys::JavaVM) }?;
//! 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(
//! ctx.context() as jni::sys::jobject,
//! "getSystemService",
//! "(Ljava/lang/String;)Ljava/lang/Object;",
//! &[audio_service],
//! )?
//! .l()?;
//! ```
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
/// let ctx = ndk_context::android_context();
/// let vm = unsafe { jni::JavaVM::from_raw(ctx.vm() as *mut jni::sys::JavaVM) }?;
/// let env = vm.attach_current_thread();
/// ```
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
/// let ctx = ndk_context::android_context();
/// let vm = unsafe { jni::JavaVM::from_raw(ctx.vm() as *mut jni::sys::JavaVM) }?;
/// 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(
/// ctx.context() as jni::sys::jobject,
/// "getSystemService",
/// "(Ljava/lang/String;)Ljava/lang/Object;",
/// &[audio_service],
/// )?
/// .l()?;
/// ```
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 initialized") }
dvc94ch marked this conversation as resolved.
Show resolved Hide resolved
}

/// Initializes the [`AndroidContext`]. [`AndroidContext`] is initialized by `ndk-glue` before
dvc94ch marked this conversation as resolved.
Show resolved Hide resolved
/// main is called.
///
/// # Safety
///
/// The pointers need to be valid.
pub unsafe fn initialize_android_context(java_vm: *mut c_void, context_jobject: *mut c_void) {
dvc94ch marked this conversation as resolved.
Show resolved Hide resolved
ANDROID_CONTEXT = Some(AndroidContext {
java_vm,
context_jobject,
});
}
1 change: 1 addition & 0 deletions ndk-examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jni = "0.18.0"
libc = "0.2"
log = "0.4.14"
ndk = { path = "../ndk", features = ["trace"] }
ndk-context = { path = "../ndk-context" }
ndk-glue = { path = "../ndk-glue", features = ["logger"] }

[[example]]
Expand Down
7 changes: 3 additions & 4 deletions ndk-examples/examples/jni_audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ const GET_DEVICES_OUTPUTS: jni::sys::jint = 2;

fn enumerate_audio_devices() -> Result<(), Box<dyn std::error::Error>> {
// Create a VM for executing Java calls
let native_activity = ndk_glue::native_activity();
let vm_ptr = native_activity.vm();
let vm = unsafe { jni::JavaVM::from_raw(vm_ptr) }?;
let ctx = ndk_context::android_context();
let vm = unsafe { jni::JavaVM::from_raw(ctx.vm() as *mut jni::sys::JavaVM) }?;
dvc94ch marked this conversation as resolved.
Show resolved Hide resolved
let env = vm.attach_current_thread()?;

// Query the global Audio Service
Expand All @@ -18,7 +17,7 @@ fn enumerate_audio_devices() -> Result<(), Box<dyn std::error::Error>> {

let audio_manager = env
.call_method(
native_activity.activity(),
ctx.context() as jni::sys::jobject,
dvc94ch marked this conversation as resolved.
Show resolved Hide resolved
"getSystemService",
// JNI type signature needs to be derived from the Java API
// (ArgTys)ResultTy
Expand Down
3 changes: 2 additions & 1 deletion ndk-glue/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ repository = "https://github.com/rust-windowing/android-ndk-rs"

[dependencies]
ndk = { path = "../ndk", version = "0.6.0" }
ndk-sys = { path = "../ndk-sys", version = "0.3.0" }
ndk-context = { path = "../ndk-context", version = "0.1.0" }
ndk-macro = { path = "../ndk-macro", version = "0.3.0" }
ndk-sys = { path = "../ndk-sys", version = "0.3.0" }
lazy_static = "1.4.0"
libc = "0.2.84"
log = "0.4.14"
Expand Down
4 changes: 4 additions & 0 deletions ndk-glue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ pub unsafe fn init(
callbacks.onLowMemory = Some(on_low_memory);

let activity = NativeActivity::from_ptr(activity);
ndk_context::initialize_android_context(
activity.vm() as *mut std::ffi::c_void,
activity.activity() as *mut std::ffi::c_void,
dvc94ch marked this conversation as resolved.
Show resolved Hide resolved
);
NATIVE_ACTIVITY = Some(activity);

let mut logpipe: [RawFd; 2] = Default::default();
Expand Down