1 //! Anything related to the Qualification API (IBluetoothQA). 2 3 use crate::callbacks::Callbacks; 4 use crate::{bluetooth::FLOSS_VER, Message, RPCProxy}; 5 use bt_topshim::btif::{BtDiscMode, BtStatus, RawAddress}; 6 use bt_topshim::profiles::hid_host::BthhReportType; 7 use tokio::sync::mpsc::Sender; 8 9 /// Defines the Qualification API 10 pub trait IBluetoothQA { 11 /// Register client callback register_qa_callback(&mut self, callback: Box<dyn IBluetoothQACallback + Send>) -> u3212 fn register_qa_callback(&mut self, callback: Box<dyn IBluetoothQACallback + Send>) -> u32; 13 /// Unregister a client callback unregister_qa_callback(&mut self, callback_id: u32) -> bool14 fn unregister_qa_callback(&mut self, callback_id: u32) -> bool; 15 /// Register a media player add_media_player(&self, name: String, browsing_supported: bool)16 fn add_media_player(&self, name: String, browsing_supported: bool); 17 /// Send RFCOMM MSC command to the remote rfcomm_send_msc(&self, dlci: u8, addr: RawAddress)18 fn rfcomm_send_msc(&self, dlci: u8, addr: RawAddress); 19 /// Fetch adapter's discoverable mode. 20 /// Result will be returned in the callback |OnFetchDiscoverableModeComplete| fetch_discoverable_mode(&self)21 fn fetch_discoverable_mode(&self); 22 /// Fetch adapter's connectable mode. 23 /// Result will be returned in the callback |OnFetchConnectableComplete| fetch_connectable(&self)24 fn fetch_connectable(&self); 25 /// Set adapter's connectable mode. 26 /// Result will be returned in the callback |OnSetConnectableComplete| set_connectable(&self, mode: bool)27 fn set_connectable(&self, mode: bool); 28 /// Fetch the adapter's Bluetooth friendly name. 29 /// Result will be returned in the callback |OnFetchAliasComplete| fetch_alias(&self)30 fn fetch_alias(&self); 31 /// Returns the adapter's Device ID information in modalias format 32 /// used by the kernel and udev. get_modalias(&self) -> String33 fn get_modalias(&self) -> String; 34 /// Gets HID report on the peer. 35 /// Result will be returned in the callback |OnGetHIDReportComplete| get_hid_report(&self, addr: RawAddress, report_type: BthhReportType, report_id: u8)36 fn get_hid_report(&self, addr: RawAddress, report_type: BthhReportType, report_id: u8); 37 /// Sets HID report to the peer. 38 /// Result will be returned in the callback |OnSetHIDReportComplete| set_hid_report(&self, addr: RawAddress, report_type: BthhReportType, report: String)39 fn set_hid_report(&self, addr: RawAddress, report_type: BthhReportType, report: String); 40 /// Sends HID data report to the peer. 41 /// Result will be returned in the callback |OnSendHIDDataComplete| send_hid_data(&self, addr: RawAddress, data: String)42 fn send_hid_data(&self, addr: RawAddress, data: String); 43 /// Sends HID virtual unplug to the peer. 44 /// Result will be returned in the callback |OnSendHIDVirtualUnplugComplete| send_hid_virtual_unplug(&self, addr: RawAddress)45 fn send_hid_virtual_unplug(&self, addr: RawAddress); 46 } 47 48 pub trait IBluetoothQACallback: RPCProxy { on_fetch_discoverable_mode_completed(&mut self, mode: BtDiscMode)49 fn on_fetch_discoverable_mode_completed(&mut self, mode: BtDiscMode); on_fetch_connectable_completed(&mut self, connectable: bool)50 fn on_fetch_connectable_completed(&mut self, connectable: bool); on_set_connectable_completed(&mut self, succeed: bool)51 fn on_set_connectable_completed(&mut self, succeed: bool); on_fetch_alias_completed(&mut self, alias: String)52 fn on_fetch_alias_completed(&mut self, alias: String); on_get_hid_report_completed(&mut self, status: BtStatus)53 fn on_get_hid_report_completed(&mut self, status: BtStatus); on_set_hid_report_completed(&mut self, status: BtStatus)54 fn on_set_hid_report_completed(&mut self, status: BtStatus); on_send_hid_data_completed(&mut self, status: BtStatus)55 fn on_send_hid_data_completed(&mut self, status: BtStatus); on_send_hid_virtual_unplug_completed(&mut self, status: BtStatus)56 fn on_send_hid_virtual_unplug_completed(&mut self, status: BtStatus); 57 } 58 59 pub struct BluetoothQA { 60 tx: Sender<Message>, 61 callbacks: Callbacks<dyn IBluetoothQACallback + Send>, 62 } 63 64 impl BluetoothQA { new(tx: Sender<Message>) -> BluetoothQA65 pub fn new(tx: Sender<Message>) -> BluetoothQA { 66 BluetoothQA { 67 tx: tx.clone(), 68 callbacks: Callbacks::new(tx.clone(), Message::QaCallbackDisconnected), 69 } 70 } on_fetch_discoverable_mode_completed(&mut self, mode: BtDiscMode)71 pub fn on_fetch_discoverable_mode_completed(&mut self, mode: BtDiscMode) { 72 self.callbacks.for_all_callbacks(|cb| { 73 cb.on_fetch_discoverable_mode_completed(mode.clone()); 74 }); 75 } on_fetch_connectable_completed(&mut self, connectable: bool)76 pub fn on_fetch_connectable_completed(&mut self, connectable: bool) { 77 self.callbacks.for_all_callbacks(|cb| { 78 cb.on_fetch_connectable_completed(connectable); 79 }); 80 } on_set_connectable_completed(&mut self, succeed: bool)81 pub fn on_set_connectable_completed(&mut self, succeed: bool) { 82 self.callbacks.for_all_callbacks(|cb: &mut Box<dyn IBluetoothQACallback + Send>| { 83 cb.on_set_connectable_completed(succeed); 84 }); 85 } on_fetch_alias_completed(&mut self, alias: String)86 pub fn on_fetch_alias_completed(&mut self, alias: String) { 87 self.callbacks.for_all_callbacks(|cb: &mut Box<dyn IBluetoothQACallback + Send>| { 88 cb.on_fetch_alias_completed(alias.clone()); 89 }); 90 } on_get_hid_report_completed(&mut self, status: BtStatus)91 pub fn on_get_hid_report_completed(&mut self, status: BtStatus) { 92 self.callbacks.for_all_callbacks(|cb: &mut Box<dyn IBluetoothQACallback + Send>| { 93 cb.on_get_hid_report_completed(status); 94 }); 95 } on_set_hid_report_completed(&mut self, status: BtStatus)96 pub fn on_set_hid_report_completed(&mut self, status: BtStatus) { 97 self.callbacks.for_all_callbacks(|cb: &mut Box<dyn IBluetoothQACallback + Send>| { 98 cb.on_set_hid_report_completed(status); 99 }); 100 } on_send_hid_data_completed(&mut self, status: BtStatus)101 pub fn on_send_hid_data_completed(&mut self, status: BtStatus) { 102 self.callbacks.for_all_callbacks(|cb: &mut Box<dyn IBluetoothQACallback + Send>| { 103 cb.on_send_hid_data_completed(status); 104 }); 105 } on_send_hid_virtual_unplug_completed(&mut self, status: BtStatus)106 pub fn on_send_hid_virtual_unplug_completed(&mut self, status: BtStatus) { 107 self.callbacks.for_all_callbacks(|cb: &mut Box<dyn IBluetoothQACallback + Send>| { 108 cb.on_send_hid_virtual_unplug_completed(status); 109 }); 110 } 111 } 112 113 impl IBluetoothQA for BluetoothQA { register_qa_callback(&mut self, callback: Box<dyn IBluetoothQACallback + Send>) -> u32114 fn register_qa_callback(&mut self, callback: Box<dyn IBluetoothQACallback + Send>) -> u32 { 115 self.callbacks.add_callback(callback) 116 } 117 unregister_qa_callback(&mut self, callback_id: u32) -> bool118 fn unregister_qa_callback(&mut self, callback_id: u32) -> bool { 119 self.callbacks.remove_callback(callback_id) 120 } add_media_player(&self, name: String, browsing_supported: bool)121 fn add_media_player(&self, name: String, browsing_supported: bool) { 122 let txl = self.tx.clone(); 123 tokio::spawn(async move { 124 let _ = txl.send(Message::QaAddMediaPlayer(name, browsing_supported)).await; 125 }); 126 } rfcomm_send_msc(&self, dlci: u8, addr: RawAddress)127 fn rfcomm_send_msc(&self, dlci: u8, addr: RawAddress) { 128 let txl = self.tx.clone(); 129 tokio::spawn(async move { 130 let _ = txl.send(Message::QaRfcommSendMsc(dlci, addr)).await; 131 }); 132 } fetch_discoverable_mode(&self)133 fn fetch_discoverable_mode(&self) { 134 let txl = self.tx.clone(); 135 tokio::spawn(async move { 136 let _ = txl.send(Message::QaFetchDiscoverableMode).await; 137 }); 138 } fetch_connectable(&self)139 fn fetch_connectable(&self) { 140 let txl = self.tx.clone(); 141 tokio::spawn(async move { 142 let _ = txl.send(Message::QaFetchConnectable).await; 143 }); 144 } set_connectable(&self, mode: bool)145 fn set_connectable(&self, mode: bool) { 146 let txl = self.tx.clone(); 147 tokio::spawn(async move { 148 let _ = txl.send(Message::QaSetConnectable(mode)).await; 149 }); 150 } fetch_alias(&self)151 fn fetch_alias(&self) { 152 let txl = self.tx.clone(); 153 tokio::spawn(async move { 154 let _ = txl.send(Message::QaFetchAlias).await; 155 }); 156 } get_modalias(&self) -> String157 fn get_modalias(&self) -> String { 158 format!("bluetooth:v00E0pC405d{:04x}", FLOSS_VER) 159 } get_hid_report(&self, addr: RawAddress, report_type: BthhReportType, report_id: u8)160 fn get_hid_report(&self, addr: RawAddress, report_type: BthhReportType, report_id: u8) { 161 let txl = self.tx.clone(); 162 tokio::spawn(async move { 163 let _ = txl.send(Message::QaGetHidReport(addr, report_type, report_id)).await; 164 }); 165 } set_hid_report(&self, addr: RawAddress, report_type: BthhReportType, report: String)166 fn set_hid_report(&self, addr: RawAddress, report_type: BthhReportType, report: String) { 167 let txl = self.tx.clone(); 168 tokio::spawn(async move { 169 let _ = txl.send(Message::QaSetHidReport(addr, report_type, report)).await; 170 }); 171 } send_hid_data(&self, addr: RawAddress, data: String)172 fn send_hid_data(&self, addr: RawAddress, data: String) { 173 let txl = self.tx.clone(); 174 tokio::spawn(async move { 175 let _ = txl.send(Message::QaSendHidData(addr, data)).await; 176 }); 177 } send_hid_virtual_unplug(&self, addr: RawAddress)178 fn send_hid_virtual_unplug(&self, addr: RawAddress) { 179 let txl = self.tx.clone(); 180 tokio::spawn(async move { 181 let _ = txl.send(Message::QaSendHidVirtualUnplug(addr)).await; 182 }); 183 } 184 } 185