Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78f93b2e authored by Jesse Melhuish's avatar Jesse Melhuish Committed by Gerrit Code Review
Browse files

Merge "floss: Add BatteryProviderManager implementation"

parents 43245f77 d727ae8a
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
use btstack::battery_manager::{Battery, IBatteryManager, IBatteryManagerCallback};
use btstack::battery_manager::{Battery, BatterySet, IBatteryManager, IBatteryManagerCallback};
use btstack::RPCProxy;
use dbus::arg::RefArg;
use dbus::strings::Path;
@@ -7,10 +7,17 @@ use dbus_projection::{dbus_generated, DisconnectWatcher};

use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};

#[dbus_propmap(BatterySet)]
pub struct BatterySetDBus {
    address: String,
    source_uuid: String,
    source_info: String,
    batteries: Vec<Battery>,
}

#[dbus_propmap(Battery)]
pub struct BatteryDBus {
    percentage: u32,
    source_info: String,
    variant: String,
}

@@ -19,7 +26,7 @@ struct IBatteryManagerCallbackDBus {}
#[dbus_proxy_obj(BatteryManagerCallback, "org.chromium.bluetooth.BatteryManagerCallback")]
impl IBatteryManagerCallback for IBatteryManagerCallbackDBus {
    #[dbus_method("OnBatteryInfoUpdated")]
    fn on_battery_info_updated(&self, remote_address: String, battery: Battery) {
    fn on_battery_info_updated(&self, remote_address: String, battery_set: BatterySet) {
        dbus_generated!()
    }
}
@@ -41,13 +48,8 @@ impl IBatteryManager for IBatteryManagerDBus {
        dbus_generated!()
    }

    #[dbus_method("EnableNotifications")]
    fn enable_notifications(&mut self, callback_id: u32, enable: bool) {
        dbus_generated!()
    }

    #[dbus_method("GetBatteryInformation")]
    fn get_battery_information(&self, remote_address: String) -> Option<Battery> {
    fn get_battery_information(&self, remote_address: String) -> Option<BatterySet> {
        dbus_generated!()
    }
}
+8 −18
Original line number Diff line number Diff line
use btstack::battery_manager::Battery;
use btstack::battery_provider_manager::{
    BatteryProvider, IBatteryProviderCallback, IBatteryProviderManager,
};
use btstack::battery_manager::BatterySet;
use btstack::battery_provider_manager::{IBatteryProviderCallback, IBatteryProviderManager};
use btstack::RPCProxy;
use dbus::arg::RefArg;
use dbus::strings::Path;
use dbus_macros::{dbus_method, dbus_propmap, dbus_proxy_obj, generate_dbus_exporter};
use dbus_macros::{dbus_method, dbus_proxy_obj, generate_dbus_exporter};
use dbus_projection::{dbus_generated, DisconnectWatcher};

use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};

#[dbus_propmap(BatteryProvider)]
pub struct BatteryProviderDBus {
    source_info: String,
    remote_address: String,
}
use crate::dbus_arg::DBusArg;

struct IBatteryProviderCallbackDBus {}

@@ -36,19 +27,18 @@ impl IBatteryProviderManager for IBatteryProviderManagerDBus {
    #[dbus_method("RegisterBatteryProvider")]
    fn register_battery_provider(
        &mut self,
        battery_provider: BatteryProvider,
        battery_provider_callback: Box<dyn IBatteryProviderCallback + Send>,
    ) -> i32 {
    ) -> u32 {
        dbus_generated!()
    }

    #[dbus_method("UnregisterBatteryProvider")]
    fn unregister_battery_provider(&mut self, battery_id: i32) {
    fn unregister_battery_provider(&mut self, battery_provider_id: u32) {
        dbus_generated!()
    }

    #[dbus_method("SetBatteryPercentage")]
    fn set_battery_percentage(&mut self, battery_id: i32, battery: Battery) {
    #[dbus_method("SetBatteryInfo")]
    fn set_battery_info(&mut self, battery_provider_id: u32, battery_set: BatterySet) {
        dbus_generated!()
    }
}
+12 −5
Original line number Diff line number Diff line
@@ -114,11 +114,17 @@ fn main() -> Result<(), Box<dyn Error>> {
        Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone(), tx.clone()))));
    let bluetooth_media =
        Arc::new(Mutex::new(Box::new(BluetoothMedia::new(tx.clone(), intf.clone()))));
    let battery_provider_manager = Arc::new(Mutex::new(Box::new(BatteryProviderManager::new())));
    let battery_service =
        Arc::new(Mutex::new(Box::new(BatteryService::new(bluetooth_gatt.clone(), tx.clone()))));
    let battery_manager =
        Arc::new(Mutex::new(Box::new(BatteryManager::new(battery_service.clone(), tx.clone()))));
    let battery_provider_manager =
        Arc::new(Mutex::new(Box::new(BatteryProviderManager::new(tx.clone()))));
    let battery_service = Arc::new(Mutex::new(Box::new(BatteryService::new(
        bluetooth_gatt.clone(),
        battery_provider_manager.clone(),
        tx.clone(),
    ))));
    let battery_manager = Arc::new(Mutex::new(Box::new(BatteryManager::new(
        battery_provider_manager.clone(),
        tx.clone(),
    ))));
    let bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new(
        tx.clone(),
        intf.clone(),
@@ -170,6 +176,7 @@ fn main() -> Result<(), Box<dyn Error>> {
            bluetooth_gatt.clone(),
            battery_service.clone(),
            battery_manager.clone(),
            battery_provider_manager.clone(),
            bluetooth_media.clone(),
            suspend.clone(),
            bt_sock_mgr.clone(),
+75 −68
Original line number Diff line number Diff line
use crate::battery_service::{
    BatteryService, BatteryServiceStatus, IBatteryService, IBatteryServiceCallback,
};
use crate::battery_provider_manager::BatteryProviderManager;
use crate::callbacks::Callbacks;
use crate::uuid;
use crate::Message;
use crate::RPCProxy;
use std::collections::HashSet;
use std::sync::{Arc, Mutex};
use tokio::sync::mpsc::Sender;

/// The primary representation of battery information for internal
/// passing and external calls.
/// The primary representation of battery information for internal passing and external calls.
#[derive(Debug, Clone)]
pub struct BatterySet {
    /// Address of the remote device.
    pub address: String,
    /// UUID of where the battery info is decoded from as found in BT Spec.
    pub source_uuid: String,
    /// Information about the battery source, e.g. "BAS" or "HFP 1.8".
    pub source_info: String,
    /// Collection of batteries from this source.
    pub batteries: Vec<Battery>,
}

/// Describes an individual battery measurement, possibly one of many for a given device.
#[derive(Debug, Clone)]
pub struct Battery {
    /// Battery charge percentage between 0 and 100. For protocols that use 0-5 this will be that
    /// number multiplied by 20.
    pub percentage: u32,
    pub source_info: String,
    /// Description of this battery, such as Left, Right, or Case. Only present if the source has
    /// this level of detail.
    pub variant: String,
}

/// Helper representation of a collection of BatterySet to simplify passing around data internally.
pub struct Batteries(Vec<BatterySet>);

/// Callback for interacting with the BatteryManager.
pub trait IBatteryManagerCallback: RPCProxy {
    /// Invoked whenever battery information associated with the given remote changes.
    fn on_battery_info_updated(&self, remote_address: String, battery: Battery);
    fn on_battery_info_updated(&self, remote_address: String, battery_set: BatterySet);
}

/// Central point for getting battery information that might be sourced from numerous systems.
@@ -35,69 +51,36 @@ pub trait IBatteryManager {
    /// Unregister a callback.
    fn unregister_battery_callback(&mut self, callback_id: u32);

    /// Enables notifications for a given callback.
    fn enable_notifications(&mut self, callback_id: u32, enable: bool);

    /// Returns battery information for the remote, sourced from the highest priority origin.
    fn get_battery_information(&self, remote_address: String) -> Option<Battery>;
    fn get_battery_information(&self, remote_address: String) -> Option<BatterySet>;
}

/// Repesentation of the BatteryManager.
pub struct BatteryManager {
    bas: Arc<Mutex<Box<BatteryService>>>,
    battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>,
    callbacks: Callbacks<dyn IBatteryManagerCallback + Send>,
    /// List of callback IDs that have enabled notifications.
    notifications_enabled: HashSet<u32>,
}

impl BatteryManager {
    /// Construct a new BatteryManager with callbacks communicating on tx.
    pub fn new(bas: Arc<Mutex<Box<BatteryService>>>, tx: Sender<Message>) -> BatteryManager {
    pub fn new(
        battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>,
        tx: Sender<Message>,
    ) -> BatteryManager {
        let callbacks = Callbacks::new(tx.clone(), Message::BatteryManagerCallbackDisconnected);
        let notifications_enabled = HashSet::new();
        Self { bas, callbacks, notifications_enabled }
    }

    /// Invoked after BAS has been initialized.
    pub fn init(&self) {
        self.bas.lock().unwrap().register_callback(Box::new(BasCallback::new()));
        Self { battery_provider_manager, callbacks }
    }

    /// Remove a callback due to disconnection or unregistration.
    pub fn remove_callback(&mut self, callback_id: u32) {
        self.callbacks.remove_callback(callback_id);
    }
}

struct BasCallback {}

impl BasCallback {
    pub fn new() -> BasCallback {
        Self {}
    }
}

impl IBatteryServiceCallback for BasCallback {
    fn on_battery_service_status_updated(
        &self,
        _remote_address: String,
        _status: BatteryServiceStatus,
    ) {
        todo!()
    }

    fn on_battery_level_updated(&self, _remote_address: String, _battery_level: u32) {
        todo!()
    }

    fn on_battery_level_read(&self, _remote_address: String, _battery_level: u32) {
        todo!()
    }
}

impl RPCProxy for BasCallback {
    fn get_object_id(&self) -> String {
        "BAS Callback".to_string()
    /// Handles a BatterySet update.
    pub fn handle_battery_updated(&mut self, remote_address: String, battery_set: BatterySet) {
        self.callbacks.for_all_callbacks(|callback| {
            callback.on_battery_info_updated(remote_address.clone(), battery_set.clone())
        });
    }
}

@@ -113,24 +96,48 @@ impl IBatteryManager for BatteryManager {
        self.remove_callback(callback_id);
    }

    fn enable_notifications(&mut self, callback_id: u32, enable: bool) {
        if self.callbacks.get_by_id(callback_id).is_none() {
            return;
    fn get_battery_information(&self, remote_address: String) -> Option<BatterySet> {
        self.battery_provider_manager.lock().unwrap().get_battery_info(remote_address)
    }
}

impl BatterySet {
    pub fn new(address: String, source_uuid: String, source_info: String) -> Self {
        Self { address, source_uuid, source_info, batteries: vec![] }
    }
        self.notifications_enabled.remove(&callback_id);
        if enable {
            self.notifications_enabled.insert(callback_id);

    pub fn add_or_update_battery(&mut self, new_battery: Battery) {
        match self.batteries.iter_mut().find(|battery| battery.variant == new_battery.variant) {
            Some(battery) => *battery = new_battery,
            None => self.batteries.push(new_battery),
        }
    }
}

impl Batteries {
    pub fn new() -> Self {
        Self(vec![])
    }

    /// Updates a battery matching all non-battery-level fields if found, otherwise adds new_battery
    /// verbatim.
    pub fn add_or_update_battery_set(&mut self, new_battery_set: BatterySet) {
        match self
            .0
            .iter_mut()
            .find(|battery_set| battery_set.source_uuid == new_battery_set.source_uuid)
        {
            Some(battery_set) => *battery_set = new_battery_set,
            None => self.0.push(new_battery_set),
        }
    }

    // TODO(b/233101174): update to use all available sources once
    // BatteryProviderManager is implemented.
    fn get_battery_information(&self, remote_address: String) -> Option<Battery> {
        let battery_level = self.bas.lock().unwrap().get_battery_level(remote_address)?;
        Some(Battery {
            percentage: battery_level,
            source_info: "BAS".to_string(),
            variant: "".to_string(),
        })
    /// Returns the best BatterySet from among reported battery data.
    pub fn pick_best(&self) -> Option<BatterySet> {
        self.0
            .iter()
            .find(|battery_set| battery_set.source_uuid == uuid::BAS)
            .or_else(|| self.0.first())
            .cloned()
    }
}
+65 −26
Original line number Diff line number Diff line
use crate::battery_manager::Battery;

#[derive(Debug, Clone)]
pub struct BatteryProvider {
    pub source_info: String,
    pub remote_address: String,
}
use crate::battery_manager::{Batteries, BatterySet};
use crate::callbacks::Callbacks;
use crate::{Message, RPCProxy};
use std::collections::HashMap;
use tokio::sync::mpsc::Sender;

/// Callback for BatteryProvider implementers.
pub trait IBatteryProviderCallback {
pub trait IBatteryProviderCallback: RPCProxy {
    /// Requests that the BatteryProvider send updated battery information.
    fn refresh_battery_info(&self);
}

/// Interface for managing BatteryProvider instances.
pub trait IBatteryProviderManager {
    /// Registers a BatteryProvider and generates a unique batttery ID for future calls.
    /// Registers a BatteryProvider and generates a unique batttery provider ID for future calls.
    fn register_battery_provider(
        &mut self,
        battery_provider: BatteryProvider,
        battery_provider_callback: Box<dyn IBatteryProviderCallback + Send>,
    ) -> i32;
    ) -> u32;

    /// Unregisters a BatteryProvider, potentially removes battery information for the remote
    /// device if there are no other providers.
    fn unregister_battery_provider(&mut self, battery_id: i32);
    /// Unregisters a BatteryProvider, potentially removes battery information for the remote device
    /// if there are no other providers.
    fn unregister_battery_provider(&mut self, battery_provider_id: u32);

    /// Updates the battery information for the battery associated with battery_id.
    fn set_battery_percentage(&mut self, battery_id: i32, battery: Battery);
    fn set_battery_info(&mut self, battery_provider_id: u32, battery_set: BatterySet);
}

pub struct BatteryProviderManager {}
/// Represents the BatteryProviderManager, a central point for collecting battery information from
/// numerous sources.
pub struct BatteryProviderManager {
    /// Sender for callback communication with the main thread.
    tx: Sender<Message>,
    battery_provider_callbacks: Callbacks<dyn IBatteryProviderCallback + Send>,
    /// Stored information merged from all battery providers.
    battery_info: HashMap<String, Batteries>,
}

impl BatteryProviderManager {
    pub fn new() -> BatteryProviderManager {
        BatteryProviderManager {}
    /// Constructs a new BatteryProviderManager with callbacks communicating on tx.
    pub fn new(tx: Sender<Message>) -> BatteryProviderManager {
        let battery_provider_callbacks =
            Callbacks::new(tx.clone(), Message::BatteryProviderManagerCallbackDisconnected);
        let battery_info = HashMap::new();
        BatteryProviderManager { tx, battery_provider_callbacks, battery_info }
    }

    /// Request battery info refresh from all battery providers.
    pub fn refresh_battery_info(&self) {
        self.battery_provider_callbacks
            .for_all_callbacks(|callback| callback.refresh_battery_info());
    }

    /// Get the best battery info available for a given device.
    pub fn get_battery_info(&self, remote_address: String) -> Option<BatterySet> {
        self.battery_info.get(&remote_address)?.pick_best()
    }

    /// Removes a battery provider callback.
    pub fn remove_battery_provider_callback(&mut self, battery_provider_id: u32) {
        self.battery_provider_callbacks.remove_callback(battery_provider_id);
    }
}

impl IBatteryProviderManager for BatteryProviderManager {
    fn register_battery_provider(
        &mut self,
        _battery_provider: BatteryProvider,
        _battery_provider_callback: Box<dyn IBatteryProviderCallback + Send>,
    ) -> i32 {
        todo!()
        battery_provider_callback: Box<dyn IBatteryProviderCallback + Send>,
    ) -> u32 {
        self.battery_provider_callbacks.add_callback(battery_provider_callback)
    }

    fn unregister_battery_provider(&mut self, _battery_id: i32) {
        todo!()
    fn unregister_battery_provider(&mut self, battery_provider_id: u32) {
        self.remove_battery_provider_callback(battery_provider_id);
    }

    fn set_battery_percentage(&mut self, _battery_id: i32, _battery: Battery) {
        todo!()
    fn set_battery_info(&mut self, _battery_provider_id: u32, battery_set: BatterySet) {
        let batteries = self
            .battery_info
            .entry(battery_set.address.clone())
            .or_insert_with(|| Batteries::new());
        batteries.add_or_update_battery_set(battery_set);
        if let Some(best_battery_set) = batteries.pick_best() {
            let tx = self.tx.clone();
            tokio::spawn(async move {
                let _ = tx
                    .send(Message::BatteryProviderManagerBatteryUpdated(
                        best_battery_set.address.clone(),
                        best_battery_set,
                    ))
                    .await;
            });
        }
    }
}
Loading