From 9af1681a136f021b34033618f72f68503ec9014b Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sat, 23 Dec 2023 19:52:50 +0100 Subject: [PATCH 1/2] ndk/input_queue: Add API-33 `from_java()` constructor --- ndk/CHANGELOG.md | 1 + ndk/Cargo.toml | 4 +++- ndk/src/input_queue.rs | 24 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/ndk/CHANGELOG.md b/ndk/CHANGELOG.md index 73093f48..c9de67c8 100644 --- a/ndk/CHANGELOG.md +++ b/ndk/CHANGELOG.md @@ -2,6 +2,7 @@ - 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) # 0.8.0 (2023-10-15) diff --git a/ndk/Cargo.toml b/ndk/Cargo.toml index 167547a3..f71a0911 100644 --- a/ndk/Cargo.toml +++ b/ndk/Cargo.toml @@ -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"] @@ -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"] diff --git a/ndk/src/input_queue.rs b/ndk/src/input_queue.rs index 91d2f01f..0fae5f11 100644 --- a/ndk/src/input_queue.rs +++ b/ndk/src/input_queue.rs @@ -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; @@ -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 { + let ptr = unsafe { ffi::AInputQueue_fromJava(env, input_queue) }; + Some(Self::from_ptr(NonNull::new(ptr)?)) + } + pub fn ptr(&self) -> NonNull { self.ptr } From 6ab211dc55a929fb8d80cce0dc1e9f3368d74523 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sat, 23 Dec 2023 20:10:41 +0100 Subject: [PATCH 2/2] ndk/event: Add API-31 `from_java()` constructors to `KeyEvent` and `MotionEvent` --- ndk/CHANGELOG.md | 1 + ndk/src/event.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/ndk/CHANGELOG.md b/ndk/CHANGELOG.md index c9de67c8..8d6bf15a 100644 --- a/ndk/CHANGELOG.md +++ b/ndk/CHANGELOG.md @@ -3,6 +3,7 @@ - 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) diff --git a/ndk/src/event.rs b/ndk/src/event.rs index a985f461..7bec3a9f 100644 --- a/ndk/src/event.rs +++ b/ndk/src/event.rs @@ -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 @@ -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) @@ -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 { + 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 { self.ptr @@ -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 { + 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 { self.ptr