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