blob: 2e71b9e969c93e4e0eb68743abdaf1f0f5cb807d [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::server::Facade;
use anyhow::{format_err, Error};
use async_trait::async_trait;
use bt_rfcomm::ServerChannel;
use fidl_fuchsia_bluetooth::PeerId;
use fidl_fuchsia_bluetooth_a2dp::Role;
use fidl_fuchsia_bluetooth_hfp::{CallDirection, CallState, NetworkInformation, SignalStrength};
use fidl_fuchsia_bluetooth_le::Filter;
use fidl_fuchsia_bluetooth_sys::{LeSecurityMode, Settings};
use serde_json::{from_value, to_value, Value};
use test_call_manager::TestCallManager as HfpFacade;
use test_rfcomm_client::RfcommManager as RfcommFacade;
// Bluetooth-related functionality
use crate::bluetooth::a2dp_facade::A2dpFacade;
use crate::bluetooth::avdtp_facade::AvdtpFacade;
use crate::bluetooth::avrcp_facade::AvrcpFacade;
use crate::bluetooth::ble_advertise_facade::BleAdvertiseFacade;
use crate::bluetooth::bt_sys_facade::BluetoothSysFacade;
use crate::bluetooth::gatt_client_facade::GattClientFacade;
use crate::bluetooth::gatt_server_facade::GattServerFacade;
use crate::bluetooth::profile_server_facade::ProfileServerFacade;
use crate::bluetooth::types::{
AbsoluteVolumeCommand, BleAdvertiseResponse, BleConnectPeripheralResponse, CustomBatteryStatus,
CustomNotificationsFilter, CustomPlayerApplicationSettings,
CustomPlayerApplicationSettingsAttributeIds, FacadeArg, GattcDiscoverCharacteristicResponse,
};
use crate::common_utils::common::{
parse_identifier, parse_identifier_as_u64, parse_max_bytes, parse_offset, parse_psm,
parse_service_identifier, parse_u64_identifier, parse_write_value,
};
use crate::common_utils::common::macros::parse_arg;
#[async_trait(?Send)]
impl Facade for BleAdvertiseFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
// TODO(armansito): Once the facade supports multi-advertising it should generate and
// return a unique ID for each instance. For now we return this dummy ID for the
// singleton advertisement.
let id = to_value(BleAdvertiseResponse::new(Some("singleton-instance".to_string())))?;
match method.as_ref() {
"BleAdvertise" => {
self.start_adv(args).await?;
}
"BleStopAdvertise" => {
self.stop_adv();
}
_ => return Err(format_err!("Invalid BleAdvertise FIDL method: {:?}", method)),
};
Ok(id)
}
fn cleanup(&self) {
Self::cleanup(self)
}
fn print(&self) {
Self::print(self)
}
}
#[async_trait(?Send)]
impl Facade for BluetoothSysFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"BluetoothAcceptPairing" => {
let input = parse_arg!(args, as_str, "input")?;
let output = parse_arg!(args, as_str, "output")?;
let result = self.accept_pairing(&input.to_string(), &output.to_string()).await?;
Ok(to_value(result)?)
}
"BluetoothInitSys" => {
let result = self.init_access_proxy().await?;
Ok(to_value(result)?)
}
"BluetoothGetKnownRemoteDevices" => {
let result = self.get_known_remote_devices().await?;
Ok(to_value(result)?)
}
"BluetoothSetDiscoverable" => {
let discoverable = parse_arg!(args, as_bool, "discoverable")?;
let result = self.set_discoverable(discoverable).await?;
Ok(to_value(result)?)
}
"BluetoothSetName" => {
let name = parse_arg!(args, as_str, "name")?;
let result = self.set_name(name.to_string()).await?;
Ok(to_value(result)?)
}
"BluetoothForgetDevice" => {
let identifier = parse_identifier_as_u64(&args)?;
let result = self.forget(identifier).await?;
Ok(to_value(result)?)
}
"BluetoothConnectDevice" => {
let identifier = parse_identifier_as_u64(&args)?;
let result = self.connect(identifier).await?;
Ok(to_value(result)?)
}
"BluetoothDisconnectDevice" => {
let identifier = parse_identifier_as_u64(&args)?;
let result = self.disconnect(identifier).await?;
Ok(to_value(result)?)
}
"BluetoothRequestDiscovery" => {
let discovery = parse_arg!(args, as_bool, "discovery")?;
let result = self.start_discovery(discovery).await?;
Ok(to_value(result)?)
}
"BluetoothInputPairingPin" => {
let pin = parse_arg!(args, as_str, "pin")?;
let result = self.input_pairing_pin(pin.to_string()).await?;
Ok(to_value(result)?)
}
"BluetoothGetPairingPin" => {
let result = self.get_pairing_pin().await?;
Ok(to_value(result)?)
}
"BluetoothGetActiveAdapterAddress" => {
let result = self.get_active_adapter_address().await?;
Ok(to_value(result)?)
}
"BluetoothPairDevice" => {
let identifier = parse_identifier_as_u64(&args)?;
let pairing_security_level =
match parse_arg!(args, as_u64, "pairing_security_level") {
Ok(v) => Some(v),
Err(_e) => None,
};
let non_bondable = match parse_arg!(args, as_bool, "non_bondable") {
Ok(v) => Some(v),
Err(_e) => None,
};
let transport = parse_arg!(args, as_u64, "transport")?;
let result =
self.pair(identifier, pairing_security_level, non_bondable, transport).await?;
Ok(to_value(result)?)
}
"BluetoothUpdateSystemSettings" => {
let le_privacy = parse_arg!(args, as_bool, "le_privacy").ok();
let le_background_scan = parse_arg!(args, as_bool, "le_background_scan").ok();
let bredr_connectable_mode =
parse_arg!(args, as_bool, "bredr_connectable_mode").ok();
let le_security_mode = if let Ok(s) = parse_arg!(args, as_str, "le_security_mode") {
match s.to_uppercase().as_ref() {
"MODE_1" => Some(LeSecurityMode::Mode1),
"SECURE_CONNECTIONS_ONLY" => Some(LeSecurityMode::SecureConnectionsOnly),
_ => bail!(
"Invalid le_security_mode {} passed to BluetoothUpdateSystemSettings",
s
),
}
} else {
None
};
let result = self
.update_settings(Settings {
le_privacy,
le_background_scan,
bredr_connectable_mode,
le_security_mode,
..Default::default()
})
.await?;
Ok(to_value(result)?)
}
_ => bail!("Invalid Bluetooth control FIDL method: {:?}", method),
}
}
fn cleanup(&self) {
Self::cleanup(self)
}
fn print(&self) {
Self::print(self)
}
}
#[async_trait(?Send)]
impl Facade for GattClientFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"BleStartScan" => {
let scan_filter = FacadeArg::new(args);
start_scan_async(&self, Some(scan_filter.try_into()?)).await
}
"BleStopScan" => stop_scan_async(self).await,
"BleGetDiscoveredDevices" => le_get_discovered_devices_async(self).await,
"BleConnectPeripheral" => {
let id = parse_identifier(args)?;
connect_peripheral_async(self, id).await
}
"BleDisconnectPeripheral" => {
let id = parse_identifier(args)?;
disconnect_peripheral_async(self, id).await
}
"GattcConnectToService" => {
let periph_id = parse_identifier(args.clone())?;
let service_id = parse_service_identifier(args)?;
gattc_connect_to_service_async(self, periph_id, service_id).await
}
"GattcDiscoverCharacteristics" => gattc_discover_characteristics_async(self).await,
"GattcWriteCharacteristicById" => {
let id = parse_u64_identifier(args.clone())?;
let value = parse_write_value(args)?;
gattc_write_char_by_id_async(self, id, value).await
}
"GattcWriteLongCharacteristicById" => {
let id = parse_u64_identifier(args.clone())?;
let offset_as_u64 = parse_offset(args.clone())?;
let offset = offset_as_u64 as u16;
let value = parse_write_value(args.clone())?;
let reliable_mode = parse_arg!(args, as_bool, "reliable_mode")?;
gattc_write_long_char_by_id_async(self, id, offset, value, reliable_mode).await
}
"GattcWriteCharacteristicByIdWithoutResponse" => {
let id = parse_u64_identifier(args.clone())?;
let value = parse_write_value(args)?;
gattc_write_char_by_id_without_response_async(self, id, value).await
}
"GattcEnableNotifyCharacteristic" => {
let id = parse_u64_identifier(args.clone())?;
gattc_toggle_notify_characteristic_async(self, id, true).await
}
"GattcDisableNotifyCharacteristic" => {
let id = parse_u64_identifier(args.clone())?;
gattc_toggle_notify_characteristic_async(self, id, false).await
}
"GattcReadCharacteristicById" => {
let id = parse_u64_identifier(args.clone())?;
gattc_read_char_by_id_async(self, id).await
}
"GattcReadCharacteristicByType" => {
let uuid = parse_arg!(args, as_str, "uuid")?;
let result = self.gattc_read_char_by_type(uuid.to_string()).await?;
Ok(to_value(result)?)
}
"GattcReadLongCharacteristicById" => {
let id = parse_u64_identifier(args.clone())?;
let offset_as_u64 = parse_offset(args.clone())?;
let offset = offset_as_u64 as u16;
let max_bytes_as_u64 = parse_max_bytes(args)?;
let max_bytes = max_bytes_as_u64 as u16;
gattc_read_long_char_by_id_async(self, id, offset, max_bytes).await
}
"GattcReadLongDescriptorById" => {
let id = parse_u64_identifier(args.clone())?;
let offset_as_u64 = parse_offset(args.clone())?;
let offset = offset_as_u64 as u16;
let max_bytes_as_u64 = parse_max_bytes(args)?;
let max_bytes = max_bytes_as_u64 as u16;
gattc_read_long_desc_by_id_async(self, id, offset, max_bytes).await
}
"GattcWriteDescriptorById" => {
let id = parse_u64_identifier(args.clone())?;
let value = parse_write_value(args)?;
gattc_write_desc_by_id_async(self, id, value).await
}
"GattcWriteLongDescriptorById" => {
let id = parse_u64_identifier(args.clone())?;
let offset_as_u64 = parse_offset(args.clone())?;
let offset = offset_as_u64 as u16;
let value = parse_write_value(args)?;
gattc_write_long_desc_by_id_async(self, id, offset, value).await
}
"GattcReadDescriptorById" => {
let id = parse_u64_identifier(args.clone())?;
gattc_read_desc_by_id_async(self, id.clone()).await
}
"GattcListServices" => {
let id = parse_identifier(args)?;
list_services_async(self, id).await
}
_ => return Err(format_err!("Invalid Gatt Client FIDL method: {:?}", method)),
}
}
fn cleanup(&self) {
Self::cleanup(self)
}
fn print(&self) {
Self::print(self)
}
}
#[async_trait(?Send)]
impl Facade for GattServerFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"GattServerPublishServer" => {
let result = self.publish_server(args).await?;
Ok(to_value(result)?)
}
"GattServerCloseServer" => {
let result = self.close_server().await;
Ok(to_value(result)?)
}
_ => return Err(format_err!("Invalid Gatt Server FIDL method: {:?}", method)),
}
}
fn cleanup(&self) {
Self::cleanup(self)
}
fn print(&self) {
Self::print(self)
}
}
#[async_trait(?Send)]
impl Facade for ProfileServerFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"ProfileServerInit" => {
let result = self.init_profile_server_proxy().await?;
Ok(to_value(result)?)
}
"ProfileServerAddSearch" => {
let result = self.add_search(args).await?;
Ok(to_value(result)?)
}
"ProfileServerAddService" => {
let result = self.add_service(args).await?;
Ok(to_value(result)?)
}
"ProfileServerCleanup" => {
let result = self.cleanup().await?;
Ok(to_value(result)?)
}
"ProfileServerConnectL2cap" => {
let id = parse_identifier(args.clone())?;
let psm = parse_psm(args.clone())?;
let mode = parse_arg!(args, as_str, "mode")?;
let result = self.connect(id, psm as u16, &mode.to_string()).await?;
Ok(to_value(result)?)
}
"ProfileServerRemoveService" => {
let service_id = parse_u64_identifier(args)? as usize;
let result = self.remove_service(service_id).await?;
Ok(to_value(result)?)
}
_ => return Err(format_err!("Invalid Profile Server FIDL method: {:?}", method)),
}
}
}
#[async_trait(?Send)]
impl Facade for AvdtpFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"AvdtpInit" => {
let initiator_delay = match parse_arg!(args, as_str, "initiator_delay") {
Ok(v) => Some(v.to_string()),
Err(_e) => None,
};
let result = self.init_avdtp_service_proxy(initiator_delay).await?;
Ok(to_value(result)?)
}
"AvdtpGetConnectedPeers" => {
let result = self.get_connected_peers().await?;
Ok(to_value(result)?)
}
"AvdtpSetConfiguration" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.set_configuration(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpGetConfiguration" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.get_configuration(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpGetCapabilities" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.get_capabilities(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpGetAllCapabilities" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.get_all_capabilities(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpReconfigureStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.reconfigure_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpSuspendStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.suspend_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpSuspendAndReconfigure" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.suspend_and_reconfigure(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpReleaseStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.release_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpEstablishStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.establish_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpStartStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.start_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpAbortStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.abort_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpRemoveService" => {
let result = self.remove_service().await;
Ok(to_value(result)?)
}
_ => bail!("Invalid AVDTP FIDL method: {:?}", method),
}
}
}
#[async_trait(?Send)]
impl Facade for A2dpFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"A2dpSetRole" => {
let a2dp_role = if let Ok(s) = parse_arg!(args, as_str, "a2dp_role") {
match s.to_uppercase().as_ref() {
"SOURCE" => Role::Source,
"SINK" => Role::Sink,
_ => bail!("Invalid A2DP role {} passed to A2dpSetRole", s),
}
} else {
bail!("Could not parse A2DP role passed to A2dpSetRole")
};
self.init_audio_mode_proxy().await?;
let result = self.set_role(a2dp_role).await?;
Ok(to_value(result)?)
}
_ => {
bail!("Invalid A2DP FIDL method: {:?}", method)
}
}
}
}
#[async_trait(?Send)]
impl Facade for AvrcpFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"AvrcpInit" => {
let target_id = parse_arg!(args, as_str, "target_id")?;
let target_id = target_id.parse::<u64>()?;
let result = self.init_avrcp(target_id).await?;
Ok(to_value(result)?)
}
"AvrcpGetMediaAttributes" => {
let result = self.get_media_attributes().await?;
Ok(to_value(result)?)
}
"AvrcpGetPlayStatus" => {
let result = self.get_play_status().await?;
Ok(to_value(result)?)
}
"AvrcpGetPlayerApplicationSettings" => {
let attribute_ids: CustomPlayerApplicationSettingsAttributeIds =
match from_value(args.clone()) {
Ok(attribute_ids) => attribute_ids,
_ => bail!(
"Invalid json argument to AvrcpGetPlayerApplicationSettings! - {}",
args
),
};
let result = self.get_player_application_settings(attribute_ids.clone()).await?;
Ok(to_value(result)?)
}
"AvrcpInformBatteryStatus" => {
let battery_status: CustomBatteryStatus = match from_value(args.clone()) {
Ok(battery_status) => battery_status,
_ => bail!("Invalid json argument to AvrcpInformBatteryStatus! - {}", args),
};
let result = self.inform_battery_status(battery_status.clone()).await?;
Ok(to_value(result)?)
}
"AvrcpNotifyNotificationHandled" => {
let result = self.notify_notification_handled().await?;
Ok(to_value(result)?)
}
"AvrcpSetAddressedPlayer" => {
let player_id: u16 = match from_value(args.clone()) {
Ok(settings) => settings,
_ => bail!("Invalid json argument to AvrcpSetAddressedPlayer! - {}", args),
};
let result = self.set_addressed_player(player_id.clone()).await?;
Ok(to_value(result)?)
}
"AvrcpSetPlayerApplicationSettings" => {
let settings: CustomPlayerApplicationSettings = match from_value(args.clone()) {
Ok(settings) => settings,
_ => bail!(
"Invalid json argument to AvrcpSetPlayerApplicationSettings! - {}",
args
),
};
let result = self.set_player_application_settings(settings.clone()).await?;
Ok(to_value(result)?)
}
"AvrcpSendCommand" => {
let command_str = parse_arg!(args, as_str, "command")?;
let result = self.send_command(command_str.to_string().into()).await?;
Ok(to_value(result)?)
}
"AvrcpSetAbsoluteVolume" => {
let absolute_volume_command: AbsoluteVolumeCommand = match from_value(args.clone())
{
Ok(absolute_volume) => absolute_volume,
_ => bail!("Invalid json argument to AvrcpSetAbsoluteVolume! - {}", args),
};
let result =
self.set_absolute_volume(absolute_volume_command.absolute_volume).await?;
Ok(to_value(result)?)
}
"AvrcpSetNotificationFilter" => {
let custom_notifications: CustomNotificationsFilter = match from_value(args.clone())
{
Ok(custom_notifications) => custom_notifications,
_ => bail!("Invalid json argument to AvrcpSetNotificationFilter! - {}", args),
};
let result = self
.set_notification_filter(
custom_notifications.notifications,
match custom_notifications.position_change_interval {
Some(position_change_interval) => position_change_interval,
_ => 0,
},
)
.await?;
Ok(to_value(result)?)
}
_ => bail!("Invalid AVRCP FIDL method: {:?}", method),
}
}
fn cleanup(&self) {}
fn print(&self) {}
}
async fn start_scan_async(
facade: &GattClientFacade,
filter: Option<Filter>,
) -> Result<Value, Error> {
let start_scan_result = facade.start_scan(filter).await?;
Ok(to_value(start_scan_result)?)
}
async fn stop_scan_async(facade: &GattClientFacade) -> Result<Value, Error> {
facade.stop_scan().await?;
// Get the list of devices discovered by the scan.
let devices = facade.get_scan_responses();
match to_value(devices) {
Ok(dev) => Ok(dev),
Err(e) => Err(e.into()),
}
}
async fn le_get_discovered_devices_async(facade: &GattClientFacade) -> Result<Value, Error> {
// Get the list of devices discovered by the scan.
match to_value(facade.get_scan_responses()) {
Ok(dev) => Ok(dev),
Err(e) => Err(e.into()),
}
}
async fn connect_peripheral_async(facade: &GattClientFacade, id: String) -> Result<Value, Error> {
let connect_periph_result = facade.connect_peripheral(id).await?;
Ok(to_value(connect_periph_result)?)
}
async fn disconnect_peripheral_async(
facade: &GattClientFacade,
id: String,
) -> Result<Value, Error> {
let value = facade.disconnect_peripheral(id).await?;
Ok(to_value(value)?)
}
// Uses the same return type as connect_peripheral_async -- Returns subset of
// fidl::ServiceInfo
async fn list_services_async(facade: &GattClientFacade, id: String) -> Result<Value, Error> {
let list_services_result = facade.list_services(id).await?;
Ok(to_value(BleConnectPeripheralResponse::new(list_services_result))?)
}
async fn gattc_connect_to_service_async(
facade: &GattClientFacade,
periph_id: String,
service_id: u64,
) -> Result<Value, Error> {
let connect_to_service_result = facade.gattc_connect_to_service(periph_id, service_id).await?;
Ok(to_value(connect_to_service_result)?)
}
async fn gattc_discover_characteristics_async(facade: &GattClientFacade) -> Result<Value, Error> {
let discover_characteristics_results = facade.gattc_discover_characteristics().await?;
Ok(to_value(GattcDiscoverCharacteristicResponse::new(discover_characteristics_results))?)
}
async fn gattc_write_char_by_id_async(
facade: &GattClientFacade,
id: u64,
write_value: Vec<u8>,
) -> Result<Value, Error> {
let write_char_status = facade.gattc_write_char_by_id(id, write_value).await?;
Ok(to_value(write_char_status)?)
}
async fn gattc_write_long_char_by_id_async(
facade: &GattClientFacade,
id: u64,
offset: u16,
write_value: Vec<u8>,
reliable_mode: bool,
) -> Result<Value, Error> {
let write_char_status =
facade.gattc_write_long_char_by_id(id, offset, write_value, reliable_mode).await?;
Ok(to_value(write_char_status)?)
}
async fn gattc_write_char_by_id_without_response_async(
facade: &GattClientFacade,
id: u64,
write_value: Vec<u8>,
) -> Result<Value, Error> {
let write_char_status = facade.gattc_write_char_by_id_without_response(id, write_value).await?;
Ok(to_value(write_char_status)?)
}
async fn gattc_read_char_by_id_async(facade: &GattClientFacade, id: u64) -> Result<Value, Error> {
let read_char_status = facade.gattc_read_char_by_id(id).await?;
Ok(to_value(read_char_status)?)
}
async fn gattc_read_long_char_by_id_async(
facade: &GattClientFacade,
id: u64,
offset: u16,
max_bytes: u16,
) -> Result<Value, Error> {
let read_long_char_status = facade.gattc_read_long_char_by_id(id, offset, max_bytes).await?;
Ok(to_value(read_long_char_status)?)
}
async fn gattc_read_long_desc_by_id_async(
facade: &GattClientFacade,
id: u64,
offset: u16,
max_bytes: u16,
) -> Result<Value, Error> {
let read_long_desc_status = facade.gattc_read_long_desc_by_id(id, offset, max_bytes).await?;
Ok(to_value(read_long_desc_status)?)
}
async fn gattc_read_desc_by_id_async(facade: &GattClientFacade, id: u64) -> Result<Value, Error> {
let read_desc_status = facade.gattc_read_desc_by_id(id).await?;
Ok(to_value(read_desc_status)?)
}
async fn gattc_write_desc_by_id_async(
facade: &GattClientFacade,
id: u64,
write_value: Vec<u8>,
) -> Result<Value, Error> {
let write_desc_status = facade.gattc_write_desc_by_id(id, write_value).await?;
Ok(to_value(write_desc_status)?)
}
async fn gattc_write_long_desc_by_id_async(
facade: &GattClientFacade,
id: u64,
offset: u16,
write_value: Vec<u8>,
) -> Result<Value, Error> {
let write_desc_status = facade.gattc_write_long_desc_by_id(id, offset, write_value).await?;
Ok(to_value(write_desc_status)?)
}
async fn gattc_toggle_notify_characteristic_async(
facade: &GattClientFacade,
id: u64,
value: bool,
) -> Result<Value, Error> {
let toggle_notify_result = facade.gattc_toggle_notify_characteristic(id, value).await?;
Ok(to_value(toggle_notify_result)?)
}
#[async_trait(?Send)]
impl Facade for HfpFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"HfpInit" => {
let result = self.init_hfp_service().await?;
Ok(to_value(result)?)
}
"HfpRemoveService" => {
self.cleanup().await;
Ok(to_value(())?)
}
"ListPeers" => {
let result = self.list_peers().await?;
Ok(to_value(result)?)
}
"SetActivePeer" => {
let id = parse_arg!(args, as_u64, "peer_id")?;
let result = self.set_active_peer(id).await?;
Ok(to_value(result)?)
}
"ListCalls" => {
let result = self.list_calls().await?;
Ok(to_value(result)?)
}
"NewCall" => {
let remote = parse_arg!(args, as_str, "remote")?;
let state = parse_arg!(args, as_str, "state")?.to_lowercase();
let state = match &*state {
"ringing" => CallState::IncomingRinging,
"waiting" => CallState::IncomingWaiting,
"dialing" => CallState::OutgoingDialing,
"alerting" => CallState::OutgoingAlerting,
"active" => CallState::OngoingActive,
"held" => CallState::OngoingHeld,
_ => bail!("Invalid state argument: {}", state),
};
let direction = parse_arg!(args, as_str, "direction")?;
let direction = match &*direction {
"incoming" => CallDirection::MobileTerminated,
"outgoing" => CallDirection::MobileOriginated,
_ => bail!("Invalid direction argument: {}", direction),
};
let result = self.new_call(&remote, state, direction).await?;
Ok(to_value(result)?)
}
"IncomingCall" => {
let remote = parse_arg!(args, as_str, "remote")?;
let result = self.incoming_ringing_call(&remote).await?;
Ok(to_value(result)?)
}
"IncomingWaitingCall" => {
let remote = parse_arg!(args, as_str, "remote")?;
let result = self.incoming_waiting_call(&remote).await?;
Ok(to_value(result)?)
}
"OutgoingCall" => {
let remote = parse_arg!(args, as_str, "remote")?;
let result = self.outgoing_call(&remote).await?;
Ok(to_value(result)?)
}
"SetCallActive" => {
let call_id = parse_arg!(args, as_u64, "call_id")?;
let result = self.set_call_active(call_id).await?;
Ok(to_value(result)?)
}
"SetCallHeld" => {
let call_id = parse_arg!(args, as_u64, "call_id")?;
let result = self.set_call_held(call_id).await?;
Ok(to_value(result)?)
}
"SetCallTerminated" => {
let call_id = parse_arg!(args, as_u64, "call_id")?;
let result = self.set_call_terminated(call_id).await?;
Ok(to_value(result)?)
}
"SetCallTransferredToAg" => {
let call_id = parse_arg!(args, as_u64, "call_id")?;
let result = self.set_call_transferred_to_ag(call_id).await?;
Ok(to_value(result)?)
}
"SetSpeakerGain" => {
let value = parse_arg!(args, as_u64, "value")?;
let result = self.set_speaker_gain(value).await?;
Ok(to_value(result)?)
}
"SetMicrophoneGain" => {
let value = parse_arg!(args, as_u64, "value")?;
let result = self.set_microphone_gain(value).await?;
Ok(to_value(result)?)
}
"SetServiceAvailable" => {
let service_available = Some(parse_arg!(args, as_bool, "value")?);
let result = self
.update_network_information(NetworkInformation {
service_available,
..Default::default()
})
.await?;
Ok(to_value(result)?)
}
"SetRoaming" => {
let roaming = Some(parse_arg!(args, as_bool, "value")?);
let result = self
.update_network_information(NetworkInformation {
roaming,
..Default::default()
})
.await?;
Ok(to_value(result)?)
}
"SetSignalStrength" => {
let signal_strength = parse_arg!(args, as_u64, "value")?;
let signal_strength = Some(match signal_strength {
0 => SignalStrength::None,
1 => SignalStrength::VeryLow,
2 => SignalStrength::Low,
3 => SignalStrength::Medium,
4 => SignalStrength::High,
5 => SignalStrength::VeryHigh,
_ => panic!(""),
});
let result = self
.update_network_information(NetworkInformation {
signal_strength,
..Default::default()
})
.await?;
Ok(to_value(result)?)
}
"SetSubscriberNumber" => {
let number = parse_arg!(args, as_str, "value")?;
self.set_subscriber_number(number).await;
Ok(to_value(())?)
}
"SetOperator" => {
let value = parse_arg!(args, as_str, "value")?;
self.set_operator(value).await;
Ok(to_value(())?)
}
"SetNrecSupport" => {
let support = parse_arg!(args, as_bool, "value")?;
self.set_nrec_support(support).await;
Ok(to_value(())?)
}
"SetBatteryLevel" => {
let level = parse_arg!(args, as_u64, "value")?;
self.set_battery_level(level).await?;
Ok(to_value(())?)
}
"SetLastDialed" => {
let number = parse_arg!(args, as_str, "number")?.to_string();
self.set_last_dialed(Some(number)).await;
Ok(to_value(())?)
}
"ClearLastDialed" => {
self.set_last_dialed(None).await;
Ok(to_value(())?)
}
"SetMemoryLocation" => {
let location = parse_arg!(args, as_str, "location")?.to_string();
let number = parse_arg!(args, as_str, "number")?.to_string();
self.set_memory_location(location, Some(number)).await;
Ok(to_value(())?)
}
"ClearMemoryLocation" => {
let location = parse_arg!(args, as_str, "location")?.to_string();
self.set_memory_location(location, None).await;
Ok(to_value(())?)
}
"SetDialResult" => {
let number = parse_arg!(args, as_str, "number")?.to_string();
let status = parse_arg!(args, as_i64, "status")?.try_into()?;
let status = fuchsia_zircon::Status::from_raw(status);
self.set_dial_result(number, status).await;
Ok(to_value(())?)
}
"GetState" => {
let result = self.get_state().await;
Ok(to_value(result)?)
}
"SetConnectionBehavior" => {
let autoconnect = parse_arg!(args, as_bool, "autoconnect")?;
self.set_connection_behavior(autoconnect).await?;
Ok(to_value(())?)
}
_ => bail!("Invalid Hfp FIDL method: {:?}", method),
}
}
}
#[async_trait(?Send)]
impl Facade for RfcommFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"RfcommInit" => {
let result = self.advertise()?;
Ok(to_value(result)?)
}
"RfcommRemoveService" => {
let result = self.clear_services();
Ok(to_value(result)?)
}
"DisconnectSession" => {
let id = PeerId { value: parse_arg!(args, as_u64, "peer_id")? };
let result = self.close_session(id.into())?;
Ok(to_value(result)?)
}
"ConnectRfcommChannel" => {
let id = PeerId { value: parse_arg!(args, as_u64, "peer_id")? };
let channel_number = parse_arg!(args, as_u64, "server_channel_number")?;
let channel_number = ServerChannel::try_from(u8::try_from(channel_number)?)?;
let result = self.outgoing_rfcomm_channel(id.into(), channel_number).await?;
Ok(to_value(result)?)
}
"DisconnectRfcommChannel" => {
let id = PeerId { value: parse_arg!(args, as_u64, "peer_id")? };
let channel_number = parse_arg!(args, as_u64, "server_channel_number")?;
let channel_number = ServerChannel::try_from(u8::try_from(channel_number)?)?;
let result = self.close_rfcomm_channel(id.into(), channel_number)?;
Ok(to_value(result)?)
}
"SendRemoteLineStatus" => {
let id = PeerId { value: parse_arg!(args, as_u64, "peer_id")? };
let channel_number = parse_arg!(args, as_u64, "server_channel_number")?;
let channel_number = ServerChannel::try_from(u8::try_from(channel_number)?)?;
let result = self.send_rls(id.into(), channel_number)?;
Ok(to_value(result)?)
}
"RfcommWrite" => {
let id = PeerId { value: parse_arg!(args, as_u64, "peer_id")? };
let channel_number = parse_arg!(args, as_u64, "server_channel_number")?;
let channel_number = ServerChannel::try_from(u8::try_from(channel_number)?)?;
let data = parse_arg!(args, as_str, "data")?.to_string();
let result = self.send_user_data(id.into(), channel_number, data.into_bytes())?;
Ok(to_value(result)?)
}
_ => bail!("Invalid RFCOMM method: {:?}", method),
}
}
}