Skip to content

Commit

Permalink
Add from_java() constructors to InputQueue, KeyEvent and `Motio…
Browse files Browse the repository at this point in the history
…nEvent` (#456)

* ndk/input_queue: Add API-33 `from_java()` constructor

* ndk/event: Add API-31 `from_java()` constructors to `KeyEvent` and `MotionEvent`
  • Loading branch information
MarijnS95 committed Jan 27, 2024
1 parent 2d269e1 commit 12eb049
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 6 deletions.
2 changes: 2 additions & 0 deletions ndk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

- Move `MediaFormat` from `media::media_codec` to its own `media::media_format` module. (#442)
- media_format: Expose `MediaFormat::copy()` and `MediaFormat::clear()` from API level 29. (#449)
- input_queue: Add `from_java()` constructor, available since API level 33. (#456)
- event: Add `from_java()` constructors to `KeyEvent` and `MotionEvent`, available since API level 31. (#456)

# 0.8.0 (2023-10-15)

Expand Down
4 changes: 3 additions & 1 deletion ndk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ rust-version = "1.66"

[features]
default = ["rwh_06"]
all = ["audio", "bitmap", "media", "sync", "api-level-31", "rwh_04", "rwh_05", "rwh_06"]
all = ["audio", "bitmap", "media", "sync", "api-level-33", "rwh_04", "rwh_05", "rwh_06"]

audio = ["ffi/audio", "api-level-26"]
bitmap = ["ffi/bitmap"]
Expand All @@ -30,6 +30,8 @@ api-level-28 = ["api-level-27"]
api-level-29 = ["api-level-28"]
api-level-30 = ["api-level-29"]
api-level-31 = ["api-level-30"]
api-level-32 = ["api-level-31"]
api-level-33 = ["api-level-32"]

test = ["ffi/test", "jni", "all"]

Expand Down
73 changes: 68 additions & 5 deletions ndk/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
//! [`android.view.KeyEvent`].
//!
//! [`AInputEvent`, `AKeyEvent` and `AMotionEvent`]: https://developer.android.com/ndk/reference/group/input
//! [`android.view.InputEvent`]: https://developer.android.com/reference/android/view/InputEvent.html
//! [`android.view.MotionEvent`]: https://developer.android.com/reference/android/view/MotionEvent.html
//! [`android.view.InputEvent`]: https://developer.android.com/reference/android/view/InputEvent
//! [`android.view.MotionEvent`]: https://developer.android.com/reference/android/view/MotionEvent
//! [`android.view.KeyEvent`]: https://developer.android.com/reference/android/view/KeyEvent

use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::ptr::NonNull;

#[cfg(feature = "api-level-31")]
use jni_sys::{jobject, JNIEnv};
use num_enum::{IntoPrimitive, TryFromPrimitive};

/// A native [`AInputEvent *`]
///
/// [`AInputEvent *`]: https://developer.android.com/ndk/reference/group/input#ainputevent
Expand All @@ -22,6 +25,28 @@ pub enum InputEvent {
KeyEvent(KeyEvent),
}

/// Wraps a Java [`InputEvent`] acquired from [`KeyEvent::from_java()`] or
/// [`MotionEvent::from_java()`] with respective [`Drop`] semantics.
#[cfg(feature = "api-level-31")]
#[derive(Debug)]
pub struct InputEventJava(InputEvent);

#[cfg(feature = "api-level-31")]
impl Drop for InputEventJava {
/// Releases interface objects created by [`KeyEvent::from_java()`] or
/// [`MotionEvent::from_java()`].
///
/// The underlying Java object remains valid and does not change its state.
#[doc(alias = "AInputEvent_release")]
fn drop(&mut self) {
let ptr = match self.0 {
InputEvent::MotionEvent(MotionEvent { ptr })
| InputEvent::KeyEvent(KeyEvent { ptr }) => ptr.as_ptr().cast(),
};
unsafe { ffi::AInputEvent_release(ptr) }
}
}

/// An enum representing the source of an [`InputEvent`].
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-36)
Expand Down Expand Up @@ -373,7 +398,26 @@ impl MotionEvent {
Self { ptr }
}

/// Returns a pointer to the native [`ffi::AInputEvent`]
/// Creates a native [`InputEvent`] object that is a copy of the specified
/// Java [`android.view.MotionEvent`]. The result may be used with generic and
/// [`MotionEvent`]-specific functions.
///
/// # Safety
///
/// This function should be called with a healthy JVM pointer and with a non-null
/// [`android.view.MotionEvent`].
///
/// [`android.view.MotionEvent`]: https://developer.android.com/reference/android/view/MotionEvent
#[cfg(feature = "api-level-31")]
#[doc(alias = "AMotionEvent_fromJava")]
pub unsafe fn from_java(env: *mut JNIEnv, key_event: jobject) -> Option<InputEventJava> {
let ptr = unsafe { ffi::AMotionEvent_fromJava(env, key_event) };
Some(InputEventJava(InputEvent::MotionEvent(Self::from_ptr(
NonNull::new(ptr.cast_mut())?,
))))
}

/// Returns a pointer to the native [`ffi::AInputEvent`].
#[inline]
pub fn ptr(&self) -> NonNull<ffi::AInputEvent> {
self.ptr
Expand Down Expand Up @@ -1342,7 +1386,26 @@ impl KeyEvent {
Self { ptr }
}

/// Returns a pointer to the native [`ffi::AInputEvent`]
/// Creates a native [`InputEvent`] object that is a copy of the specified Java
/// [`android.view.KeyEvent`]. The result may be used with generic and [`KeyEvent`]-specific
/// functions.
///
/// # Safety
///
/// This function should be called with a healthy JVM pointer and with a non-null
/// [`android.view.KeyEvent`].
///
/// [`android.view.KeyEvent`]: https://developer.android.com/reference/android/view/KeyEvent
#[cfg(feature = "api-level-31")]
#[doc(alias = "AKeyEvent_fromJava")]
pub unsafe fn from_java(env: *mut JNIEnv, key_event: jobject) -> Option<InputEventJava> {
let ptr = unsafe { ffi::AKeyEvent_fromJava(env, key_event) };
Some(InputEventJava(InputEvent::KeyEvent(Self::from_ptr(
NonNull::new(ptr.cast_mut())?,
))))
}

/// Returns a pointer to the native [`ffi::AInputEvent`].
#[inline]
pub fn ptr(&self) -> NonNull<ffi::AInputEvent> {
self.ptr
Expand Down
24 changes: 24 additions & 0 deletions ndk/src/input_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use std::io::Result;
use std::os::raw::c_int;
use std::ptr::{self, NonNull};

#[cfg(feature = "api-level-33")]
use jni_sys::{jobject, JNIEnv};

use crate::event::InputEvent;
#[cfg(doc)]
use crate::event::KeyEvent;
Expand Down Expand Up @@ -35,6 +38,27 @@ impl InputQueue {
Self { ptr }
}

/// Returns the [`InputQueue`] object associated with the supplied
/// [Java `InputQueue`][`android.view.InputQueue`] object.
///
/// # Safety
///
/// This function should be called with a healthy JVM pointer and with a non-null
/// [`android.view.InputQueue`], which must be kept alive on the Java/Kotlin side.
///
/// The returned native object holds a weak reference to the Java object, and is only valid as
/// long as the Java object has not yet been disposed. You should ensure that there is a strong
/// reference to the Java object and that it has not been disposed before using the returned
/// object.
///
/// [`android.view.InputQueue`]: https://developer.android.com/reference/android/view/InputQueue
#[cfg(feature = "api-level-33")]
#[doc(alias = "AInputQueue_fromJava")]
pub unsafe fn from_java(env: *mut JNIEnv, input_queue: jobject) -> Option<Self> {
let ptr = unsafe { ffi::AInputQueue_fromJava(env, input_queue) };
Some(Self::from_ptr(NonNull::new(ptr)?))
}

pub fn ptr(&self) -> NonNull<ffi::AInputQueue> {
self.ptr
}
Expand Down

0 comments on commit 12eb049

Please sign in to comment.