use tauri::{plugin::TauriPlugin, Runtime};
#[cfg(target_os = "android")]
use std::sync::atomic::{AtomicBool, Ordering};
#[cfg(target_os = "android")]
use std::sync::OnceLock;
#[cfg(target_os = "android")]
use tokio::sync::broadcast;
#[cfg(target_os = "android")]
const PLUGIN_IDENTIFIER: &str = "org.jakebot.blew";
#[cfg(target_os = "android")]
static AUTO_REQUEST_PERMISSIONS: AtomicBool = AtomicBool::new(true);
#[cfg(target_os = "android")]
static PERMISSIONS_TX: OnceLock<broadcast::Sender<BlePermissionStatus>> = OnceLock::new();
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BlePermissionStatus {
Granted,
Denied,
}
impl BlePermissionStatus {
#[must_use]
pub fn is_granted(self) -> bool {
matches!(self, BlePermissionStatus::Granted)
}
}
#[derive(Clone, Debug)]
pub struct BlewPluginConfig {
pub auto_request_permissions: bool,
}
impl Default for BlewPluginConfig {
fn default() -> Self {
Self {
auto_request_permissions: true,
}
}
}
pub fn are_ble_permissions_granted() -> bool {
#[cfg(target_os = "android")]
{
blew::platform::android::are_ble_permissions_granted()
}
#[cfg(not(target_os = "android"))]
{
true
}
}
pub fn request_ble_permissions() {
#[cfg(target_os = "android")]
{
blew::platform::android::request_ble_permissions();
}
}
#[cfg(target_os = "android")]
pub fn permission_events() -> blew::util::BroadcastEventStream<BlePermissionStatus> {
let tx = PERMISSIONS_TX.get_or_init(|| broadcast::channel(16).0);
blew::util::BroadcastEventStream::new(tx.subscribe())
}
pub fn is_emulator() -> bool {
#[cfg(target_os = "android")]
{
blew::platform::android::is_emulator()
}
#[cfg(not(target_os = "android"))]
{
std::env::var("SIMULATOR_DEVICE_NAME").is_ok()
}
}
pub fn init<R: Runtime>() -> TauriPlugin<R> {
init_with_config(BlewPluginConfig::default())
}
pub fn init_with_config<R: Runtime>(config: BlewPluginConfig) -> TauriPlugin<R> {
#[cfg(target_os = "android")]
{
AUTO_REQUEST_PERMISSIONS.store(config.auto_request_permissions, Ordering::Relaxed);
let _ = PERMISSIONS_TX.get_or_init(|| broadcast::channel(16).0);
}
#[cfg(not(target_os = "android"))]
{
let _ = config;
}
tauri::plugin::Builder::<R>::new("blew")
.setup(|_app, api| {
#[cfg(target_os = "android")]
{
let ctx = ndk_context::android_context();
let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) };
blew::platform::android::init_jvm(vm);
api.register_android_plugin(PLUGIN_IDENTIFIER, "BlewPlugin")?;
}
let _ = api;
Ok(())
})
.build()
}
#[cfg(target_os = "android")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn Java_org_jakebot_blew_BlewPluginNative_autoRequestPermissionsEnabled(
_env: jni::EnvUnowned,
_class: jni::objects::JClass,
) -> jni::sys::jboolean {
AUTO_REQUEST_PERMISSIONS.load(Ordering::Relaxed)
}
#[cfg(target_os = "android")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn Java_org_jakebot_blew_BlewPluginNative_onPermissionsChanged(
_env: jni::EnvUnowned,
_class: jni::objects::JClass,
granted: jni::sys::jboolean,
) {
let status = if granted {
BlePermissionStatus::Granted
} else {
BlePermissionStatus::Denied
};
if let Some(tx) = PERMISSIONS_TX.get() {
let _ = tx.send(status);
}
}