Integrate the devices respository (#30974)

Despite the name of this dependency, it only handles bluetooth. Because
it's a separate repository. Integrating it, allows changes here to be
tested more consistently. In addition, it's likely that new bluetooth
libraries will allow removing the majority of the platform-specific code
in this directory.

This is based on the version of this dependency from:
https://github.com/servo/devices/pull/34
This commit is contained in:
Martin Robinson 2024-01-09 10:13:41 +01:00 committed by GitHub
parent fddc4a430f
commit 6a804cd775
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 3880 additions and 27 deletions

View file

@ -13,7 +13,7 @@ path = "lib.rs"
[dependencies]
bitflags = { workspace = true }
bluetooth_traits = { workspace = true }
device = { git = "https://github.com/servo/devices", features = ["bluetooth-test"], rev = "cb28c4725ffbfece99dab842d17d3e8c50774778" }
blurmock = { version = "0.1.2", optional = true }
embedder_traits = { workspace = true }
ipc-channel = { workspace = true }
log = { workspace = true }
@ -22,4 +22,14 @@ servo_rand = { path = "../rand" }
uuid = { workspace = true }
[features]
native-bluetooth = ["device/bluetooth"]
native-bluetooth = ["blurz", "blurdroid", "blurmac", "bluetooth-test"]
bluetooth-test = ["blurmock"]
[target.'cfg(target_os = "linux")'.dependencies]
blurz = { version = "0.3", optional = true }
[target.'cfg(target_os = "android")'.dependencies]
blurdroid = { version = "0.1.2", optional = true }
[target.'cfg(target_os = "macos")'.dependencies]
blurmac = { path = "../../third_party/blurmac", optional = true }

View file

@ -0,0 +1,55 @@
# Bluetooth Rust lib using macOS CoreBluetooth
[![Build Status](https://travis-ci.org/akosthekiss/blurmac.svg?branch=master)](https://travis-ci.org/akosthekiss/blurmac)
[![Crates.io](https://img.shields.io/crates/v/blurmac.svg)](https://crates.io/crates/blurmac)
The main aim of BlurMac is to enable [WebBluetooth](https://webbluetoothcg.github.io)
in [Servo](https://github.com/servo/servo) on macOS. Thus, API and implementation
decisions are affected by the encapsulating [Devices](https://github.com/servo/devices),
and the sibling [BlurZ](https://github.com/szeged/blurz) and [BlurDroid](https://github.com/szeged/blurdroid)
crates.
## Run Servo with WebBluetooth Enabled
Usually, you don't want to work with BlurMac on its own but use it within Servo.
So, most probably you'll want to run Servo with WebBluetooth enabled:
```
RUST_LOG=blurmac \
./mach run \
--dev \
--pref=dom.bluetooth.enabled \
--pref=dom.permissions.testing.allowed_in_nonsecure_contexts \
URL
```
Notes:
* The above command is actually not really BlurMac-specific (except for the `RUST_LOG`
part). It runs Servo with WBT enabled on any platform where WBT is supported.
* You don't need the `RUST_LOG=blurmac` part if you don't want to see BlurMac debug
messages on the console.
* You don't need the `--dev` part if you want to run a release build.
* You don't need the `--pref=dom.permissions.testing.allowed_in_nonsecure_contexts`
part if your `URL` is https (but you do need it if you test a local file).
## Known Issues
* Device RSSI can not be retrieved yet.
* Support for included services is incomplete.
* Descriptors are not supported yet.
* Notifications on characteristics are not supported yet (the limitation comes from
Devices).
## Compatibility
Tested on:
* macOS Sierra 10.12.
## Copyright and Licensing
Licensed under the BSD 3-Clause [License](LICENSE.md).

View file

@ -0,0 +1,408 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::error::Error;
use std::sync::Arc;
#[cfg(all(target_os = "android", feature = "bluetooth"))]
use blurdroid::bluetooth_adapter::Adapter as BluetoothAdapterAndroid;
#[cfg(all(target_os = "android", feature = "bluetooth"))]
use blurdroid::bluetooth_device::Device as BluetoothDeviceAndroid;
#[cfg(all(target_os = "android", feature = "bluetooth"))]
use blurdroid::bluetooth_discovery_session::DiscoverySession as BluetoothDiscoverySessionAndroid;
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
use blurmac::BluetoothAdapter as BluetoothAdapterMac;
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
use blurmac::BluetoothDevice as BluetoothDeviceMac;
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
use blurmac::BluetoothDiscoverySession as BluetoothDiscoverySessionMac;
#[cfg(feature = "bluetooth-test")]
use blurmock::fake_adapter::FakeBluetoothAdapter;
#[cfg(feature = "bluetooth-test")]
use blurmock::fake_device::FakeBluetoothDevice;
#[cfg(feature = "bluetooth-test")]
use blurmock::fake_discovery_session::FakeBluetoothDiscoverySession;
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
use blurz::bluetooth_adapter::BluetoothAdapter as BluetoothAdapterBluez;
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
use blurz::bluetooth_device::BluetoothDevice as BluetoothDeviceBluez;
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
use blurz::bluetooth_discovery_session::BluetoothDiscoverySession as BluetoothDiscoverySessionBluez;
use super::bluetooth::{BluetoothDevice, BluetoothDiscoverySession};
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
use super::empty::BluetoothDevice as BluetoothDeviceEmpty;
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
use super::empty::BluetoothDiscoverySession as BluetoothDiscoverySessionEmpty;
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
use super::empty::EmptyAdapter as BluetoothAdapterEmpty;
use super::macros::get_inner_and_call;
#[cfg(feature = "bluetooth-test")]
use super::macros::get_inner_and_call_test_func;
#[derive(Clone, Debug)]
pub enum BluetoothAdapter {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
Bluez(Arc<BluetoothAdapterBluez>),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
Android(Arc<BluetoothAdapterAndroid>),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
Mac(Arc<BluetoothAdapterMac>),
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
Empty(Arc<BluetoothAdapterEmpty>),
#[cfg(feature = "bluetooth-test")]
Mock(Arc<FakeBluetoothAdapter>),
}
impl BluetoothAdapter {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
let bluez_adapter = BluetoothAdapterBluez::init()?;
Ok(Self::Bluez(Arc::new(bluez_adapter)))
}
#[cfg(all(target_os = "android", feature = "bluetooth"))]
pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
let blurdroid_adapter = BluetoothAdapterAndroid::get_adapter()?;
Ok(Self::Android(Arc::new(blurdroid_adapter)))
}
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
let mac_adapter = BluetoothAdapterMac::init()?;
Ok(Self::Mac(Arc::new(mac_adapter)))
}
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
let adapter = BluetoothAdapterEmpty::init()?;
Ok(Self::Empty(Arc::new(adapter)))
}
#[cfg(feature = "bluetooth-test")]
pub fn new_mock() -> Result<BluetoothAdapter, Box<dyn Error>> {
Ok(Self::Mock(FakeBluetoothAdapter::new_empty()))
}
pub fn get_id(&self) -> String {
get_inner_and_call!(self, BluetoothAdapter, get_id)
}
pub fn get_devices(&self) -> Result<Vec<BluetoothDevice>, Box<dyn Error>> {
match self {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
BluetoothAdapter::Bluez(inner) => {
let device_list = inner.get_device_list()?;
Ok(device_list
.into_iter()
.map(|device| {
BluetoothDevice::Bluez(BluetoothDeviceBluez::new_empty(
self.0.clone(),
device,
))
})
.collect())
},
#[cfg(all(target_os = "android", feature = "bluetooth"))]
BluetoothAdapter::Android(inner) => {
let device_list = inner.get_device_list()?;
Ok(device_list
.into_iter()
.map(|device| {
BluetoothDevice::Android(BluetoothDeviceAndroid::new_empty(
self.0.clone(),
device,
))
})
.collect())
},
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
BluetoothAdapter::Mac(inner) => {
let device_list = inner.get_device_list()?;
Ok(device_list
.into_iter()
.map(|device| {
BluetoothDevice::Mac(Arc::new(BluetoothDeviceMac::new(
inner.clone(),
device,
)))
})
.collect())
},
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
BluetoothAdapter::Empty(inner) => {
let device_list = inner.get_device_list()?;
Ok(device_list
.into_iter()
.map(|device| {
BluetoothDevice::Empty(Arc::new(BluetoothDeviceEmpty::new(device)))
})
.collect())
},
#[cfg(feature = "bluetooth-test")]
BluetoothAdapter::Mock(inner) => {
let device_list = inner.get_device_list()?;
Ok(device_list
.into_iter()
.map(|device| {
BluetoothDevice::Mock(FakeBluetoothDevice::new_empty(inner.clone(), device))
})
.collect())
},
}
}
pub fn get_device(&self, address: String) -> Result<Option<BluetoothDevice>, Box<dyn Error>> {
let devices = self.get_devices()?;
for device in devices {
if device.get_address()? == address {
return Ok(Some(device));
}
}
Ok(None)
}
pub fn create_mock_device(&self, _device: String) -> Result<BluetoothDevice, Box<dyn Error>> {
match self {
#[cfg(feature = "bluetooth-test")]
BluetoothAdapter::Mock(inner) => Ok(BluetoothDevice::Mock(
FakeBluetoothDevice::new_empty(inner.clone(), _device),
)),
_ => Err(Box::from(
"Error! Test functions are not supported on real devices!",
)),
}
}
pub fn create_discovery_session(&self) -> Result<BluetoothDiscoverySession, Box<dyn Error>> {
let discovery_session = match self {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
BluetoothAdapter::Bluez(inner) => {
BluetoothDiscoverySession::Bluez(Arc::new(
BluetoothDiscoverySessionBluez::create_session(inner.get_id())?,
));
},
#[cfg(all(target_os = "android", feature = "bluetooth"))]
BluetoothAdapter::Android(inner) => BluetoothDiscoverySession::Android(Arc::new(
BluetoothDiscoverySessionAndroid::create_session(inner.clone())?,
)),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
BluetoothAdapter::Mac(_) => {
BluetoothDiscoverySession::Mac(Arc::new(BluetoothDiscoverySessionMac {}))
},
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
BluetoothAdapter::Empty(_) => {
BluetoothDiscoverySession::Empty(Arc::new(BluetoothDiscoverySessionEmpty {}))
},
#[cfg(feature = "bluetooth-test")]
BluetoothAdapter::Mock(inner) => BluetoothDiscoverySession::Mock(Arc::new(
FakeBluetoothDiscoverySession::create_session(inner.clone())?,
)),
};
Ok(discovery_session)
}
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_address)
}
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_name)
}
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_alias)
}
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_class)
}
pub fn is_powered(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, is_powered)
}
pub fn is_discoverable(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, is_discoverable)
}
pub fn is_pairable(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, is_pairable)
}
pub fn get_pairable_timeout(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_pairable_timeout)
}
pub fn get_discoverable_timeout(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_discoverable_timeout)
}
pub fn is_discovering(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, is_discovering)
}
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_uuids)
}
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_vendor_id_source)
}
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_vendor_id)
}
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_product_id)
}
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_device_id)
}
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothAdapter, get_modalias)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_id(&self, id: String) -> Result<(), Box<dyn Error>> {
match self {
#[cfg(feature = "bluetooth-test")]
BluetoothAdapter::Mock(inner) => Ok(inner.set_id(id)),
_ => Err(Box::from(
"Error! Test functions are not supported on real devices!",
)),
}
}
#[cfg(feature = "bluetooth-test")]
pub fn set_address(&self, address: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_address, address)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_name(&self, name: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_name, name)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_alias(&self, alias: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_alias, alias)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_class(&self, class: u32) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_class, class)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_powered(&self, powered: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_powered, powered)
}
#[cfg(feature = "bluetooth-test")]
pub fn is_present(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, is_present)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_present(&self, present: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_present, present)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_discoverable(&self, discoverable: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_discoverable, discoverable)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_pairable(&self, pairable: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_pairable, pairable)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_pairable_timeout(&self, timeout: u32) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_pairable_timeout, timeout)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_can_start_discovery(&self, can_start_discovery: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(
self,
BluetoothAdapter,
set_can_start_discovery,
can_start_discovery
)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_discoverable_timeout(&self, timeout: u32) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_discoverable_timeout, timeout)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_discovering(&self, discovering: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_discovering, discovering)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_can_stop_discovery(&self, can_stop_discovery: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(
self,
BluetoothAdapter,
set_can_stop_discovery,
can_stop_discovery
)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_uuids(&self, uuids: Vec<String>) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_uuids, uuids)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_modalias(&self, modalias: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_modalias, modalias)
}
#[cfg(feature = "bluetooth-test")]
pub fn get_ad_datas(&self) -> Result<Vec<String>, Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, get_ad_datas)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_ad_datas(&self, ad_datas: Vec<String>) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothAdapter, set_ad_datas, ad_datas)
}
}

View file

@ -0,0 +1,753 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::collections::HashMap;
use std::error::Error;
use std::sync::Arc;
#[cfg(all(target_os = "android", feature = "bluetooth"))]
use blurdroid::bluetooth_device::Device as BluetoothDeviceAndroid;
#[cfg(all(target_os = "android", feature = "bluetooth"))]
use blurdroid::bluetooth_discovery_session::DiscoverySession as BluetoothDiscoverySessionAndroid;
#[cfg(all(target_os = "android", feature = "bluetooth"))]
use blurdroid::bluetooth_gatt_characteristic::Characteristic as BluetoothGATTCharacteristicAndroid;
#[cfg(all(target_os = "android", feature = "bluetooth"))]
use blurdroid::bluetooth_gatt_descriptor::Descriptor as BluetoothGATTDescriptorAndroid;
#[cfg(all(target_os = "android", feature = "bluetooth"))]
use blurdroid::bluetooth_gatt_service::Service as BluetoothGATTServiceAndroid;
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
use blurmac::BluetoothDevice as BluetoothDeviceMac;
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
use blurmac::BluetoothDiscoverySession as BluetoothDiscoverySessionMac;
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
use blurmac::BluetoothGATTCharacteristic as BluetoothGATTCharacteristicMac;
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
use blurmac::BluetoothGATTDescriptor as BluetoothGATTDescriptorMac;
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
use blurmac::BluetoothGATTService as BluetoothGATTServiceMac;
#[cfg(feature = "bluetooth-test")]
use blurmock::fake_characteristic::FakeBluetoothGATTCharacteristic;
#[cfg(feature = "bluetooth-test")]
use blurmock::fake_descriptor::FakeBluetoothGATTDescriptor;
#[cfg(feature = "bluetooth-test")]
use blurmock::fake_device::FakeBluetoothDevice;
#[cfg(feature = "bluetooth-test")]
use blurmock::fake_discovery_session::FakeBluetoothDiscoverySession;
#[cfg(feature = "bluetooth-test")]
use blurmock::fake_service::FakeBluetoothGATTService;
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
use blurz::bluetooth_device::BluetoothDevice as BluetoothDeviceBluez;
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
use blurz::bluetooth_discovery_session::BluetoothDiscoverySession as BluetoothDiscoverySessionBluez;
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
use blurz::bluetooth_gatt_characteristic::BluetoothGATTCharacteristic as BluetoothGATTCharacteristicBluez;
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
use blurz::bluetooth_gatt_descriptor::BluetoothGATTDescriptor as BluetoothGATTDescriptorBluez;
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
use blurz::bluetooth_gatt_service::BluetoothGATTService as BluetoothGATTServiceBluez;
pub use super::adapter::BluetoothAdapter;
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
use super::empty::BluetoothDevice as BluetoothDeviceEmpty;
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
use super::empty::BluetoothDiscoverySession as BluetoothDiscoverySessionEmpty;
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
use super::empty::BluetoothGATTCharacteristic as BluetoothGATTCharacteristicEmpty;
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
use super::empty::BluetoothGATTDescriptor as BluetoothGATTDescriptorEmpty;
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
use super::empty::BluetoothGATTService as BluetoothGATTServiceEmpty;
use super::macros::get_inner_and_call;
#[cfg(feature = "bluetooth-test")]
use super::macros::get_inner_and_call_test_func;
#[cfg(feature = "bluetooth-test")]
const NOT_SUPPORTED_ON_MOCK_ERROR: &'static str =
"Error! The first parameter must be a mock structure!";
#[derive(Debug)]
pub enum BluetoothDiscoverySession {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
Bluez(Arc<BluetoothDiscoverySessionBluez>),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
Android(Arc<BluetoothDiscoverySessionAndroid>),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
Mac(Arc<BluetoothDiscoverySessionMac>),
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
Empty(Arc<BluetoothDiscoverySessionEmpty>),
#[cfg(feature = "bluetooth-test")]
Mock(Arc<FakeBluetoothDiscoverySession>),
}
#[derive(Clone, Debug)]
pub enum BluetoothDevice {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
Bluez(Arc<BluetoothDeviceBluez>),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
Android(Arc<BluetoothDeviceAndroid>),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
Mac(Arc<BluetoothDeviceMac>),
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
Empty(Arc<BluetoothDeviceEmpty>),
#[cfg(feature = "bluetooth-test")]
Mock(Arc<FakeBluetoothDevice>),
}
#[derive(Clone, Debug)]
pub enum BluetoothGATTService {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
Bluez(Arc<BluetoothGATTServiceBluez>),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
Android(Arc<BluetoothGATTServiceAndroid>),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
Mac(Arc<BluetoothGATTServiceMac>),
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
Empty(Arc<BluetoothGATTServiceEmpty>),
#[cfg(feature = "bluetooth-test")]
Mock(Arc<FakeBluetoothGATTService>),
}
#[derive(Clone, Debug)]
pub enum BluetoothGATTCharacteristic {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
Bluez(Arc<BluetoothGATTCharacteristicBluez>),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
Android(Arc<BluetoothGATTCharacteristicAndroid>),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
Mac(Arc<BluetoothGATTCharacteristicMac>),
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
Empty(Arc<BluetoothGATTCharacteristicEmpty>),
#[cfg(feature = "bluetooth-test")]
Mock(Arc<FakeBluetoothGATTCharacteristic>),
}
#[derive(Clone, Debug)]
pub enum BluetoothGATTDescriptor {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
Bluez(Arc<BluetoothGATTDescriptorBluez>),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
Android(Arc<BluetoothGATTDescriptorAndroid>),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
Mac(Arc<BluetoothGATTDescriptorMac>),
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
Empty(Arc<BluetoothGATTDescriptorEmpty>),
#[cfg(feature = "bluetooth-test")]
Mock(Arc<FakeBluetoothGATTDescriptor>),
}
impl BluetoothDiscoverySession {
pub fn start_discovery(&self) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDiscoverySession, start_discovery)
}
pub fn stop_discovery(&self) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDiscoverySession, stop_discovery)
}
}
impl BluetoothDevice {
pub fn get_id(&self) -> String {
get_inner_and_call!(self, BluetoothDevice, get_id)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_id(&self, id: String) {
match self {
&BluetoothDevice::Mock(ref fake_adapter) => fake_adapter.set_id(id),
_ => (),
}
}
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_address)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_address(&self, address: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_address, address)
}
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_name)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_name(&self, name: Option<String>) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_name, name)
}
pub fn get_icon(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_icon)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_icon(&self, icon: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_icon, icon)
}
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_class)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_class(&self, class: u32) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_class, class)
}
pub fn get_appearance(&self) -> Result<u16, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_appearance)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_appearance(&self, appearance: u16) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_appearance, Some(appearance))
}
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_uuids)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_uuids(&self, uuids: Vec<String>) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_uuids, uuids)
}
pub fn is_paired(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, is_paired)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_paired(&self, paired: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_paired, paired)
}
pub fn is_connected(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, is_connected)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_connected(&self, connected: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_connected, connected)
}
#[cfg(feature = "bluetooth-test")]
pub fn is_connectable(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, is_connectable)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_connectable(&self, connectable: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_connectable, connectable)
}
pub fn is_trusted(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, is_trusted)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_trusted(&self, trusted: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_trusted, trusted)
}
pub fn is_blocked(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, is_blocked)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_blocked(&self, blocked: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_blocked, blocked)
}
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_alias)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_alias(&self, alias: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_alias, alias)
}
pub fn is_legacy_pairing(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, is_legacy_pairing)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_legacy_pairing(&self, legacy_pairing: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_legacy_pairing, legacy_pairing)
}
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_vendor_id_source)
}
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_vendor_id)
}
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_product_id)
}
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_device_id)
}
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_modalias)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_modalias(&self, modalias: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_modalias, modalias)
}
pub fn get_rssi(&self) -> Result<i16, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_rssi)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_rssi(&self, rssi: i16) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_rssi, Some(rssi))
}
pub fn get_tx_power(&self) -> Result<i16, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_tx_power)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_tx_power(&self, tx_power: i16) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_tx_power, Some(tx_power))
}
pub fn get_manufacturer_data(&self) -> Result<HashMap<u16, Vec<u8>>, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_manufacturer_data)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_manufacturer_data(
&self,
manufacturer_data: HashMap<u16, Vec<u8>>,
) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(
self,
BluetoothDevice,
set_manufacturer_data,
Some(manufacturer_data)
)
}
pub fn get_service_data(&self) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, get_service_data)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_service_data(
&self,
service_data: HashMap<String, Vec<u8>>,
) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothDevice, set_service_data, Some(service_data))
}
pub fn get_gatt_services(&self) -> Result<Vec<BluetoothGATTService>, Box<dyn Error>> {
let services = get_inner_and_call!(self, BluetoothDevice, get_gatt_services)?;
Ok(services
.into_iter()
.map(|service| BluetoothGATTService::create_service(self.clone(), service))
.collect())
}
pub fn connect(&self) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, connect)
}
pub fn disconnect(&self) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, disconnect)
}
pub fn connect_profile(&self, uuid: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, connect_profile, uuid)
}
pub fn disconnect_profile(&self, uuid: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, disconnect_profile, uuid)
}
pub fn pair(&self) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, pair)
}
pub fn cancel_pairing(&self) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothDevice, cancel_pairing)
}
}
impl BluetoothGATTService {
fn create_service(device: BluetoothDevice, service: String) -> BluetoothGATTService {
match device {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
BluetoothDevice::Bluez(_bluez_device) => {
BluetoothGATTService::Bluez(Arc::new(BluetoothGATTServiceBluez::new(service)))
},
#[cfg(all(target_os = "android", feature = "bluetooth"))]
BluetoothDevice::Android(android_device) => BluetoothGATTService::Android(Arc::new(
BluetoothGATTServiceAndroid::new(android_device, service),
)),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
BluetoothDevice::Mac(mac_device) => BluetoothGATTService::Mac(Arc::new(
BluetoothGATTServiceMac::new(mac_device, service),
)),
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
BluetoothDevice::Empty(_device) => {
BluetoothGATTService::Empty(Arc::new(BluetoothGATTServiceEmpty::new(service)))
},
#[cfg(feature = "bluetooth-test")]
BluetoothDevice::Mock(fake_device) => BluetoothGATTService::Mock(
FakeBluetoothGATTService::new_empty(fake_device, service),
),
}
}
#[cfg(feature = "bluetooth-test")]
pub fn create_mock_service(
device: BluetoothDevice,
service: String,
) -> Result<BluetoothGATTService, Box<dyn Error>> {
match device {
BluetoothDevice::Mock(fake_device) => Ok(BluetoothGATTService::Mock(
FakeBluetoothGATTService::new_empty(fake_device, service),
)),
_ => Err(Box::from(
"Error! The first parameter must be a mock structure!",
)),
}
}
pub fn get_id(&self) -> String {
get_inner_and_call!(self, BluetoothGATTService, get_id)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_id(&self, id: String) {
match self {
&BluetoothGATTService::Mock(ref fake_service) => fake_service.set_id(id),
_ => (),
}
}
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTService, get_uuid)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_uuid(&self, uuid: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothGATTService, set_uuid, uuid)
}
pub fn is_primary(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTService, is_primary)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_primary(&self, primary: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothGATTService, set_is_primary, primary)
}
pub fn get_includes(
&self,
device: BluetoothDevice,
) -> Result<Vec<BluetoothGATTService>, Box<dyn Error>> {
let services = get_inner_and_call!(self, BluetoothGATTService, get_includes)?;
Ok(services
.into_iter()
.map(|service| BluetoothGATTService::create_service(device.clone(), service))
.collect())
}
pub fn get_gatt_characteristics(
&self,
) -> Result<Vec<BluetoothGATTCharacteristic>, Box<dyn Error>> {
let characteristics =
get_inner_and_call!(self, BluetoothGATTService, get_gatt_characteristics)?;
Ok(characteristics
.into_iter()
.map(|characteristic| {
BluetoothGATTCharacteristic::create_characteristic(self.clone(), characteristic)
})
.collect())
}
}
impl BluetoothGATTCharacteristic {
fn create_characteristic(
service: BluetoothGATTService,
characteristic: String,
) -> BluetoothGATTCharacteristic {
match service {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
BluetoothGATTService::Bluez(_bluez_service) => BluetoothGATTCharacteristic::Bluez(
Arc::new(BluetoothGATTCharacteristicBluez::new(characteristic)),
),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
BluetoothGATTService::Android(android_service) => {
BluetoothGATTCharacteristic::Android(Arc::new(
BluetoothGATTCharacteristicAndroid::new(android_service, characteristic),
))
},
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
BluetoothGATTService::Mac(mac_service) => BluetoothGATTCharacteristic::Mac(Arc::new(
BluetoothGATTCharacteristicMac::new(mac_service, characteristic),
)),
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
BluetoothGATTService::Empty(_service) => BluetoothGATTCharacteristic::Empty(Arc::new(
BluetoothGATTCharacteristicEmpty::new(characteristic),
)),
#[cfg(feature = "bluetooth-test")]
BluetoothGATTService::Mock(fake_service) => BluetoothGATTCharacteristic::Mock(
FakeBluetoothGATTCharacteristic::new_empty(fake_service, characteristic),
),
}
}
#[cfg(feature = "bluetooth-test")]
pub fn create_mock_characteristic(
service: BluetoothGATTService,
characteristic: String,
) -> Result<BluetoothGATTCharacteristic, Box<dyn Error>> {
match service {
BluetoothGATTService::Mock(fake_service) => Ok(BluetoothGATTCharacteristic::Mock(
FakeBluetoothGATTCharacteristic::new_empty(fake_service, characteristic),
)),
_ => Err(Box::from(
"Error! The first parameter must be a mock structure!",
)),
}
}
pub fn get_id(&self) -> String {
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_id)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_id(&self, id: String) {
match self {
&BluetoothGATTCharacteristic::Mock(ref fake_characteristic) => {
fake_characteristic.set_id(id)
},
_ => (),
}
}
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_uuid)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_uuid(&self, uuid: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothGATTCharacteristic, set_uuid, uuid)
}
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_value)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_value(&self, value: Vec<u8>) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothGATTCharacteristic, set_value, Some(value))
}
pub fn is_notifying(&self) -> Result<bool, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTCharacteristic, is_notifying)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_notifying(&self, notifying: bool) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothGATTCharacteristic, set_notifying, notifying)
}
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_flags)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_flags(&self, flags: Vec<String>) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothGATTCharacteristic, set_flags, flags)
}
pub fn get_gatt_descriptors(&self) -> Result<Vec<BluetoothGATTDescriptor>, Box<dyn Error>> {
let descriptors =
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_gatt_descriptors)?;
Ok(descriptors
.into_iter()
.map(|descriptor| BluetoothGATTDescriptor::create_descriptor(self.clone(), descriptor))
.collect())
}
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
get_inner_and_call!(@with_bluez_offset, self, BluetoothGATTCharacteristic, read_value)
}
pub fn write_value(&self, values: Vec<u8>) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(@with_bluez_offset, self, BluetoothGATTCharacteristic, write_value, values)
}
pub fn start_notify(&self) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTCharacteristic, start_notify)
}
pub fn stop_notify(&self) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTCharacteristic, stop_notify)
}
}
impl BluetoothGATTDescriptor {
fn create_descriptor(
characteristic: BluetoothGATTCharacteristic,
descriptor: String,
) -> BluetoothGATTDescriptor {
match characteristic {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
BluetoothGATTCharacteristic::Bluez(_bluez_characteristic) => {
BluetoothGATTDescriptor::Bluez(Arc::new(BluetoothGATTDescriptorBluez::new(
descriptor,
)))
},
#[cfg(all(target_os = "android", feature = "bluetooth"))]
BluetoothGATTCharacteristic::Android(android_characteristic) => {
BluetoothGATTDescriptor::Android(Arc::new(BluetoothGATTDescriptorAndroid::new(
android_characteristic,
descriptor,
)))
},
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
BluetoothGATTCharacteristic::Mac(_mac_characteristic) => {
BluetoothGATTDescriptor::Mac(Arc::new(BluetoothGATTDescriptorMac::new(descriptor)))
},
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
BluetoothGATTCharacteristic::Empty(_characteristic) => BluetoothGATTDescriptor::Empty(
Arc::new(BluetoothGATTDescriptorEmpty::new(descriptor)),
),
#[cfg(feature = "bluetooth-test")]
BluetoothGATTCharacteristic::Mock(fake_characteristic) => {
BluetoothGATTDescriptor::Mock(FakeBluetoothGATTDescriptor::new_empty(
fake_characteristic,
descriptor,
))
},
}
}
#[cfg(feature = "bluetooth-test")]
pub fn create_mock_descriptor(
characteristic: BluetoothGATTCharacteristic,
descriptor: String,
) -> Result<BluetoothGATTDescriptor, Box<dyn Error>> {
match characteristic {
BluetoothGATTCharacteristic::Mock(fake_characteristic) => {
Ok(BluetoothGATTDescriptor::Mock(
FakeBluetoothGATTDescriptor::new_empty(fake_characteristic, descriptor),
))
},
_ => Err(Box::from(NOT_SUPPORTED_ON_MOCK_ERROR)),
}
}
pub fn get_id(&self) -> String {
get_inner_and_call!(self, BluetoothGATTDescriptor, get_id)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_id(&self, id: String) {
match self {
&BluetoothGATTDescriptor::Mock(ref fake_descriptor) => fake_descriptor.set_id(id),
_ => (),
}
}
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTDescriptor, get_uuid)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_uuid(&self, uuid: String) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothGATTDescriptor, set_uuid, uuid)
}
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTDescriptor, get_value)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_value(&self, value: Vec<u8>) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothGATTDescriptor, set_value, Some(value))
}
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
get_inner_and_call!(self, BluetoothGATTDescriptor, get_flags)
}
#[cfg(feature = "bluetooth-test")]
pub fn set_flags(&self, flags: Vec<String>) -> Result<(), Box<dyn Error>> {
get_inner_and_call_test_func!(self, BluetoothGATTDescriptor, set_flags, flags)
}
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
get_inner_and_call!(@with_bluez_offset, self, BluetoothGATTDescriptor, read_value)
}
pub fn write_value(&self, values: Vec<u8>) -> Result<(), Box<dyn Error>> {
get_inner_and_call!(@with_bluez_offset, self, BluetoothGATTDescriptor, write_value, values)
}
}

View file

@ -0,0 +1,377 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::collections::HashMap;
use std::error::Error;
use std::sync::Arc;
const NOT_SUPPORTED_ERROR: &'static str = "Error! Not supported platform!";
#[derive(Clone, Debug)]
pub struct EmptyAdapter {}
impl EmptyAdapter {
pub fn init() -> Result<EmptyAdapter, Box<dyn Error>> {
Ok(EmptyAdapter::new())
}
fn new() -> EmptyAdapter {
EmptyAdapter {}
}
pub fn get_id(&self) -> String {
String::new()
}
pub fn get_device_list(&self) -> Result<Vec<String>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn set_alias(&self, _value: String) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_powered(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn set_powered(&self, _value: bool) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_discoverable(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn set_discoverable(&self, _value: bool) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_pairable(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn set_pairable(&self, _value: bool) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_pairable_timeout(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn set_pairable_timeout(&self, _value: u32) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_discoverable_timeout(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn set_discoverable_timeout(&self, _value: u32) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_discovering(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
}
#[derive(Clone, Debug)]
pub struct BluetoothDiscoverySession {}
impl BluetoothDiscoverySession {
pub fn create_session(
_adapter: Arc<EmptyAdapter>,
) -> Result<BluetoothDiscoverySession, Box<dyn Error>> {
Ok(BluetoothDiscoverySession {})
}
pub fn start_discovery(&self) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn stop_discovery(&self) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
}
#[derive(Clone, Debug)]
pub struct BluetoothDevice {}
impl BluetoothDevice {
pub fn new(_device: String) -> BluetoothDevice {
BluetoothDevice {}
}
pub fn get_id(&self) -> String {
String::new()
}
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_icon(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_appearance(&self) -> Result<u16, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_paired(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_connected(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_trusted(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_blocked(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn set_alias(&self, _value: String) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_legacy_pairing(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_rssi(&self) -> Result<i16, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_tx_power(&self) -> Result<i16, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_manufacturer_data(&self) -> Result<HashMap<u16, Vec<u8>>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_service_data(&self) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_gatt_services(&self) -> Result<Vec<String>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn connect(&self) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn disconnect(&self) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn connect_profile(&self, _uuid: String) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn disconnect_profile(&self, _uuid: String) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn pair(&self) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn cancel_pairing(&self) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
}
#[derive(Clone, Debug)]
pub struct BluetoothGATTService {}
impl BluetoothGATTService {
pub fn new(_service: String) -> BluetoothGATTService {
BluetoothGATTService {}
}
pub fn get_id(&self) -> String {
String::new()
}
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_primary(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_includes(&self) -> Result<Vec<String>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_gatt_characteristics(&self) -> Result<Vec<String>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
}
#[derive(Clone, Debug)]
pub struct BluetoothGATTCharacteristic {}
impl BluetoothGATTCharacteristic {
pub fn new(_characteristic: String) -> BluetoothGATTCharacteristic {
BluetoothGATTCharacteristic {}
}
pub fn get_id(&self) -> String {
String::new()
}
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn is_notifying(&self) -> Result<bool, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_gatt_descriptors(&self) -> Result<Vec<String>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn write_value(&self, _values: Vec<u8>) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn start_notify(&self) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn stop_notify(&self) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
}
#[derive(Clone, Debug)]
pub struct BluetoothGATTDescriptor {}
impl BluetoothGATTDescriptor {
pub fn new(_descriptor: String) -> BluetoothGATTDescriptor {
BluetoothGATTDescriptor {}
}
pub fn get_id(&self) -> String {
String::new()
}
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
pub fn write_value(&self, _values: Vec<u8>) -> Result<(), Box<dyn Error>> {
Err(Box::from(NOT_SUPPORTED_ERROR))
}
}

View file

@ -2,6 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
pub mod adapter;
pub mod bluetooth;
#[cfg(not(any(
all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth")
)))]
mod empty;
mod macros;
pub mod test;
use std::borrow::ToOwned;
@ -20,16 +29,17 @@ use bluetooth_traits::{
BluetoothRequest, BluetoothResponse, BluetoothResponseResult, BluetoothResult,
BluetoothServiceMsg, GATTType,
};
use device::bluetooth::{
BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic, BluetoothGATTDescriptor,
BluetoothGATTService,
};
use embedder_traits::{EmbedderMsg, EmbedderProxy};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use log::warn;
use servo_config::pref;
use servo_rand::{self, Rng};
use crate::bluetooth::{
BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic, BluetoothGATTDescriptor,
BluetoothGATTService,
};
// A transaction not completed within 30 seconds shall time out. Such a transaction shall be considered to have failed.
// https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439 (Vol. 3, page 480)
const MAXIMUM_TRANSACTION_TIME: u8 = 30;
@ -67,9 +77,9 @@ impl BluetoothThreadFactory for IpcSender<BluetoothRequest> {
fn new(embedder_proxy: EmbedderProxy) -> IpcSender<BluetoothRequest> {
let (sender, receiver) = ipc::channel().unwrap();
let adapter = if pref!(dom.bluetooth.enabled) {
BluetoothAdapter::init()
BluetoothAdapter::new()
} else {
BluetoothAdapter::init_mock()
BluetoothAdapter::new_mock()
}
.ok();
thread::Builder::new()
@ -287,7 +297,7 @@ impl BluetoothManager {
self.cached_characteristics.clear();
self.cached_descriptors.clear();
self.allowed_services.clear();
self.adapter = BluetoothAdapter::init_mock().ok();
self.adapter = BluetoothAdapter::new_mock().ok();
match test::test(self, data_set_name) {
Ok(_) => return Ok(()),
Err(error) => Err(BluetoothError::Type(error.to_string())),
@ -324,7 +334,7 @@ impl BluetoothManager {
.as_ref()
.map_or(false, |a| a.get_address().is_ok());
if !adapter_valid {
self.adapter = BluetoothAdapter::init().ok();
self.adapter = BluetoothAdapter::new().ok();
}
let adapter = self.adapter.as_ref()?;

View file

@ -0,0 +1,98 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
macro_rules! get_inner_and_call(
($enum_value: expr, $enum_type: ident, $function_name: ident) => {
match $enum_value {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
&$enum_type::Bluez(ref bluez) => bluez.$function_name(),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
&$enum_type::Android(ref android) => android.$function_name(),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
&$enum_type::Mac(ref mac) => mac.$function_name(),
#[cfg(not(any(all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth"))))]
&$enum_type::Empty(ref empty) => empty.$function_name(),
#[cfg(feature = "bluetooth-test")]
&$enum_type::Mock(ref fake) => fake.$function_name(),
}
};
(@with_bluez_offset, $enum_value: expr, $enum_type: ident, $function_name: ident) => {
match $enum_value {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
&$enum_type::Bluez(ref bluez) => bluez.$function_name(None),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
&$enum_type::Android(ref android) => android.$function_name(),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
&$enum_type::Mac(ref mac) => mac.$function_name(),
#[cfg(not(any(all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth"))))]
&$enum_type::Empty(ref empty) => empty.$function_name(),
#[cfg(feature = "bluetooth-test")]
&$enum_type::Mock(ref fake) => fake.$function_name(),
}
};
($enum_value: expr, $enum_type: ident, $function_name: ident, $value: expr) => {
match $enum_value {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
&$enum_type::Bluez(ref bluez) => bluez.$function_name($value),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
&$enum_type::Android(ref android) => android.$function_name($value),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
&$enum_type::Mac(ref mac) => mac.$function_name($value),
#[cfg(not(any(all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth"))))]
&$enum_type::Empty(ref empty) => empty.$function_name($value),
#[cfg(feature = "bluetooth-test")]
&$enum_type::Mock(ref fake) => fake.$function_name($value),
}
};
(@with_bluez_offset, $enum_value: expr, $enum_type: ident, $function_name: ident, $value: expr) => {
match $enum_value {
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
&$enum_type::Bluez(ref bluez) => bluez.$function_name($value, None),
#[cfg(all(target_os = "android", feature = "bluetooth"))]
&$enum_type::Android(ref android) => android.$function_name($value),
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
&$enum_type::Mac(ref mac) => mac.$function_name($value),
#[cfg(not(any(all(target_os = "linux", feature = "bluetooth"),
all(target_os = "android", feature = "bluetooth"),
all(target_os = "macos", feature = "bluetooth"))))]
&$enum_type::Empty(ref empty) => empty.$function_name($value),
#[cfg(feature = "bluetooth-test")]
&$enum_type::Mock(ref fake) => fake.$function_name($value),
}
};
);
#[cfg(feature = "bluetooth-test")]
macro_rules! get_inner_and_call_test_func {
($enum_value: expr, $enum_type: ident, $function_name: ident, $value: expr) => {
match $enum_value {
&$enum_type::Mock(ref fake) => fake.$function_name($value),
_ => Err(Box::from(
"Error! Test functions are not supported on real devices!",
)),
}
};
($enum_value: expr, $enum_type: ident, $function_name: ident) => {
match $enum_value {
&$enum_type::Mock(ref fake) => fake.$function_name(),
_ => Err(Box::from(
"Error! Test functions are not supported on real devices!",
)),
}
};
}
pub(crate) use get_inner_and_call;
#[cfg(feature = "bluetooth-test")]
pub(crate) use get_inner_and_call_test_func;

View file

@ -8,12 +8,12 @@ use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::string::String;
use device::bluetooth::{
use uuid::Uuid;
use crate::bluetooth::{
BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic, BluetoothGATTDescriptor,
BluetoothGATTService,
};
use uuid::Uuid;
use crate::BluetoothManager;
thread_local!(pub static CACHED_IDS: RefCell<HashSet<Uuid>> = RefCell::new(HashSet::new()));
@ -152,7 +152,7 @@ fn create_device(
name: String,
address: String,
) -> Result<BluetoothDevice, Box<dyn Error>> {
let device = BluetoothDevice::create_mock_device(adapter.clone(), generate_id().to_string())?;
let device = adapter.create_mock_device(generate_id().to_string())?;
device.set_name(Some(name))?;
device.set_address(address)?;
device.set_connectable(true)?;