180 lines
5.2 KiB
Rust
180 lines
5.2 KiB
Rust
use android_view::jni::{
|
|
JNIEnv, JavaVM,
|
|
objects::{GlobalRef, JObject, JValue},
|
|
};
|
|
|
|
/// `android.os.BatteryManager.BATTERY_PROPERTY_CURRENT_NOW` -- not exposed
|
|
/// as a constant anywhere reachable without the Android SDK jar, so named
|
|
/// here with its source rather than left as a bare `2`.
|
|
const BATTERY_PROPERTY_CURRENT_NOW: i32 = 2;
|
|
|
|
pub struct PlatformHandle {
|
|
vm: JavaVM,
|
|
view: GlobalRef,
|
|
}
|
|
|
|
impl PlatformHandle {
|
|
pub fn new(vm: JavaVM, view: GlobalRef) -> Self {
|
|
Self { vm, view }
|
|
}
|
|
|
|
fn context<'e>(&self, env: &mut JNIEnv<'e>) -> Option<JObject<'e>> {
|
|
env.call_method(
|
|
self.view.as_obj(),
|
|
"getContext",
|
|
"()Landroid/content/Context;",
|
|
&[],
|
|
)
|
|
.ok()?
|
|
.l()
|
|
.ok()
|
|
}
|
|
|
|
fn system_service<'e>(
|
|
&self,
|
|
env: &mut JNIEnv<'e>,
|
|
context: &JObject<'e>,
|
|
name: &str,
|
|
) -> Option<JObject<'e>> {
|
|
let jname = env.new_string(name).ok()?;
|
|
env.call_method(
|
|
context,
|
|
"getSystemService",
|
|
"(Ljava/lang/String;)Ljava/lang/Object;",
|
|
&[JValue::Object(jname.as_ref())],
|
|
)
|
|
.ok()?
|
|
.l()
|
|
.ok()
|
|
}
|
|
|
|
pub fn battery_current_ua(&self) -> Option<i32> {
|
|
let mut guard = self.vm.attach_current_thread().ok()?;
|
|
let env: &mut JNIEnv = &mut guard;
|
|
let context = self.context(env)?;
|
|
let battery_manager = self.system_service(env, &context, "batterymanager")?;
|
|
let value = env
|
|
.call_method(
|
|
&battery_manager,
|
|
"getIntProperty",
|
|
"(I)I",
|
|
&[JValue::Int(BATTERY_PROPERTY_CURRENT_NOW)],
|
|
)
|
|
.ok()?
|
|
.i()
|
|
.ok()?;
|
|
if value == 0 || value == i32::MIN {
|
|
None
|
|
} else {
|
|
Some(value)
|
|
}
|
|
}
|
|
|
|
/// Puts `text` on the system clipboard through `ClipboardManager` --
|
|
/// `true` only if the whole JNI chain (service lookup, `ClipData`,
|
|
/// `setPrimaryClip`) succeeded.
|
|
pub fn copy_to_clipboard(&self, label: &str, text: &str) -> bool {
|
|
self.try_copy_to_clipboard(label, text).is_some()
|
|
}
|
|
|
|
fn try_copy_to_clipboard(&self, label: &str, text: &str) -> Option<()> {
|
|
let mut guard = self.vm.attach_current_thread().ok()?;
|
|
let env: &mut JNIEnv = &mut guard;
|
|
let context = self.context(env)?;
|
|
let clipboard = self.system_service(env, &context, "clipboard")?;
|
|
let jlabel = env.new_string(label).ok()?;
|
|
let jtext = env.new_string(text).ok()?;
|
|
let clip = env
|
|
.call_static_method(
|
|
"android/content/ClipData",
|
|
"newPlainText",
|
|
"(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Landroid/content/ClipData;",
|
|
&[
|
|
JValue::Object(jlabel.as_ref()),
|
|
JValue::Object(jtext.as_ref()),
|
|
],
|
|
)
|
|
.ok()?
|
|
.l()
|
|
.ok()?;
|
|
env.call_method(
|
|
&clipboard,
|
|
"setPrimaryClip",
|
|
"(Landroid/content/ClipData;)V",
|
|
&[JValue::Object(&clip)],
|
|
)
|
|
.ok()?;
|
|
Some(())
|
|
}
|
|
|
|
pub fn refresh_rate_hz(&self) -> Option<f32> {
|
|
let mut guard = self.vm.attach_current_thread().ok()?;
|
|
let env: &mut JNIEnv = &mut guard;
|
|
let display = env
|
|
.call_method(
|
|
self.view.as_obj(),
|
|
"getDisplay",
|
|
"()Landroid/view/Display;",
|
|
&[],
|
|
)
|
|
.ok()?
|
|
.l()
|
|
.ok()?;
|
|
if display.is_null() {
|
|
return None;
|
|
}
|
|
let rate = env
|
|
.call_method(&display, "getRefreshRate", "()F", &[])
|
|
.ok()?
|
|
.f()
|
|
.ok()?;
|
|
if rate > 0.0 { Some(rate) } else { None }
|
|
}
|
|
|
|
pub fn show_ime(&self) -> bool {
|
|
self.try_toggle_ime(true).unwrap_or(false)
|
|
}
|
|
|
|
pub fn hide_ime(&self) -> bool {
|
|
self.try_toggle_ime(false).unwrap_or(false)
|
|
}
|
|
|
|
fn try_toggle_ime(&self, show: bool) -> Option<bool> {
|
|
let mut guard = self.vm.attach_current_thread().ok()?;
|
|
let env: &mut JNIEnv = &mut guard;
|
|
let context = self.context(env)?;
|
|
let imm = self.system_service(env, &context, "input_method")?;
|
|
if show {
|
|
env.call_method(
|
|
&imm,
|
|
"showSoftInput",
|
|
"(Landroid/view/View;I)Z",
|
|
&[JValue::Object(self.view.as_obj()), JValue::Int(0)],
|
|
)
|
|
.ok()?
|
|
.z()
|
|
.ok()
|
|
} else {
|
|
let token = env
|
|
.call_method(
|
|
self.view.as_obj(),
|
|
"getWindowToken",
|
|
"()Landroid/os/IBinder;",
|
|
&[],
|
|
)
|
|
.ok()?
|
|
.l()
|
|
.ok()?;
|
|
env.call_method(
|
|
&imm,
|
|
"hideSoftInputFromWindow",
|
|
"(Landroid/os/IBinder;I)Z",
|
|
&[JValue::Object(&token), JValue::Int(0)],
|
|
)
|
|
.ok()?
|
|
.z()
|
|
.ok()
|
|
}
|
|
}
|
|
}
|