diff --git a/src/android.rs b/src/android.rs index 767e7dd..d001502 100644 --- a/src/android.rs +++ b/src/android.rs @@ -1,6 +1,6 @@ use crate::{Browser, BrowserOptions, Error, ErrorKind, Result}; use jni::objects::JValue; -pub use std::os::unix::process::ExitStatusExt; +use std::process::{Command, Stdio}; /// Deal with opening of browsers on Android. Only [Browser::Default] is supported, and /// in options, only [BrowserOptions::dry_run] is honoured. @@ -17,17 +17,27 @@ pub fn open_browser_internal(browser: Browser, url: &str, options: &BrowserOptio /// Open the default browser #[inline] -pub fn open_browser_default(url: &str, options: &BrowserOptions) -> Result<()> { +fn open_browser_default(url: &str, options: &BrowserOptions) -> Result<()> { // always return true for a dry run if options.dry_run { return Ok(()); } + // first we try to see if we're in a termux env, because if we are, then + // the android context may not have been initialized, and it'll panic + if try_for_termux(url, options).is_ok() { + 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 vm = unsafe { jni::JavaVM::from_raw(ctx.vm() as _) }.map_err(|_| -> Error { + Error::new( + ErrorKind::NotFound, + "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") @@ -82,3 +92,36 @@ pub fn open_browser_default(url: &str, options: &BrowserOptions) -> Result<()> { Ok(()) } + +/// Attemps to open a browser assuming a termux environment +/// +/// See [issue #53](https://github.com/amodm/webbrowser-rs/issues/53) +#[inline] +fn try_for_termux(url: &str, options: &BrowserOptions) -> Result<()> { + use std::env; + if env::var("TERMUX_VERSION").is_ok() { + // return true on dry-run given that termux-open command is guaranteed to be present + if options.dry_run { + return Ok(()); + } + let mut cmd = Command::new("termux-open"); + cmd.arg(url); + if options.suppress_output { + cmd.stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()); + } + cmd.status().and_then(|status| { + if status.success() { + Ok(()) + } else { + Err(Error::new( + ErrorKind::Other, + "command present but exited unsuccessfully", + )) + } + }) + } else { + Err(Error::new(ErrorKind::Other, "Not a termux environment")) + } +}