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

Commit 7d26c219 authored by Sonny Sasaka's avatar Sonny Sasaka
Browse files

Floss: Implement (Un)RegisterScannerCallback

Implement the front-end of RegisterScannerCallback and
UnregisterScannerCallback, which only contain the registration and
unregistration of the callbacks. Follow up will be adding
RegisterScanner and UnregisterScanner for (un)registration of the
scanner itself.

This change also adds a reusable `Callbacks` utility in the `callbacks`
module. This utility provides callback logic common to many APIs:
* Adding a callback: generating an id, watching for disconnect.
* Removing a callback: stopping disconnect watcher, removing from
  storage.
* Utility to execute function on all callbacks (`for_all_callbacks`).

Future patch will refactor existing callback management using this
module to avoid code duplication and make sure consistent behavior.

Bug: 217273154
Tag: #floss
Test: Manual - Build Floss on Linux

Change-Id: Ie93287954298600155feaa0987a4f9c7e24253fe
parent c1bc8e16
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ use btstack::uuid::Profile;
use dbus::arg::RefArg;
use dbus::nonblock::SyncConnection;

use dbus_projection::{impl_dbus_arg_enum, ClientDBusProxy, DisconnectWatcher};
use dbus_projection::{dbus_generated, impl_dbus_arg_enum, ClientDBusProxy, DisconnectWatcher};

use dbus_macros::{
    dbus_method, dbus_propmap, generate_dbus_exporter, generate_dbus_interface_client,
@@ -549,20 +549,20 @@ impl BluetoothGattDBus {

#[generate_dbus_interface_client]
impl IBluetoothGatt for BluetoothGattDBus {
    fn register_scanner(&self, _callback: Box<dyn IScannerCallback + Send>) {
        // TODO(b/200066804): implement
    fn register_scanner_callback(&mut self, _callback: Box<dyn IScannerCallback + Send>) -> u32 {
        dbus_generated!()
    }

    fn unregister_scanner(&self, _scanner_id: i32) {
        // TODO(b/200066804): implement
    fn unregister_scanner_callback(&mut self, _scanner_id: u32) -> bool {
        dbus_generated!()
    }

    fn start_scan(&self, _scanner_id: i32, _settings: ScanSettings, _filters: Vec<ScanFilter>) {
        // TODO(b/200066804): implement
        dbus_generated!()
    }

    fn stop_scan(&self, _scanner_id: i32) {
        // TODO(b/200066804): implement
        dbus_generated!()
    }

    #[dbus_method("RegisterClient")]
+4 −4
Original line number Diff line number Diff line
@@ -202,13 +202,13 @@ struct IBluetoothGattDBus {}

#[generate_dbus_exporter(export_bluetooth_gatt_dbus_intf, "org.chromium.bluetooth.BluetoothGatt")]
impl IBluetoothGatt for IBluetoothGattDBus {
    #[dbus_method("RegisterScanner")]
    fn register_scanner(&self, callback: Box<dyn IScannerCallback + Send>) {
    #[dbus_method("RegisterScannerCallback")]
    fn register_scanner_callback(&mut self, callback: Box<dyn IScannerCallback + Send>) -> u32 {
        dbus_generated!()
    }

    #[dbus_method("UnregisterScanner")]
    fn unregister_scanner(&self, scanner_id: i32) {
    #[dbus_method("UnregisterScannerCallback")]
    fn unregister_scanner_callback(&mut self, scanner_id: u32) -> bool {
        dbus_generated!()
    }

+2 −1
Original line number Diff line number Diff line
@@ -80,7 +80,8 @@ fn main() -> Result<(), Box<dyn Error>> {

    let intf = Arc::new(Mutex::new(get_btinterface().unwrap()));
    let suspend = Arc::new(Mutex::new(Box::new(Suspend::new(intf.clone(), tx.clone()))));
    let bluetooth_gatt = Arc::new(Mutex::new(Box::new(BluetoothGatt::new(intf.clone()))));
    let bluetooth_gatt =
        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 bluetooth = Arc::new(Mutex::new(Box::new(Bluetooth::new(
+21 −9
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ use std::collections::HashSet;
use std::sync::{Arc, Mutex};
use tokio::sync::mpsc::Sender;

use crate::callbacks::Callbacks;
use crate::{Message, RPCProxy};

struct Client {
@@ -137,9 +138,13 @@ impl ContextMap {

/// Defines the GATT API.
pub trait IBluetoothGatt {
    fn register_scanner(&self, callback: Box<dyn IScannerCallback + Send>);
    /// Registers an LE scanner callback.
    ///
    /// Returns the callback id.
    fn register_scanner_callback(&mut self, callback: Box<dyn IScannerCallback + Send>) -> u32;

    fn unregister_scanner(&self, scanner_id: i32);
    /// Unregisters an LE scanner callback identified by the given id.
    fn unregister_scanner_callback(&mut self, scanner_id: u32) -> bool;

    fn start_scan(&self, scanner_id: i32, settings: ScanSettings, filters: Vec<ScanFilter>);
    fn stop_scan(&self, scanner_id: i32);
@@ -400,8 +405,9 @@ pub trait IBluetoothGattCallback: RPCProxy {
    fn on_service_changed(&self, addr: String);
}

/// Interface for scanner callbacks to clients, passed to `IBluetoothGatt::register_scanner`.
pub trait IScannerCallback {
/// Interface for scanner callbacks to clients, passed to
/// `IBluetoothGatt::register_scanner_callback`.
pub trait IScannerCallback: RPCProxy {
    /// When the `register_scanner` request is done.
    fn on_scanner_registered(&self, status: i32, scanner_id: i32);
}
@@ -485,16 +491,18 @@ pub struct BluetoothGatt {

    context_map: ContextMap,
    reliable_queue: HashSet<String>,
    callbacks: Callbacks<dyn IScannerCallback + Send>,
}

impl BluetoothGatt {
    /// Constructs a new IBluetoothGatt implementation.
    pub fn new(intf: Arc<Mutex<BluetoothInterface>>) -> BluetoothGatt {
    pub fn new(intf: Arc<Mutex<BluetoothInterface>>, tx: Sender<Message>) -> BluetoothGatt {
        BluetoothGatt {
            intf: intf,
            gatt: None,
            context_map: ContextMap::new(),
            reliable_queue: HashSet::new(),
            callbacks: Callbacks::new(tx.clone(), Message::ScannerCallbackDisconnected),
        }
    }

@@ -522,6 +530,10 @@ impl BluetoothGatt {
            },
        );
    }

    pub fn remove_scanner_callback(&mut self, id: u32) -> bool {
        self.callbacks.remove_callback(id)
    }
}

// Temporary util that covers only basic string conversion.
@@ -556,12 +568,12 @@ pub enum GattWriteRequestStatus {
}

impl IBluetoothGatt for BluetoothGatt {
    fn register_scanner(&self, _callback: Box<dyn IScannerCallback + Send>) {
        // TODO(b/200066804): implement
    fn register_scanner_callback(&mut self, callback: Box<dyn IScannerCallback + Send>) -> u32 {
        self.callbacks.add_callback(callback)
    }

    fn unregister_scanner(&self, _scanner_id: i32) {
        // TODO(b/200066804): implement
    fn unregister_scanner_callback(&mut self, scanner_id: u32) -> bool {
        self.callbacks.remove_callback(scanner_id)
    }

    fn start_scan(&self, _scanner_id: i32, _settings: ScanSettings, _filters: Vec<ScanFilter>) {
+75 −0
Original line number Diff line number Diff line
//! Provides utilities for managing callbacks.

use std::collections::HashMap;
use tokio::sync::mpsc::Sender;

use crate::{Message, RPCProxy};

/// Utility for managing callbacks conveniently.
pub struct Callbacks<T: Send + ?Sized> {
    callbacks: HashMap<u32, Box<T>>,
    tx: Sender<Message>,
    disconnected_message: fn(u32) -> Message,
}

impl<T: RPCProxy + Send + ?Sized> Callbacks<T> {
    /// Creates new Callbacks.
    ///
    /// Parameters:
    /// `tx`: Sender to use when notifying callback disconnect events.
    /// `disconnected_message`: Constructor of the message to be sent on callback disconnection.
    pub fn new(tx: Sender<Message>, disconnected_message: fn(u32) -> Message) -> Self {
        Self { callbacks: HashMap::new(), tx, disconnected_message }
    }

    /// Stores a new callback and monitors for callback disconnect.
    ///
    /// When the callback disconnects, a message is sent. This message should be handled and then
    /// the `remove_callback` function can be used.
    ///
    /// Returns the id of the callback.
    pub fn add_callback(&mut self, mut callback: Box<T>) -> u32 {
        let tx = self.tx.clone();
        let disconnected_message = self.disconnected_message;
        let id = callback.register_disconnect(Box::new(move |cb_id| {
            let tx = tx.clone();
            tokio::spawn(async move {
                let _result = tx.send(disconnected_message(cb_id)).await;
            });
        }));

        self.callbacks.insert(id, callback);
        id
    }

    /// Removes the callback given the id.
    ///
    /// When a callback is removed, disconnect monitoring is stopped and the proxy object is
    /// removed.
    ///
    /// Returns true if callback is removed, false if there is no such id.
    pub fn remove_callback(&mut self, id: u32) -> bool {
        match self.callbacks.get_mut(&id) {
            Some(callback) => {
                // Stop watching for disconnect.
                callback.unregister(id);
                // Remove the proxy object.
                self.callbacks.remove(&id);
                true
            }
            None => false,
        }
    }

    /// Returns the callback object based on the given id.
    pub fn get_by_id(&mut self, id: u32) -> Option<&mut Box<T>> {
        self.callbacks.get_mut(&id)
    }

    /// Applies the given function on all active callbacks.
    pub fn for_all_callbacks<F: Fn(&Box<T>)>(&self, f: F) {
        for (_, callback) in self.callbacks.iter() {
            f(&callback);
        }
    }
}
Loading