1 use crate::battery_provider_manager::BatteryProviderManager; 2 use crate::callbacks::Callbacks; 3 use crate::uuid; 4 use crate::Message; 5 use crate::RPCProxy; 6 use bt_topshim::btif::RawAddress; 7 use itertools::Itertools; 8 use std::sync::{Arc, Mutex}; 9 use tokio::sync::mpsc::Sender; 10 11 /// The primary representation of battery information for internal passing and external calls. 12 #[derive(Debug, Clone)] 13 pub struct BatterySet { 14 /// Address of the remote device. 15 pub address: RawAddress, 16 /// UUID of where the battery info is decoded from as found in BT Spec. 17 pub source_uuid: String, 18 /// Information about the battery source, e.g. "BAS" or "HFP 1.8". 19 pub source_info: String, 20 /// Collection of batteries from this source. 21 pub batteries: Vec<Battery>, 22 } 23 24 /// Describes an individual battery measurement, possibly one of many for a given device. 25 #[derive(Debug, Clone)] 26 pub struct Battery { 27 /// Battery charge percentage between 0 and 100. For protocols that use 0-5 this will be that 28 /// number multiplied by 20. 29 pub percentage: u32, 30 /// Description of this battery, such as Left, Right, or Case. Only present if the source has 31 /// this level of detail. 32 pub variant: String, 33 } 34 35 /// Helper representation of a collection of BatterySet to simplify passing around data internally. 36 pub struct Batteries(Vec<BatterySet>); 37 38 /// Callback for interacting with the BatteryManager. 39 pub trait IBatteryManagerCallback: RPCProxy { 40 /// Invoked whenever battery information associated with the given remote changes. on_battery_info_updated(&mut self, remote_address: RawAddress, battery_set: BatterySet)41 fn on_battery_info_updated(&mut self, remote_address: RawAddress, battery_set: BatterySet); 42 } 43 44 /// Central point for getting battery information that might be sourced from numerous systems. 45 pub trait IBatteryManager { 46 /// Registers a callback for interfacing with the BatteryManager and returns a unique 47 /// callback_id for future calls. register_battery_callback( &mut self, battery_manager_callback: Box<dyn IBatteryManagerCallback + Send>, ) -> u3248 fn register_battery_callback( 49 &mut self, 50 battery_manager_callback: Box<dyn IBatteryManagerCallback + Send>, 51 ) -> u32; 52 53 /// Unregister a callback. unregister_battery_callback(&mut self, callback_id: u32) -> bool54 fn unregister_battery_callback(&mut self, callback_id: u32) -> bool; 55 56 /// Returns battery information for the remote, sourced from the highest priority origin. get_battery_information(&self, remote_address: RawAddress) -> Option<BatterySet>57 fn get_battery_information(&self, remote_address: RawAddress) -> Option<BatterySet>; 58 } 59 60 /// Repesentation of the BatteryManager. 61 pub struct BatteryManager { 62 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, 63 callbacks: Callbacks<dyn IBatteryManagerCallback + Send>, 64 } 65 66 impl BatteryManager { 67 /// Construct a new BatteryManager with callbacks communicating on tx. new( battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, tx: Sender<Message>, ) -> BatteryManager68 pub fn new( 69 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, 70 tx: Sender<Message>, 71 ) -> BatteryManager { 72 let callbacks = Callbacks::new(tx.clone(), Message::BatteryManagerCallbackDisconnected); 73 Self { battery_provider_manager, callbacks } 74 } 75 76 /// Remove a callback due to disconnection or unregistration. remove_callback(&mut self, callback_id: u32) -> bool77 pub fn remove_callback(&mut self, callback_id: u32) -> bool { 78 self.callbacks.remove_callback(callback_id) 79 } 80 81 /// Handles a BatterySet update. handle_battery_updated(&mut self, remote_address: RawAddress, battery_set: BatterySet)82 pub fn handle_battery_updated(&mut self, remote_address: RawAddress, battery_set: BatterySet) { 83 self.callbacks.for_all_callbacks(|callback| { 84 callback.on_battery_info_updated(remote_address, battery_set.clone()) 85 }); 86 } 87 } 88 89 impl IBatteryManager for BatteryManager { register_battery_callback( &mut self, battery_manager_callback: Box<dyn IBatteryManagerCallback + Send>, ) -> u3290 fn register_battery_callback( 91 &mut self, 92 battery_manager_callback: Box<dyn IBatteryManagerCallback + Send>, 93 ) -> u32 { 94 self.callbacks.add_callback(battery_manager_callback) 95 } 96 unregister_battery_callback(&mut self, callback_id: u32) -> bool97 fn unregister_battery_callback(&mut self, callback_id: u32) -> bool { 98 self.remove_callback(callback_id) 99 } 100 get_battery_information(&self, remote_address: RawAddress) -> Option<BatterySet>101 fn get_battery_information(&self, remote_address: RawAddress) -> Option<BatterySet> { 102 self.battery_provider_manager.lock().unwrap().get_battery_info(remote_address) 103 } 104 } 105 106 impl BatterySet { new( address: RawAddress, source_uuid: String, source_info: String, batteries: Vec<Battery>, ) -> Self107 pub fn new( 108 address: RawAddress, 109 source_uuid: String, 110 source_info: String, 111 batteries: Vec<Battery>, 112 ) -> Self { 113 Self { address, source_uuid, source_info, batteries } 114 } 115 add_or_update_battery(&mut self, new_battery: Battery)116 pub fn add_or_update_battery(&mut self, new_battery: Battery) { 117 match self.batteries.iter_mut().find(|battery| battery.variant == new_battery.variant) { 118 Some(battery) => *battery = new_battery, 119 None => self.batteries.push(new_battery), 120 } 121 } 122 } 123 124 impl Batteries { new() -> Self125 pub fn new() -> Self { 126 Self(vec![]) 127 } 128 129 /// Updates a battery matching all non-battery-level fields if found, otherwise adds new_battery 130 /// verbatim. add_or_update_battery_set(&mut self, new_battery_set: BatterySet)131 pub fn add_or_update_battery_set(&mut self, new_battery_set: BatterySet) { 132 match self 133 .0 134 .iter_mut() 135 .find(|battery_set| battery_set.source_uuid == new_battery_set.source_uuid) 136 { 137 Some(battery_set) => *battery_set = new_battery_set, 138 None => self.0.push(new_battery_set), 139 } 140 } 141 remove_battery_set(&mut self, uuid: &String)142 pub fn remove_battery_set(&mut self, uuid: &String) { 143 self.0.retain(|battery_set| &battery_set.source_uuid != uuid); 144 } 145 is_empty(&self) -> bool146 pub fn is_empty(&self) -> bool { 147 self.0.is_empty() 148 } 149 150 /// Returns the best BatterySet from among reported battery data. pick_best(&self) -> Option<BatterySet>151 pub fn pick_best(&self) -> Option<BatterySet> { 152 self.0 153 .iter() 154 .filter(|battery_set| !battery_set.batteries.is_empty()) 155 // Now we prefer BAS, but we might need to prioritize other sources first 156 // TODO (b/295577710): Make a preference list 157 .find_or_first(|battery_set| battery_set.source_uuid == uuid::BAS) 158 .or_else(|| self.0.first()) 159 .cloned() 160 } 161 } 162