blob: a45f37bcbfd0d3bef397c3f3e2520c5335f38f42 [file] [log] [blame]
//! Anything related to the adapter API (IBluetooth).
use bt_topshim::btif::ffi;
use bt_topshim::btif::{BluetoothCallbacks, BluetoothInterface, BtState};
use bt_topshim::topstack;
use btif_macros::btif_callbacks_generator;
use btif_macros::stack_message;
use num_traits::cast::ToPrimitive;
use num_traits::FromPrimitive;
use std::fmt::Debug;
use std::sync::Arc;
use std::sync::Mutex;
use tokio::sync::mpsc::Sender;
use crate::{BDAddr, Message, RPCProxy};
/// Defines the adapter API.
pub trait IBluetooth {
/// Adds a callback from a client who wishes to observe adapter events.
fn register_callback(&mut self, callback: Box<dyn IBluetoothCallback + Send>);
/// Enables the adapter.
///
/// Returns true if the request is accepted.
fn enable(&mut self) -> bool;
/// Disables the adapter.
///
/// Returns true if the request is accepted.
fn disable(&mut self) -> bool;
/// Returns the Bluetooth address of the local adapter.
fn get_address(&self) -> String;
}
/// The interface for adapter callbacks registered through `IBluetooth::register_callback`.
pub trait IBluetoothCallback: RPCProxy {
/// When any of the adapter states is changed.
fn on_bluetooth_state_changed(&self, prev_state: u32, new_state: u32);
/// When any of the adapter local address is changed.
fn on_bluetooth_address_changed(&self, addr: String);
}
/// Implementation of the adapter API.
pub struct Bluetooth {
intf: Arc<Mutex<BluetoothInterface>>,
state: BtState,
callbacks: Vec<(u32, Box<dyn IBluetoothCallback + Send>)>,
callbacks_last_id: u32,
tx: Sender<Message>,
local_address: Option<BDAddr>,
}
impl Bluetooth {
/// Constructs the IBluetooth implementation.
pub fn new(tx: Sender<Message>, intf: Arc<Mutex<BluetoothInterface>>) -> Bluetooth {
Bluetooth {
tx,
intf,
state: BtState::Off,
callbacks: vec![],
callbacks_last_id: 0,
local_address: None,
}
}
fn update_local_address(&mut self, raw: &Vec<u8>) {
self.local_address = Some(BDAddr::from_byte_vec(raw));
for callback in &self.callbacks {
callback.1.on_bluetooth_address_changed(self.local_address.unwrap().to_string());
}
}
pub(crate) fn callback_disconnected(&mut self, id: u32) {
self.callbacks.retain(|x| x.0 != id);
}
}
#[btif_callbacks_generator(btif_bluetooth_callbacks, BluetoothCallbacks)]
pub(crate) trait BtifBluetoothCallbacks {
#[stack_message(BluetoothAdapterStateChanged)]
fn adapter_state_changed(&mut self, state: BtState);
#[stack_message(BluetoothAdapterPropertiesChanged)]
fn adapter_properties_changed(
&mut self,
status: i32,
num_properties: i32,
properties: Vec<ffi::BtProperty>,
);
}
#[derive(FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(i32)]
#[derive(Debug)]
enum PropertyType {
BDName = 0x01,
BDAddr,
Uuids,
ClassOfDevice,
TypeOfDevice,
ServiceRecord,
AdapterScanMode,
AdapterBondedDevices,
AdapterDiscoverableTimeout,
RemoteFriendlyName,
RemoteRssi,
RemoteVersionInfo,
RemoteLocalLeFeatures,
RemoteDynamicAudioBuffer = 0x10,
Unknown = 0x100,
}
impl BtifBluetoothCallbacks for Bluetooth {
fn adapter_state_changed(&mut self, state: BtState) {
for callback in &self.callbacks {
callback
.1
.on_bluetooth_state_changed(self.state.to_u32().unwrap(), state.to_u32().unwrap());
}
self.state = state;
}
#[allow(unused_variables)]
fn adapter_properties_changed(
&mut self,
status: i32,
num_properties: i32,
properties: Vec<ffi::BtProperty>,
) {
if status != 0 {
return;
}
for prop in properties {
let prop_type = PropertyType::from_i32(prop.prop_type);
if prop_type.is_none() {
continue;
}
match prop_type.unwrap() {
PropertyType::BDAddr => {
self.update_local_address(&prop.val);
}
_ => {}
}
}
}
}
// TODO: Add unit tests for this implementation
impl IBluetooth for Bluetooth {
fn register_callback(&mut self, mut callback: Box<dyn IBluetoothCallback + Send>) {
let tx = self.tx.clone();
// TODO: Refactor into a separate wrap-around id generator.
self.callbacks_last_id += 1;
let id = self.callbacks_last_id;
callback.register_disconnect(Box::new(move || {
let tx = tx.clone();
topstack::get_runtime().spawn(async move {
let _result = tx.send(Message::BluetoothCallbackDisconnected(id)).await;
});
}));
self.callbacks.push((id, callback))
}
fn enable(&mut self) -> bool {
self.intf.lock().unwrap().enable() == 0
}
fn disable(&mut self) -> bool {
self.intf.lock().unwrap().disable() == 0
}
fn get_address(&self) -> String {
match self.local_address {
None => String::from(""),
Some(addr) => addr.to_string(),
}
}
}