|
1 | | -/// 通过 JNI 设置 Android 软键盘的显示状态 |
2 | 1 | #[cfg(android)] |
3 | 2 | pub fn set_soft_input_visible(visible: bool) { |
| 3 | + if let Err(err) = rust_set_soft_input_visible(visible) { |
| 4 | + log::error!("Failed to set soft input visible ({}): {:?}", visible, err); |
| 5 | + } |
| 6 | +} |
| 7 | + |
| 8 | +#[cfg(android)] |
| 9 | +fn rust_set_soft_input_visible(visible: bool) -> jni::errors::Result<()> { |
4 | 10 | use jni::JavaVM; |
5 | 11 | use jni::objects::JObject; |
6 | 12 |
|
7 | 13 | let ctx = ndk_context::android_context(); |
8 | | - let vm = match unsafe { JavaVM::from_raw(ctx.vm().cast()) } { |
9 | | - Ok(vm) => vm, |
10 | | - Err(err) => { |
11 | | - eprintln!("Failed to get JavaVM: {err}"); |
12 | | - return; |
13 | | - } |
14 | | - }; |
15 | | - let mut env = match vm.attach_current_thread() { |
16 | | - Ok(env) => env, |
17 | | - Err(err) => { |
18 | | - eprintln!("Failed to attach thread: {err}"); |
19 | | - return; |
20 | | - } |
21 | | - }; |
| 14 | + let vm = unsafe { JavaVM::from_raw(ctx.vm().cast()) }?; |
| 15 | + let mut env = vm.attach_current_thread()?; |
22 | 16 | let activity = unsafe { JObject::from_raw(ctx.context().cast()) }; |
23 | 17 |
|
24 | | - // InputMethodManager |
25 | | - let imm_service_name = match env.new_string("input_method") { |
26 | | - Ok(value) => value, |
27 | | - Err(err) => { |
28 | | - eprintln!("Failed to create IMM service name: {err}"); |
29 | | - return; |
30 | | - } |
31 | | - }; |
32 | | - let imm = match env.call_method( |
33 | | - &activity, |
34 | | - "getSystemService", |
35 | | - "(Ljava/lang/String;)Ljava/lang/Object;", |
36 | | - &[(&imm_service_name).into()], |
37 | | - ) { |
38 | | - Ok(value) => match value.l() { |
39 | | - Ok(obj) => obj, |
40 | | - Err(err) => { |
41 | | - eprintln!("IMM is not an object: {err}"); |
42 | | - return; |
43 | | - } |
44 | | - }, |
45 | | - Err(err) => { |
46 | | - eprintln!("Failed to get IMM: {err}"); |
47 | | - return; |
48 | | - } |
49 | | - }; |
| 18 | + // 获取 InputMethodManager |
| 19 | + let imm_service_name = env.new_string("input_method")?; |
| 20 | + let imm = env |
| 21 | + .call_method( |
| 22 | + &activity, |
| 23 | + "getSystemService", |
| 24 | + "(Ljava/lang/String;)Ljava/lang/Object;", |
| 25 | + &[(&imm_service_name).into()], |
| 26 | + )? |
| 27 | + .l()?; |
50 | 28 |
|
51 | | - // DecorView |
52 | | - let window = match env.call_method(&activity, "getWindow", "()Landroid/view/Window;", &[]) { |
53 | | - Ok(value) => match value.l() { |
54 | | - Ok(obj) => obj, |
55 | | - Err(err) => { |
56 | | - eprintln!("Window is not an object: {err}"); |
57 | | - return; |
58 | | - } |
59 | | - }, |
60 | | - Err(err) => { |
61 | | - eprintln!("Failed to get Window: {err}"); |
62 | | - return; |
63 | | - } |
64 | | - }; |
65 | | - let view = match env.call_method(&window, "getDecorView", "()Landroid/view/View;", &[]) { |
66 | | - Ok(value) => match value.l() { |
67 | | - Ok(obj) => obj, |
68 | | - Err(err) => { |
69 | | - eprintln!("DecorView is not an object: {err}"); |
70 | | - return; |
71 | | - } |
72 | | - }, |
73 | | - Err(err) => { |
74 | | - eprintln!("Failed to get DecorView: {err}"); |
75 | | - return; |
76 | | - } |
77 | | - }; |
| 29 | + // 获取当前 View (DecorView) |
| 30 | + let window = env |
| 31 | + .call_method(&activity, "getWindow", "()Landroid/view/Window;", &[])? |
| 32 | + .l()?; |
| 33 | + let view = env |
| 34 | + .call_method(&window, "getDecorView", "()Landroid/view/View;", &[])? |
| 35 | + .l()?; |
78 | 36 |
|
79 | 37 | if visible { |
80 | | - // 0 代表隐式请求 |
81 | | - if let Err(err) = env.call_method( |
| 38 | + // 请求显示键盘,通常需要 View 已获得焦点 |
| 39 | + env.call_method( |
82 | 40 | &imm, |
83 | 41 | "showSoftInput", |
84 | 42 | "(Landroid/view/View;I)Z", |
85 | 43 | &[(&view).into(), 0.into()], |
86 | | - ) { |
87 | | - eprintln!("Failed to show input: {err}"); |
88 | | - } |
| 44 | + )?; |
89 | 45 | } else { |
90 | | - let window_token = |
91 | | - match env.call_method(&view, "getWindowToken", "()Landroid/os/IBinder;", &[]) { |
92 | | - Ok(value) => match value.l() { |
93 | | - Ok(obj) => obj, |
94 | | - Err(err) => { |
95 | | - eprintln!("Window token is not an object: {err}"); |
96 | | - return; |
97 | | - } |
98 | | - }, |
99 | | - Err(err) => { |
100 | | - eprintln!("Failed to get window token: {err}"); |
101 | | - return; |
102 | | - } |
103 | | - }; |
104 | | - if let Err(err) = env.call_method( |
| 46 | + // 请求隐藏键盘 |
| 47 | + let window_token = env |
| 48 | + .call_method(&view, "getWindowToken", "()Landroid/os/IBinder;", &[])? |
| 49 | + .l()?; |
| 50 | + env.call_method( |
105 | 51 | &imm, |
106 | 52 | "hideSoftInputFromWindow", |
107 | 53 | "(Landroid/os/IBinder;I)Z", |
108 | 54 | &[(&window_token).into(), 0.into()], |
109 | | - ) { |
110 | | - eprintln!("Failed to hide input: {err}"); |
111 | | - } |
| 55 | + )?; |
112 | 56 | } |
| 57 | + |
| 58 | + Ok(()) |
113 | 59 | } |
0 commit comments