forked from amodm/webbrowser-rs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
android.rs
84 lines (76 loc) · 2.96 KB
/
android.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use crate::{Browser, BrowserOptions, Error, ErrorKind, Result};
use jni::objects::JValue;
pub use std::os::unix::process::ExitStatusExt;
/// Deal with opening of browsers on Android. Only [Browser::Default] is supported, and
/// in options, only [BrowserOptions::dry_run] is honoured.
#[inline]
pub fn open_browser_internal(browser: Browser, url: &str, options: &BrowserOptions) -> Result<()> {
match browser {
Browser::Default => open_browser_default(url, options),
_ => Err(Error::new(
ErrorKind::NotFound,
"only default browser supported",
)),
}
}
/// Open the default browser
#[inline]
pub fn open_browser_default(url: &str, options: &BrowserOptions) -> Result<()> {
// always return true for a dry run
if options.dry_run {
return Ok(());
}
// Create a VM for executing Java calls
let ctx = ndk_context::android_context();
let vm = unsafe {
jni::JavaVM::from_raw(ctx.vm() as _).expect("Expected to find JVM via ndk_context crate")
};
let activity = unsafe { jni::objects::JObject::from_raw(ctx.context() as _) };
let env = vm.attach_current_thread().map_err(|_| -> Error {
Error::new(ErrorKind::Other, "Failed to attach current thread")
})?;
// Create ACTION_VIEW object
let intent_class = env
.find_class("android/content/Intent")
.map_err(|_| -> Error { Error::new(ErrorKind::NotFound, "Failed to find Intent class") })?;
let action_view = env
.get_static_field(intent_class, "ACTION_VIEW", "Ljava/lang/String;")
.map_err(|_| -> Error {
Error::new(ErrorKind::NotFound, "Failed to get intent.ACTION_VIEW")
})?;
// Create Uri object
let uri_class = env
.find_class("android/net/Uri")
.map_err(|_| -> Error { Error::new(ErrorKind::NotFound, "Failed to find Uri class") })?;
let url = env
.new_string(url)
.map_err(|_| -> Error { Error::new(ErrorKind::Other, "Failed to create JNI string") })?;
let uri = env
.call_static_method(
uri_class,
"parse",
"(Ljava/lang/String;)Landroid/net/Uri;",
&[JValue::Object(*url)],
)
.map_err(|_| -> Error { Error::new(ErrorKind::Other, "Failed to parse JNI Uri") })?;
// Create new ACTION_VIEW intent with the uri
let intent = env
.alloc_object(intent_class)
.map_err(|_| -> Error { Error::new(ErrorKind::Other, "Failed to allocate intent") })?;
env.call_method(
intent,
"<init>",
"(Ljava/lang/String;Landroid/net/Uri;)V",
&[action_view, uri],
)
.map_err(|_| -> Error { Error::new(ErrorKind::Other, "Failed to initialize intent") })?;
// Start the intent activity.
env.call_method(
activity,
"startActivity",
"(Landroid/content/Intent;)V",
&[JValue::Object(intent)],
)
.map_err(|_| -> Error { Error::new(ErrorKind::Other, "Failed to start activity") })?;
Ok(())
}