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 #[derive(Default)] 37 pub struct Batteries(Vec<BatterySet>); 38 39 /// Callback for interacting with the BatteryManager. 40 pub trait IBatteryManagerCallback: RPCProxy { 41 /// Invoked whenever battery information associated with the given remote changes. on_battery_info_updated(&mut self, remote_address: RawAddress, battery_set: BatterySet)42 fn on_battery_info_updated(&mut self, remote_address: RawAddress, battery_set: BatterySet); 43 } 44 45 /// Central point for getting battery information that might be sourced from numerous systems. 46 pub trait IBatteryManager { 47 /// Registers a callback for interfacing with the BatteryManager and returns a unique 48 /// callback_id for future calls. register_battery_callback( &mut self, battery_manager_callback: Box<dyn IBatteryManagerCallback + Send>, ) -> u3249 fn register_battery_callback( 50 &mut self, 51 battery_manager_callback: Box<dyn IBatteryManagerCallback + Send>, 52 ) -> u32; 53 54 /// Unregister a callback. unregister_battery_callback(&mut self, callback_id: u32) -> bool55 fn unregister_battery_callback(&mut self, callback_id: u32) -> bool; 56 57 /// Returns battery information for the remote, sourced from the highest priority origin. get_battery_information(&self, remote_address: RawAddress) -> Option<BatterySet>58 fn get_battery_information(&self, remote_address: RawAddress) -> Option<BatterySet>; 59 } 60 61 /// Repesentation of the BatteryManager. 62 pub struct BatteryManager { 63 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, 64 callbacks: Callbacks<dyn IBatteryManagerCallback + Send>, 65 } 66 67 impl BatteryManager { 68 /// Construct a new BatteryManager with callbacks communicating on tx. new( battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, tx: Sender<Message>, ) -> BatteryManager69 pub fn new( 70 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, 71 tx: Sender<Message>, 72 ) -> BatteryManager { 73 let callbacks = Callbacks::new(tx.clone(), Message::BatteryManagerCallbackDisconnected); 74 Self { battery_provider_manager, callbacks } 75 } 76 77 /// Remove a callback due to disconnection or unregistration. remove_callback(&mut self, callback_id: u32) -> bool78 pub fn remove_callback(&mut self, callback_id: u32) -> bool { 79 self.callbacks.remove_callback(callback_id) 80 } 81 82 /// Handles a BatterySet update. handle_battery_updated(&mut self, remote_address: RawAddress, battery_set: BatterySet)83 pub fn handle_battery_updated(&mut self, remote_address: RawAddress, battery_set: BatterySet) { 84 self.callbacks.for_all_callbacks(|callback| { 85 callback.on_battery_info_updated(remote_address, battery_set.clone()) 86 }); 87 } 88 } 89 90 impl IBatteryManager for BatteryManager { register_battery_callback( &mut self, battery_manager_callback: Box<dyn IBatteryManagerCallback + Send>, ) -> u3291 fn register_battery_callback( 92 &mut self, 93 battery_manager_callback: Box<dyn IBatteryManagerCallback + Send>, 94 ) -> u32 { 95 self.callbacks.add_callback(battery_manager_callback) 96 } 97 unregister_battery_callback(&mut self, callback_id: u32) -> bool98 fn unregister_battery_callback(&mut self, callback_id: u32) -> bool { 99 self.remove_callback(callback_id) 100 } 101 get_battery_information(&self, remote_address: RawAddress) -> Option<BatterySet>102 fn get_battery_information(&self, remote_address: RawAddress) -> Option<BatterySet> { 103 self.battery_provider_manager.lock().unwrap().get_battery_info(remote_address) 104 } 105 } 106 107 impl BatterySet { new( address: RawAddress, source_uuid: String, source_info: String, batteries: Vec<Battery>, ) -> Self108 pub fn new( 109 address: RawAddress, 110 source_uuid: String, 111 source_info: String, 112 batteries: Vec<Battery>, 113 ) -> Self { 114 Self { address, source_uuid, source_info, batteries } 115 } 116 add_or_update_battery(&mut self, new_battery: Battery)117 pub fn add_or_update_battery(&mut self, new_battery: Battery) { 118 match self.batteries.iter_mut().find(|battery| battery.variant == new_battery.variant) { 119 Some(battery) => *battery = new_battery, 120 None => self.batteries.push(new_battery), 121 } 122 } 123 } 124 125 impl Batteries { new() -> Self126 pub fn new() -> Self { 127 Default::default() 128 } 129 130 /// Updates a battery matching all non-battery-level fields if found, otherwise adds new_battery 131 /// verbatim. add_or_update_battery_set(&mut self, new_battery_set: BatterySet)132 pub fn add_or_update_battery_set(&mut self, new_battery_set: BatterySet) { 133 match self 134 .0 135 .iter_mut() 136 .find(|battery_set| battery_set.source_uuid == new_battery_set.source_uuid) 137 { 138 Some(battery_set) => *battery_set = new_battery_set, 139 None => self.0.push(new_battery_set), 140 } 141 } 142 remove_battery_set(&mut self, uuid: &String)143 pub fn remove_battery_set(&mut self, uuid: &String) { 144 self.0.retain(|battery_set| &battery_set.source_uuid != uuid); 145 } 146 is_empty(&self) -> bool147 pub fn is_empty(&self) -> bool { 148 self.0.is_empty() 149 } 150 151 /// Returns the best BatterySet from among reported battery data. pick_best(&self) -> Option<BatterySet>152 pub fn pick_best(&self) -> Option<BatterySet> { 153 self.0 154 .iter() 155 .filter(|battery_set| !battery_set.batteries.is_empty()) 156 // Now we prefer BAS, but we might need to prioritize other sources first 157 // TODO (b/295577710): Make a preference list 158 .find_or_first(|battery_set| battery_set.source_uuid == uuid::BAS) 159 .or_else(|| self.0.first()) 160 .cloned() 161 } 162 } 163