use jni::objects::{JObject, JString};
use jni::{JNIEnv, JavaVM};
use winit::platform::android::activity::AndroidApp;
pub(crate) fn launch_link(app: &AndroidApp) -> Option<String> {
with_intent(app, |env, intent| {
let data = env
.call_method(intent, "getDataString", "()Ljava/lang/String;", &[])?
.l()?;
string(env, data)
})
}
pub(crate) fn launch_extra(app: &AndroidApp, name: &str) -> Option<String> {
with_intent(app, |env, intent| {
let key = env.new_string(name)?;
let value = env
.call_method(
intent,
"getStringExtra",
"(Ljava/lang/String;)Ljava/lang/String;",
&[(&key).into()],
)?
.l()?;
string(env, value)
})
}
fn with_intent(
app: &AndroidApp,
read: impl FnOnce(&mut JNIEnv, &JObject) -> Result<Option<String>, jni::errors::Error>,
) -> Option<String> {
let vm = unsafe { JavaVM::from_raw(app.vm_as_ptr() as *mut jni::sys::JavaVM) }.ok()?;
let mut env = vm.attach_current_thread_permanently().ok()?;
let activity = unsafe { JObject::from_raw(app.activity_as_ptr() as jni::sys::jobject) };
let result = env
.call_method(&activity, "getIntent", "()Landroid/content/Intent;", &[])
.and_then(|intent| intent.l())
.and_then(|intent| {
if intent.is_null() {
Ok(None)
} else {
read(&mut env, &intent)
}
});
match result {
Ok(value) => value,
Err(err) => {
log::warn!("the launch intent could not be read ({err})");
if env.exception_check().unwrap_or(false) {
let _ = env.exception_clear();
}
None
}
}
}
fn string(env: &mut JNIEnv, value: JObject) -> Result<Option<String>, jni::errors::Error> {
if value.is_null() {
return Ok(None);
}
let value = JString::from(value);
let text: String = env.get_string(&value)?.into();
Ok(Some(text))
}