From f2d36eded8abb01618b877b80705b2b0baa72e17 Mon Sep 17 00:00:00 2001 From: Arnold Loubriat Date: Tue, 15 Sep 2026 22:55:51 +0200 Subject: [PATCH] fix: Make the Android injecting adapter usable from any thread --- adapters/android/src/inject.rs | 135 +++++++++++++++++---------------- 1 file changed, 70 insertions(+), 65 deletions(-) diff --git a/adapters/android/src/inject.rs b/adapters/android/src/inject.rs index 81f0d9257..5b369972b 100644 --- a/adapters/android/src/inject.rs +++ b/adapters/android/src/inject.rs @@ -94,6 +94,10 @@ fn inner_adapter_from_handle(handle: jlong) -> Option TreeUpdate) { - let mut env = self.vm.get_env().unwrap(); - let Some(host) = self.host.upgrade_local(&env).unwrap() else { - return; - }; - let mut inner = self.inner.lock().unwrap(); - let Some(events) = inner.adapter.update_if_active(update_factory) else { - return; - }; - drop(inner); - post_to_ui_thread( - &mut env, - self.delegate_class, - &host, - |env, _delegate_class, host| { - events.raise(env, host); - }, - ); - } -} - -impl Drop for InjectingAdapter { - fn drop(&mut self) { - fn drop_impl(env: &mut JNIEnv, delegate_class: &JClass, host: &WeakRef) -> Result<()> { - let Some(host) = host.upgrade_local(env)? else { + let mut env = self.vm.attach_current_thread().unwrap(); + env.with_local_frame(LOCAL_FRAME_CAPACITY, |env| -> Result<()> { + let Some(host) = self.host.upgrade_local(env)? else { return Ok(()); }; - post_to_ui_thread(env, delegate_class, &host, |env, delegate_class, host| { - let prev_delegate = env - .call_method( - host, - "getAccessibilityDelegate", - "()Landroid/view/View$AccessibilityDelegate;", - &[], - ) - .unwrap() - .l() - .unwrap(); - if prev_delegate.is_null() - && !env.is_instance_of(&prev_delegate, delegate_class).unwrap() - { - return; - } - let null = JObject::null(); - env.call_method( - host, - "setAccessibilityDelegate", - "(Landroid/view/View$AccessibilityDelegate;)V", - &[(&null).into()], - ) - .unwrap(); - env.call_method( - host, - "setOnHoverListener", - "(Landroid/view/View$OnHoverListener;)V", - &[(&null).into()], - ) - .unwrap(); - }); + let mut inner = self.inner.lock().unwrap(); + let Some(events) = inner.adapter.update_if_active(update_factory) else { + return Ok(()); + }; + drop(inner); + post_to_ui_thread( + env, + self.delegate_class, + &host, + |env, _delegate_class, host| { + events.raise(env, host); + }, + ); Ok(()) - } + }) + .unwrap(); + } +} - let res = match self.vm.get_env() { - Ok(mut env) => drop_impl(&mut env, self.delegate_class, &self.host), - Err(_) => self - .vm - .attach_current_thread() - .and_then(|mut env| drop_impl(&mut env, self.delegate_class, &self.host)), - }; +fn uninstall_delegate(env: &mut JNIEnv, delegate_class: &JClass, host: &JObject) { + let prev_delegate = env + .call_method( + host, + "getAccessibilityDelegate", + "()Landroid/view/View$AccessibilityDelegate;", + &[], + ) + .unwrap() + .l() + .unwrap(); + if prev_delegate.is_null() || !env.is_instance_of(&prev_delegate, delegate_class).unwrap() { + return; + } + let null = JObject::null(); + env.call_method( + host, + "setAccessibilityDelegate", + "(Landroid/view/View$AccessibilityDelegate;)V", + &[(&null).into()], + ) + .unwrap(); + env.call_method( + host, + "setOnHoverListener", + "(Landroid/view/View$OnHoverListener;)V", + &[(&null).into()], + ) + .unwrap(); +} +impl Drop for InjectingAdapter { + fn drop(&mut self) { + let res = self.vm.attach_current_thread().and_then(|mut env| { + env.with_local_frame(LOCAL_FRAME_CAPACITY, |env| { + let Some(host) = self.host.upgrade_local(env)? else { + return Ok(()); + }; + post_to_ui_thread(env, self.delegate_class, &host, uninstall_delegate); + Ok(()) + }) + }); if let Err(err) = res { debug!("error dropping InjectingAdapter: {:#?}", err); } - HANDLE_MAP.lock().unwrap().remove(&self.handle); } }