use std::sync::Mutex;
use jni::objects::{JClass, JObject, JString, JValue};
use jni::sys::jint;
use jni::JNIEnv;
use crate::autofill::AutofillField;
static FILLS: Mutex<Vec<(i32, String)>> = Mutex::new(Vec::new());
pub(crate) fn publish(fields: &[AutofillField]) {
crate::android_ime::with_bridge("publishing the autofill form", |env, class, _activity| {
for field in fields {
env.with_local_frame(8 + field.hints.len() as i32, |env| {
let hints = env.new_object_array(
field.hints.len() as i32,
"java/lang/String",
JObject::null(),
)?;
for (i, hint) in field.hints.iter().enumerate() {
let hint = env.new_string(hint)?;
env.set_object_array_element(&hints, i as i32, &hint)?;
}
let value = env.new_string(&field.value)?;
let [left, top, width, height] = field.bounds;
env.call_static_method(
class,
"addField",
"(I[Ljava/lang/String;IIIILjava/lang/String;Z)V",
&[
JValue::Int(field.virtual_id),
JValue::Object(&hints),
JValue::Int(left),
JValue::Int(top),
JValue::Int(width),
JValue::Int(height),
JValue::Object(&value),
JValue::Bool(field.sensitive as u8),
],
)
.map(|_| ())
})?;
}
env.call_static_method(class, "publishFields", "()V", &[])
.map(|_| ())
});
}
pub(crate) fn enter(virtual_id: i32) {
call_with_id("autofillEnter", virtual_id);
}
pub(crate) fn exit(virtual_id: i32) {
call_with_id("autofillExit", virtual_id);
}
fn call_with_id(method: &'static str, virtual_id: i32) {
crate::android_ime::with_bridge(method, |env, class, activity| {
env.call_static_method(
class,
method,
"(Landroid/app/Activity;I)V",
&[JValue::Object(activity), JValue::Int(virtual_id)],
)
.map(|_| ())
});
}
pub(crate) fn value_changed(virtual_id: i32, value: &str) {
crate::android_ime::with_bridge("autofillValueChanged", |env, class, activity| {
env.with_local_frame(4, |env| {
let value = env.new_string(value)?;
env.call_static_method(
class,
"autofillValueChanged",
"(Landroid/app/Activity;ILjava/lang/String;)V",
&[
JValue::Object(activity),
JValue::Int(virtual_id),
JValue::Object(&value),
],
)
.map(|_| ())
})
});
}
pub(crate) fn commit() {
crate::android_ime::with_bridge("autofillCommit", |env, class, activity| {
env.call_static_method(
class,
"autofillCommit",
"(Landroid/app/Activity;)V",
&[JValue::Object(activity)],
)
.map(|_| ())
});
}
pub(crate) fn drain() -> Vec<(i32, String)> {
std::mem::take(&mut FILLS.lock().unwrap())
}
pub(crate) extern "system" fn native_autofill(
mut env: JNIEnv,
_class: JClass,
virtual_id: jint,
value: JString,
) {
let value: String = env.get_string(&value).map(Into::into).unwrap_or_default();
FILLS.lock().unwrap().push((virtual_id, value));
crate::android_ime::wake();
}