From 9af1681a136f021b34033618f72f68503ec9014b Mon Sep 17 00:00:00 2001
From: Marijn Suijten <marijn@traverseresearch.nl>
Date: Sat, 23 Dec 2023 19:52:50 +0100
Subject: [PATCH] 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<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
     }