blob: 1fc3ed833b6d0af0962c2a9beb8a3a801108ac2f [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/bluetooth/dbus/fake_bluetooth_device_client.h"
#include <fcntl.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include "base/base64.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h"
#include "device/bluetooth/dbus/bluez_dbus_manager.h"
#include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_agent_manager_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_agent_service_provider.h"
#include "device/bluetooth/dbus/fake_bluetooth_gatt_service_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_input_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_profile_manager_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_profile_service_provider.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace bluez {
namespace {
// Default interval between simulated events.
const int kSimulationIntervalMs = 750;
// Minimum and maximum bounds for randomly generated RSSI values.
const int kMinRSSI = -90;
const int kMaxRSSI = -30;
// The default value of connection info properties from GetConnInfo().
const int kUnkownPower = 127;
// This is meant to delay the removal of a pre defined device until the
// developer has time to see it.
const int kVanishingDevicePairTimeMultiplier = 4;
// Meant to delay a pair request for an observable amount of time.
const int kIncomingSimulationPairTimeMultiplier = 45;
// Meant to delay a request that asks for pair requests for an observable
// amount of time.
const int kIncomingSimulationStartPairTimeMultiplier = 30;
// This allows the PIN code dialog to be shown for a long enough time to see
// the PIN code UI in detail.
const int kPinCodeDevicePairTimeMultiplier = 7;
// This allows the pairing dialog to be shown for a long enough time to see
// its UI in detail.
const int kSimulateNormalPairTimeMultiplier = 3;
void SimulatedProfileSocket(int fd) {
// Simulate a server-side socket of a profile; read data from the socket,
// write it back, and then close.
char buf[1024];
ssize_t len;
ssize_t count;
len = read(fd, buf, sizeof buf);
if (len < 0) {
close(fd);
return;
}
count = len;
len = write(fd, buf, count);
if (len < 0) {
close(fd);
return;
}
close(fd);
}
void SimpleErrorCallback(const std::string& error_name,
const std::string& error_message) {
VLOG(1) << "Bluetooth Error: " << error_name << ": " << error_message;
}
BluetoothDeviceClient::ServiceRecordList CreateFakeServiceRecords() {
BluetoothDeviceClient::ServiceRecordList records;
std::unique_ptr<BluetoothServiceRecordBlueZ> record1 =
std::make_unique<BluetoothServiceRecordBlueZ>();
// ID 0 = handle.
record1->AddRecordEntry(
0x0, BluetoothServiceAttributeValueBlueZ(
BluetoothServiceAttributeValueBlueZ::UINT, 4,
std::make_unique<base::Value>(static_cast<int32_t>(0x1337))));
// ID 1 = service class id list.
std::unique_ptr<BluetoothServiceAttributeValueBlueZ::Sequence> class_id_list =
std::make_unique<BluetoothServiceAttributeValueBlueZ::Sequence>();
class_id_list->emplace_back(BluetoothServiceAttributeValueBlueZ::UUID, 4,
std::make_unique<base::Value>("1802"));
record1->AddRecordEntry(
0x1, BluetoothServiceAttributeValueBlueZ(std::move(class_id_list)));
records.emplace_back(*record1);
std::unique_ptr<BluetoothServiceRecordBlueZ> record2 =
std::make_unique<BluetoothServiceRecordBlueZ>();
// ID 0 = handle.
record2->AddRecordEntry(
0x0,
BluetoothServiceAttributeValueBlueZ(
BluetoothServiceAttributeValueBlueZ::UINT, 4,
std::make_unique<base::Value>(static_cast<int32_t>(0xffffffff))));
records.emplace_back(*record2);
return records;
}
} // namespace
const char FakeBluetoothDeviceClient::kTestPinCode[] = "123456";
const int FakeBluetoothDeviceClient::kTestPassKey = 123456;
const char FakeBluetoothDeviceClient::kPairingMethodNone[] = "None";
const char FakeBluetoothDeviceClient::kPairingMethodPinCode[] = "PIN Code";
const char FakeBluetoothDeviceClient::kPairingMethodPassKey[] = "PassKey";
const char FakeBluetoothDeviceClient::kPairingActionConfirmation[] =
"Confirmation";
const char FakeBluetoothDeviceClient::kPairingActionDisplay[] = "Display";
const char FakeBluetoothDeviceClient::kPairingActionFail[] = "Fail";
const char FakeBluetoothDeviceClient::kPairingActionRequest[] = "Request";
const char FakeBluetoothDeviceClient::kPairedDevicePath[] = "/fake/hci0/dev0";
const char FakeBluetoothDeviceClient::kPairedDeviceAddress[] =
"00:11:22:33:44:55";
const char FakeBluetoothDeviceClient::kPairedDeviceName[] =
"Fake Device (name)";
const char FakeBluetoothDeviceClient::kPairedDeviceAlias[] =
"Fake Device (alias)";
const uint32_t FakeBluetoothDeviceClient::kPairedDeviceClass = 0x000104;
const char FakeBluetoothDeviceClient::kLegacyAutopairPath[] = "/fake/hci0/dev1";
const char FakeBluetoothDeviceClient::kLegacyAutopairAddress[] =
"28:CF:DA:00:00:00";
const char FakeBluetoothDeviceClient::kLegacyAutopairName[] =
"Bluetooth 2.0 Mouse";
const uint32_t FakeBluetoothDeviceClient::kLegacyAutopairClass = 0x002580;
const char FakeBluetoothDeviceClient::kDisplayPinCodePath[] = "/fake/hci0/dev2";
const char FakeBluetoothDeviceClient::kDisplayPinCodeAddress[] =
"28:37:37:00:00:00";
const char FakeBluetoothDeviceClient::kDisplayPinCodeName[] =
"Bluetooth 2.0 Keyboard";
const uint32_t FakeBluetoothDeviceClient::kDisplayPinCodeClass = 0x002540;
const char FakeBluetoothDeviceClient::kVanishingDevicePath[] =
"/fake/hci0/dev3";
const char FakeBluetoothDeviceClient::kVanishingDeviceAddress[] =
"01:02:03:04:05:06";
const char FakeBluetoothDeviceClient::kVanishingDeviceName[] =
"Vanishing Device";
const uint32_t FakeBluetoothDeviceClient::kVanishingDeviceClass = 0x000104;
const char FakeBluetoothDeviceClient::kConnectUnpairablePath[] =
"/fake/hci0/dev4";
const char FakeBluetoothDeviceClient::kConnectUnpairableAddress[] =
"7C:ED:8D:00:00:00";
const char FakeBluetoothDeviceClient::kConnectUnpairableName[] =
"Unpairable Device";
const uint32_t FakeBluetoothDeviceClient::kConnectUnpairableClass = 0x002580;
const char FakeBluetoothDeviceClient::kDisplayPasskeyPath[] = "/fake/hci0/dev5";
const char FakeBluetoothDeviceClient::kDisplayPasskeyAddress[] =
"00:0F:F6:00:00:00";
const char FakeBluetoothDeviceClient::kDisplayPasskeyName[] =
"Bluetooth 2.1+ Keyboard";
const uint32_t FakeBluetoothDeviceClient::kDisplayPasskeyClass = 0x002540;
const char FakeBluetoothDeviceClient::kRequestPinCodePath[] = "/fake/hci0/dev6";
const char FakeBluetoothDeviceClient::kRequestPinCodeAddress[] =
"00:24:BE:00:00:00";
const char FakeBluetoothDeviceClient::kRequestPinCodeName[] = "PIN Device";
const uint32_t FakeBluetoothDeviceClient::kRequestPinCodeClass = 0x240408;
const char FakeBluetoothDeviceClient::kConfirmPasskeyPath[] = "/fake/hci0/dev7";
const char FakeBluetoothDeviceClient::kConfirmPasskeyAddress[] =
"20:7D:74:00:00:00";
const char FakeBluetoothDeviceClient::kConfirmPasskeyName[] = "Phone";
const uint32_t FakeBluetoothDeviceClient::kConfirmPasskeyClass = 0x7a020c;
const char FakeBluetoothDeviceClient::kRequestPasskeyPath[] = "/fake/hci0/dev8";
const char FakeBluetoothDeviceClient::kRequestPasskeyAddress[] =
"20:7D:74:00:00:01";
const char FakeBluetoothDeviceClient::kRequestPasskeyName[] = "Passkey Device";
const uint32_t FakeBluetoothDeviceClient::kRequestPasskeyClass = 0x7a020c;
const char FakeBluetoothDeviceClient::kUnconnectableDevicePath[] =
"/fake/hci0/dev9";
const char FakeBluetoothDeviceClient::kUnconnectableDeviceAddress[] =
"20:7D:74:00:00:02";
const char FakeBluetoothDeviceClient::kUnconnectableDeviceName[] =
"Unconnectable Device";
const uint32_t FakeBluetoothDeviceClient::kUnconnectableDeviceClass = 0x7a020c;
const char FakeBluetoothDeviceClient::kUnpairableDevicePath[] =
"/fake/hci0/devA";
const char FakeBluetoothDeviceClient::kUnpairableDeviceAddress[] =
"20:7D:74:00:00:03";
const char FakeBluetoothDeviceClient::kUnpairableDeviceName[] =
"Unpairable Device";
const uint32_t FakeBluetoothDeviceClient::kUnpairableDeviceClass = 0x002540;
const char FakeBluetoothDeviceClient::kJustWorksPath[] = "/fake/hci0/devB";
const char FakeBluetoothDeviceClient::kJustWorksAddress[] = "00:0C:8A:00:00:00";
const char FakeBluetoothDeviceClient::kJustWorksName[] = "Just-Works Device";
const uint32_t FakeBluetoothDeviceClient::kJustWorksClass = 0x240428;
const char FakeBluetoothDeviceClient::kLowEnergyPath[] = "/fake/hci0/devC";
const char FakeBluetoothDeviceClient::kLowEnergyAddress[] = "00:1A:11:00:15:30";
const char FakeBluetoothDeviceClient::kLowEnergyName[] =
"Bluetooth 4.0 Heart Rate Monitor";
const uint32_t FakeBluetoothDeviceClient::kLowEnergyClass =
0x000918; // Major class "Health", Minor class "Heart/Pulse Rate Monitor."
const char FakeBluetoothDeviceClient::kDualPath[] = "/fake/hci0/devF";
const char FakeBluetoothDeviceClient::kDualAddress[] = "00:1A:11:00:15:40";
const char FakeBluetoothDeviceClient::kDualName[] =
"Bluetooth 4.0 Battery Monitor";
const char FakeBluetoothDeviceClient::kPairedUnconnectableDevicePath[] =
"/fake/hci0/devD";
const char FakeBluetoothDeviceClient::kPairedUnconnectableDeviceAddress[] =
"20:7D:74:00:00:04";
const char FakeBluetoothDeviceClient::kPairedUnconnectableDeviceName[] =
"Paired Unconnectable Device (name)";
const char FakeBluetoothDeviceClient::kPairedUnconnectableDeviceAlias[] =
"Paired Unconnectable Device (alias)";
const uint32_t FakeBluetoothDeviceClient::kPairedUnconnectableDeviceClass =
0x000104;
const char FakeBluetoothDeviceClient::kConnectedTrustedNotPairedDevicePath[] =
"/fake/hci0/devE";
const char
FakeBluetoothDeviceClient::kConnectedTrustedNotPairedDeviceAddress[] =
"11:22:33:44:55:66";
const char FakeBluetoothDeviceClient::kConnectedTrustedNotPairedDeviceName[] =
"Connected Pairable Device";
const uint32_t
FakeBluetoothDeviceClient::kConnectedTrustedNotPairedDeviceClass = 0x7a020c;
FakeBluetoothDeviceClient::Properties::Properties(
const PropertyChangedCallback& callback)
: BluetoothDeviceClient::Properties(
NULL,
bluetooth_device::kBluetoothDeviceInterface,
callback) {}
FakeBluetoothDeviceClient::Properties::~Properties() = default;
void FakeBluetoothDeviceClient::Properties::Get(
dbus::PropertyBase* property,
dbus::PropertySet::GetCallback callback) {
VLOG(1) << "Get " << property->name();
callback.Run(false);
}
void FakeBluetoothDeviceClient::Properties::GetAll() {
VLOG(1) << "GetAll";
}
void FakeBluetoothDeviceClient::Properties::Set(
dbus::PropertyBase* property,
dbus::PropertySet::SetCallback callback) {
VLOG(1) << "Set " << property->name();
if (property->name() == trusted.name()) {
callback.Run(true);
property->ReplaceValueWithSetValue();
} else {
callback.Run(false);
}
}
FakeBluetoothDeviceClient::SimulatedPairingOptions::SimulatedPairingOptions() =
default;
FakeBluetoothDeviceClient::SimulatedPairingOptions::~SimulatedPairingOptions() =
default;
FakeBluetoothDeviceClient::IncomingDeviceProperties::
IncomingDeviceProperties() = default;
FakeBluetoothDeviceClient::IncomingDeviceProperties::
~IncomingDeviceProperties() = default;
FakeBluetoothDeviceClient::FakeBluetoothDeviceClient()
: simulation_interval_ms_(kSimulationIntervalMs),
discovery_simulation_step_(0),
incoming_pairing_simulation_step_(0),
pairing_cancelled_(false),
connection_rssi_(kUnkownPower),
transmit_power_(kUnkownPower),
max_transmit_power_(kUnkownPower),
delay_start_discovery_(false) {
std::unique_ptr<Properties> properties(new Properties(
base::Bind(&FakeBluetoothDeviceClient::OnPropertyChanged,
base::Unretained(this), dbus::ObjectPath(kPairedDevicePath))));
properties->address.ReplaceValue(kPairedDeviceAddress);
properties->bluetooth_class.ReplaceValue(kPairedDeviceClass);
properties->name.ReplaceValue(kPairedDeviceName);
properties->name.set_valid(true);
properties->alias.ReplaceValue(kPairedDeviceAlias);
properties->paired.ReplaceValue(true);
properties->trusted.ReplaceValue(true);
properties->adapter.ReplaceValue(
dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
std::vector<std::string> uuids;
uuids.push_back("00001800-0000-1000-8000-00805f9b34fb");
uuids.push_back("00001801-0000-1000-8000-00805f9b34fb");
properties->uuids.ReplaceValue(uuids);
properties->modalias.ReplaceValue("usb:v05ACp030Dd0306");
properties_map_.insert(std::make_pair(dbus::ObjectPath(kPairedDevicePath),
std::move(properties)));
device_list_.push_back(dbus::ObjectPath(kPairedDevicePath));
properties.reset(new Properties(base::Bind(
&FakeBluetoothDeviceClient::OnPropertyChanged, base::Unretained(this),
dbus::ObjectPath(kPairedUnconnectableDevicePath))));
properties->address.ReplaceValue(kPairedUnconnectableDeviceAddress);
properties->bluetooth_class.ReplaceValue(kPairedUnconnectableDeviceClass);
properties->name.ReplaceValue(kPairedUnconnectableDeviceName);
properties->name.set_valid(true);
properties->alias.ReplaceValue(kPairedUnconnectableDeviceAlias);
properties->paired.ReplaceValue(true);
properties->trusted.ReplaceValue(true);
properties->adapter.ReplaceValue(
dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
properties->uuids.ReplaceValue(uuids);
properties->modalias.ReplaceValue("usb:v05ACp030Dd0306");
properties_map_.insert(std::make_pair(
dbus::ObjectPath(kPairedUnconnectableDevicePath), std::move(properties)));
device_list_.push_back(dbus::ObjectPath(kPairedUnconnectableDevicePath));
}
FakeBluetoothDeviceClient::~FakeBluetoothDeviceClient() = default;
void FakeBluetoothDeviceClient::Init(dbus::Bus* bus) {}
void FakeBluetoothDeviceClient::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void FakeBluetoothDeviceClient::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
std::vector<dbus::ObjectPath> FakeBluetoothDeviceClient::GetDevicesForAdapter(
const dbus::ObjectPath& adapter_path) {
if (adapter_path ==
dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath))
return device_list_;
else
return std::vector<dbus::ObjectPath>();
}
FakeBluetoothDeviceClient::Properties* FakeBluetoothDeviceClient::GetProperties(
const dbus::ObjectPath& object_path) {
PropertiesMap::const_iterator iter = properties_map_.find(object_path);
if (iter != properties_map_.end())
return iter->second.get();
return NULL;
}
FakeBluetoothDeviceClient::SimulatedPairingOptions*
FakeBluetoothDeviceClient::GetPairingOptions(
const dbus::ObjectPath& object_path) {
PairingOptionsMap::const_iterator iter =
pairing_options_map_.find(object_path);
if (iter != pairing_options_map_.end())
return iter->second.get();
return iter != pairing_options_map_.end() ? iter->second.get() : nullptr;
}
void FakeBluetoothDeviceClient::Connect(const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "Connect: " << object_path.value();
Properties* properties = GetProperties(object_path);
if (properties->connected.value() == true) {
// Already connected.
callback.Run();
return;
}
if (properties->paired.value() != true &&
object_path != dbus::ObjectPath(kConnectUnpairablePath) &&
object_path != dbus::ObjectPath(kLowEnergyPath)) {
// Must be paired.
error_callback.Run(bluetooth_device::kErrorFailed, "Not paired");
return;
} else if (properties->paired.value() == true &&
(object_path == dbus::ObjectPath(kUnconnectableDevicePath) ||
object_path ==
dbus::ObjectPath(kPairedUnconnectableDevicePath))) {
// Must not be paired
error_callback.Run(bluetooth_device::kErrorFailed,
"Connection fails while paired");
return;
}
// The device can be connected.
properties->connected.ReplaceValue(true);
callback.Run();
// Expose GATT services if connected to LE device.
if (object_path == dbus::ObjectPath(kLowEnergyPath)) {
FakeBluetoothGattServiceClient* gatt_service_client =
static_cast<FakeBluetoothGattServiceClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothGattServiceClient());
gatt_service_client->ExposeHeartRateService(object_path);
properties->services_resolved.ReplaceValue(true);
}
AddInputDeviceIfNeeded(object_path, properties);
}
void FakeBluetoothDeviceClient::Disconnect(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "Disconnect: " << object_path.value();
Properties* properties = GetProperties(object_path);
if (!properties->connected.value()) {
error_callback.Run(bluetooth_device::kErrorNotConnected, "Not Connected");
return;
}
// Hide the Heart Rate Service if disconnected from LE device.
if (object_path == dbus::ObjectPath(kLowEnergyPath)) {
FakeBluetoothGattServiceClient* gatt_service_client =
static_cast<FakeBluetoothGattServiceClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothGattServiceClient());
gatt_service_client->HideHeartRateService();
}
callback.Run();
properties->connected.ReplaceValue(false);
}
void FakeBluetoothDeviceClient::ConnectProfile(
const dbus::ObjectPath& object_path,
const std::string& uuid,
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "ConnectProfile: " << object_path.value() << " " << uuid;
FakeBluetoothProfileManagerClient* fake_bluetooth_profile_manager_client =
static_cast<FakeBluetoothProfileManagerClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothProfileManagerClient());
FakeBluetoothProfileServiceProvider* profile_service_provider =
fake_bluetooth_profile_manager_client->GetProfileServiceProvider(uuid);
if (profile_service_provider == NULL) {
error_callback.Run(kNoResponseError, "Missing profile");
return;
}
if (object_path == dbus::ObjectPath(kPairedUnconnectableDevicePath)) {
error_callback.Run(bluetooth_device::kErrorFailed, "unconnectable");
return;
}
// Make a socket pair of a compatible type with the type used by Bluetooth;
// spin up a thread to simulate the server side and wrap the client side in
// a D-Bus file descriptor object.
int socket_type = SOCK_STREAM;
if (uuid == FakeBluetoothProfileManagerClient::kL2capUuid)
socket_type = SOCK_SEQPACKET;
int fds[2];
if (socketpair(AF_UNIX, socket_type, 0, fds) < 0) {
error_callback.Run(kNoResponseError, "socketpair call failed");
return;
}
int args;
args = fcntl(fds[1], F_GETFL, NULL);
if (args < 0) {
error_callback.Run(kNoResponseError, "failed to get socket flags");
return;
}
args |= O_NONBLOCK;
if (fcntl(fds[1], F_SETFL, args) < 0) {
error_callback.Run(kNoResponseError, "failed to set socket non-blocking");
return;
}
base::PostTaskWithTraits(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::Bind(&SimulatedProfileSocket, fds[0]));
base::ScopedFD fd(fds[1]);
// Post the new connection to the service provider.
BluetoothProfileServiceProvider::Delegate::Options options;
profile_service_provider->NewConnection(
object_path, std::move(fd), options,
base::Bind(&FakeBluetoothDeviceClient::ConnectionCallback,
base::Unretained(this), object_path, callback,
error_callback));
}
void FakeBluetoothDeviceClient::DisconnectProfile(
const dbus::ObjectPath& object_path,
const std::string& uuid,
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "DisconnectProfile: " << object_path.value() << " " << uuid;
FakeBluetoothProfileManagerClient* fake_bluetooth_profile_manager_client =
static_cast<FakeBluetoothProfileManagerClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothProfileManagerClient());
FakeBluetoothProfileServiceProvider* profile_service_provider =
fake_bluetooth_profile_manager_client->GetProfileServiceProvider(uuid);
if (profile_service_provider == NULL) {
error_callback.Run(kNoResponseError, "Missing profile");
return;
}
profile_service_provider->RequestDisconnection(
object_path, base::Bind(&FakeBluetoothDeviceClient::DisconnectionCallback,
base::Unretained(this), object_path, callback,
error_callback));
}
void FakeBluetoothDeviceClient::Pair(const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "Pair: " << object_path.value();
Properties* properties = GetProperties(object_path);
if (properties->paired.value() == true) {
// Already paired.
callback.Run();
return;
}
SimulatePairing(object_path, false, callback, error_callback);
}
void FakeBluetoothDeviceClient::CancelPairing(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "CancelPairing: " << object_path.value();
pairing_cancelled_ = true;
callback.Run();
}
void FakeBluetoothDeviceClient::GetConnInfo(
const dbus::ObjectPath& object_path,
const ConnInfoCallback& callback,
const ErrorCallback& error_callback) {
Properties* properties = GetProperties(object_path);
if (!properties->connected.value()) {
error_callback.Run(bluetooth_device::kErrorNotConnected, "Not Connected");
return;
}
callback.Run(connection_rssi_, transmit_power_, max_transmit_power_);
}
void FakeBluetoothDeviceClient::SetLEConnectionParameters(
const dbus::ObjectPath& object_path,
const ConnectionParameters& conn_params,
const base::Closure& callback,
const ErrorCallback& error_callback) {
Properties* properties = GetProperties(object_path);
if (!properties->type.is_valid() || properties->type.value() == kTypeBredr) {
error_callback.Run(bluetooth_device::kErrorFailed,
"BR/EDR devices not supported");
return;
}
callback.Run();
}
void FakeBluetoothDeviceClient::GetServiceRecords(
const dbus::ObjectPath& object_path,
const ServiceRecordsCallback& callback,
const ErrorCallback& error_callback) {
Properties* properties = GetProperties(object_path);
if (!properties->connected.value()) {
error_callback.Run(bluetooth_device::kErrorNotConnected, "Not Connected");
return;
}
callback.Run(CreateFakeServiceRecords());
}
void FakeBluetoothDeviceClient::BeginDiscoverySimulation(
const dbus::ObjectPath& adapter_path) {
VLOG(1) << "starting discovery simulation";
discovery_simulation_step_ = 1;
int delay = delay_start_discovery_ ? simulation_interval_ms_ : 0;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::DiscoverySimulationTimer,
base::Unretained(this)),
base::TimeDelta::FromMilliseconds(delay));
}
void FakeBluetoothDeviceClient::EndDiscoverySimulation(
const dbus::ObjectPath& adapter_path) {
VLOG(1) << "stopping discovery simulation";
discovery_simulation_step_ = 0;
InvalidateDeviceRSSI(dbus::ObjectPath(kLowEnergyPath));
}
void FakeBluetoothDeviceClient::BeginIncomingPairingSimulation(
const dbus::ObjectPath& adapter_path) {
VLOG(1) << "starting incoming pairing simulation";
incoming_pairing_simulation_step_ = 1;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::IncomingPairingSimulationTimer,
base::Unretained(this)),
base::TimeDelta::FromMilliseconds(
kIncomingSimulationStartPairTimeMultiplier *
simulation_interval_ms_));
}
void FakeBluetoothDeviceClient::EndIncomingPairingSimulation(
const dbus::ObjectPath& adapter_path) {
VLOG(1) << "stopping incoming pairing simulation";
incoming_pairing_simulation_step_ = 0;
}
void FakeBluetoothDeviceClient::SetSimulationIntervalMs(int interval_ms) {
simulation_interval_ms_ = interval_ms;
}
void FakeBluetoothDeviceClient::CreateDevice(
const dbus::ObjectPath& adapter_path,
const dbus::ObjectPath& device_path) {
if (base::ContainsValue(device_list_, device_path))
return;
std::unique_ptr<Properties> properties(
new Properties(base::Bind(&FakeBluetoothDeviceClient::OnPropertyChanged,
base::Unretained(this), device_path)));
properties->adapter.ReplaceValue(adapter_path);
properties->type.ReplaceValue(BluetoothDeviceClient::kTypeBredr);
properties->type.set_valid(true);
if (device_path == dbus::ObjectPath(kLegacyAutopairPath)) {
properties->address.ReplaceValue(kLegacyAutopairAddress);
properties->bluetooth_class.ReplaceValue(kLegacyAutopairClass);
properties->name.ReplaceValue(kLegacyAutopairName);
properties->name.set_valid(true);
std::vector<std::string> uuids;
uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
properties->uuids.ReplaceValue(uuids);
} else if (device_path == dbus::ObjectPath(kDisplayPinCodePath)) {
properties->address.ReplaceValue(kDisplayPinCodeAddress);
properties->bluetooth_class.ReplaceValue(kDisplayPinCodeClass);
properties->name.ReplaceValue(kDisplayPinCodeName);
properties->name.set_valid(true);
std::vector<std::string> uuids;
uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
properties->uuids.ReplaceValue(uuids);
} else if (device_path == dbus::ObjectPath(kVanishingDevicePath)) {
properties->address.ReplaceValue(kVanishingDeviceAddress);
properties->bluetooth_class.ReplaceValue(kVanishingDeviceClass);
properties->name.ReplaceValue(kVanishingDeviceName);
properties->name.set_valid(true);
} else if (device_path == dbus::ObjectPath(kConnectUnpairablePath)) {
properties->address.ReplaceValue(kConnectUnpairableAddress);
properties->bluetooth_class.ReplaceValue(kConnectUnpairableClass);
properties->name.ReplaceValue(kConnectUnpairableName);
properties->name.set_valid(true);
std::vector<std::string> uuids;
uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
properties->uuids.ReplaceValue(uuids);
} else if (device_path == dbus::ObjectPath(kDisplayPasskeyPath)) {
properties->address.ReplaceValue(kDisplayPasskeyAddress);
properties->bluetooth_class.ReplaceValue(kDisplayPasskeyClass);
properties->name.ReplaceValue(kDisplayPasskeyName);
properties->name.set_valid(true);
std::vector<std::string> uuids;
uuids.push_back("00001124-0000-1000-8000-00805f9b34fb");
properties->uuids.ReplaceValue(uuids);
} else if (device_path == dbus::ObjectPath(kRequestPinCodePath)) {
properties->address.ReplaceValue(kRequestPinCodeAddress);
properties->bluetooth_class.ReplaceValue(kRequestPinCodeClass);
properties->name.ReplaceValue(kRequestPinCodeName);
properties->name.set_valid(true);
} else if (device_path == dbus::ObjectPath(kConfirmPasskeyPath)) {
properties->address.ReplaceValue(kConfirmPasskeyAddress);
properties->bluetooth_class.ReplaceValue(kConfirmPasskeyClass);
properties->name.ReplaceValue(kConfirmPasskeyName);
properties->name.set_valid(true);
} else if (device_path == dbus::ObjectPath(kRequestPasskeyPath)) {
properties->address.ReplaceValue(kRequestPasskeyAddress);
properties->bluetooth_class.ReplaceValue(kRequestPasskeyClass);
properties->name.ReplaceValue(kRequestPasskeyName);
properties->name.set_valid(true);
} else if (device_path == dbus::ObjectPath(kUnconnectableDevicePath)) {
properties->address.ReplaceValue(kUnconnectableDeviceAddress);
properties->bluetooth_class.ReplaceValue(kUnconnectableDeviceClass);
properties->name.ReplaceValue(kUnconnectableDeviceName);
properties->name.set_valid(true);
} else if (device_path == dbus::ObjectPath(kUnpairableDevicePath)) {
properties->address.ReplaceValue(kUnpairableDeviceAddress);
properties->bluetooth_class.ReplaceValue(kUnpairableDeviceClass);
properties->name.ReplaceValue(kUnpairableDeviceName);
properties->name.set_valid(true);
} else if (device_path == dbus::ObjectPath(kJustWorksPath)) {
properties->address.ReplaceValue(kJustWorksAddress);
properties->bluetooth_class.ReplaceValue(kJustWorksClass);
properties->name.ReplaceValue(kJustWorksName);
properties->name.set_valid(true);
} else if (device_path == dbus::ObjectPath(kLowEnergyPath)) {
properties->address.ReplaceValue(kLowEnergyAddress);
properties->bluetooth_class.ReplaceValue(kLowEnergyClass);
properties->name.ReplaceValue(kLowEnergyName);
properties->name.set_valid(true);
properties->services_resolved.ReplaceValue(false);
properties->type.ReplaceValue(BluetoothDeviceClient::kTypeLe);
properties->uuids.ReplaceValue(std::vector<std::string>(
{FakeBluetoothGattServiceClient::kHeartRateServiceUUID}));
} else if (device_path == dbus::ObjectPath(kDualPath)) {
properties->address.ReplaceValue(kDualAddress);
properties->name.ReplaceValue(kDualName);
properties->name.set_valid(true);
properties->services_resolved.ReplaceValue(false);
properties->type.ReplaceValue(BluetoothDeviceClient::kTypeDual);
properties->uuids.ReplaceValue(std::vector<std::string>(
{FakeBluetoothGattServiceClient::kGenericAccessServiceUUID,
FakeBluetoothGattServiceClient::kHeartRateServiceUUID}));
} else if (device_path ==
dbus::ObjectPath(kConnectedTrustedNotPairedDevicePath)) {
properties->address.ReplaceValue(kConnectedTrustedNotPairedDeviceAddress);
properties->bluetooth_class.ReplaceValue(
kConnectedTrustedNotPairedDeviceClass);
properties->trusted.ReplaceValue(true);
properties->connected.ReplaceValue(true);
properties->paired.ReplaceValue(false);
properties->name.ReplaceValue(kConnectedTrustedNotPairedDeviceName);
properties->name.set_valid(true);
} else {
NOTREACHED();
}
properties_map_.insert(std::make_pair(device_path, std::move(properties)));
device_list_.push_back(device_path);
for (auto& observer : observers_)
observer.DeviceAdded(device_path);
}
void FakeBluetoothDeviceClient::CreateDeviceWithProperties(
const dbus::ObjectPath& adapter_path,
const IncomingDeviceProperties& props) {
dbus::ObjectPath device_path(props.device_path);
if (base::ContainsValue(device_list_, device_path))
return;
std::unique_ptr<Properties> properties(
new Properties(base::Bind(&FakeBluetoothDeviceClient::OnPropertyChanged,
base::Unretained(this), device_path)));
properties->adapter.ReplaceValue(adapter_path);
properties->name.ReplaceValue(props.device_name);
properties->name.set_valid(true);
properties->alias.ReplaceValue(props.device_alias);
properties->address.ReplaceValue(props.device_address);
properties->bluetooth_class.ReplaceValue(props.device_class);
properties->trusted.ReplaceValue(props.is_trusted);
if (props.is_trusted)
properties->paired.ReplaceValue(true);
std::unique_ptr<SimulatedPairingOptions> options(new SimulatedPairingOptions);
options->pairing_method = props.pairing_method;
options->pairing_auth_token = props.pairing_auth_token;
options->pairing_action = props.pairing_action;
options->incoming = props.incoming;
properties_map_.insert(std::make_pair(device_path, std::move(properties)));
device_list_.push_back(device_path);
pairing_options_map_.insert(std::make_pair(device_path, std::move(options)));
for (auto& observer : observers_)
observer.DeviceAdded(device_path);
}
std::unique_ptr<base::ListValue>
FakeBluetoothDeviceClient::GetBluetoothDevicesAsDictionaries() const {
std::unique_ptr<base::ListValue> predefined_devices(new base::ListValue);
std::unique_ptr<base::DictionaryValue> pairedDevice(
new base::DictionaryValue);
pairedDevice->SetString("path", kPairedDevicePath);
pairedDevice->SetString("address", kPairedDeviceAddress);
pairedDevice->SetString("name", kPairedDeviceName);
pairedDevice->SetString("alias", kPairedDeviceName);
pairedDevice->SetString("pairingMethod", "");
pairedDevice->SetString("pairingAuthToken", "");
pairedDevice->SetString("pairingAction", "");
pairedDevice->SetInteger("classValue", kPairedDeviceClass);
pairedDevice->SetBoolean("discoverable", true);
pairedDevice->SetBoolean("isTrusted", true);
pairedDevice->SetBoolean("paired", true);
pairedDevice->SetBoolean("incoming", false);
predefined_devices->Append(std::move(pairedDevice));
std::unique_ptr<base::DictionaryValue> legacyDevice(
new base::DictionaryValue);
legacyDevice->SetString("path", kLegacyAutopairPath);
legacyDevice->SetString("address", kLegacyAutopairAddress);
legacyDevice->SetString("name", kLegacyAutopairName);
legacyDevice->SetString("alias", kLegacyAutopairName);
legacyDevice->SetString("pairingMethod", "");
legacyDevice->SetString("pairingAuthToken", "");
legacyDevice->SetString("pairingAction", "");
legacyDevice->SetInteger("classValue", kLegacyAutopairClass);
legacyDevice->SetBoolean("isTrusted", true);
legacyDevice->SetBoolean("discoverable", false);
legacyDevice->SetBoolean("paired", false);
legacyDevice->SetBoolean("incoming", false);
predefined_devices->Append(std::move(legacyDevice));
std::unique_ptr<base::DictionaryValue> pin(new base::DictionaryValue);
pin->SetString("path", kDisplayPinCodePath);
pin->SetString("address", kDisplayPinCodeAddress);
pin->SetString("name", kDisplayPinCodeName);
pin->SetString("alias", kDisplayPinCodeName);
pin->SetString("pairingMethod", kPairingMethodPinCode);
pin->SetString("pairingAuthToken", kTestPinCode);
pin->SetString("pairingAction", kPairingActionDisplay);
pin->SetInteger("classValue", kDisplayPinCodeClass);
pin->SetBoolean("isTrusted", false);
pin->SetBoolean("discoverable", false);
pin->SetBoolean("paired", false);
pin->SetBoolean("incoming", false);
predefined_devices->Append(std::move(pin));
std::unique_ptr<base::DictionaryValue> vanishing(new base::DictionaryValue);
vanishing->SetString("path", kVanishingDevicePath);
vanishing->SetString("address", kVanishingDeviceAddress);
vanishing->SetString("name", kVanishingDeviceName);
vanishing->SetString("alias", kVanishingDeviceName);
vanishing->SetString("pairingMethod", "");
vanishing->SetString("pairingAuthToken", "");
vanishing->SetString("pairingAction", "");
vanishing->SetInteger("classValue", kVanishingDeviceClass);
vanishing->SetBoolean("isTrusted", false);
vanishing->SetBoolean("discoverable", false);
vanishing->SetBoolean("paired", false);
vanishing->SetBoolean("incoming", false);
predefined_devices->Append(std::move(vanishing));
std::unique_ptr<base::DictionaryValue> connect_unpairable(
new base::DictionaryValue);
connect_unpairable->SetString("path", kConnectUnpairablePath);
connect_unpairable->SetString("address", kConnectUnpairableAddress);
connect_unpairable->SetString("name", kConnectUnpairableName);
connect_unpairable->SetString("pairingMethod", "");
connect_unpairable->SetString("pairingAuthToken", "");
connect_unpairable->SetString("pairingAction", "");
connect_unpairable->SetString("alias", kConnectUnpairableName);
connect_unpairable->SetInteger("classValue", kConnectUnpairableClass);
connect_unpairable->SetBoolean("isTrusted", false);
connect_unpairable->SetBoolean("discoverable", false);
connect_unpairable->SetBoolean("paired", false);
connect_unpairable->SetBoolean("incoming", false);
predefined_devices->Append(std::move(connect_unpairable));
std::unique_ptr<base::DictionaryValue> passkey(new base::DictionaryValue);
passkey->SetString("path", kDisplayPasskeyPath);
passkey->SetString("address", kDisplayPasskeyAddress);
passkey->SetString("name", kDisplayPasskeyName);
passkey->SetString("alias", kDisplayPasskeyName);
passkey->SetString("pairingMethod", kPairingMethodPassKey);
passkey->SetInteger("pairingAuthToken", kTestPassKey);
passkey->SetString("pairingAction", kPairingActionDisplay);
passkey->SetInteger("classValue", kDisplayPasskeyClass);
passkey->SetBoolean("isTrusted", false);
passkey->SetBoolean("discoverable", false);
passkey->SetBoolean("paired", false);
passkey->SetBoolean("incoming", false);
predefined_devices->Append(std::move(passkey));
std::unique_ptr<base::DictionaryValue> request_pin(new base::DictionaryValue);
request_pin->SetString("path", kRequestPinCodePath);
request_pin->SetString("address", kRequestPinCodeAddress);
request_pin->SetString("name", kRequestPinCodeName);
request_pin->SetString("alias", kRequestPinCodeName);
request_pin->SetString("pairingMethod", "");
request_pin->SetString("pairingAuthToken", "");
request_pin->SetString("pairingAction", kPairingActionRequest);
request_pin->SetInteger("classValue", kRequestPinCodeClass);
request_pin->SetBoolean("isTrusted", false);
request_pin->SetBoolean("discoverable", false);
request_pin->SetBoolean("paired", false);
request_pin->SetBoolean("incoming", false);
predefined_devices->Append(std::move(request_pin));
std::unique_ptr<base::DictionaryValue> confirm(new base::DictionaryValue);
confirm->SetString("path", kConfirmPasskeyPath);
confirm->SetString("address", kConfirmPasskeyAddress);
confirm->SetString("name", kConfirmPasskeyName);
confirm->SetString("alias", kConfirmPasskeyName);
confirm->SetString("pairingMethod", "");
confirm->SetInteger("pairingAuthToken", kTestPassKey);
confirm->SetString("pairingAction", kPairingActionConfirmation);
confirm->SetInteger("classValue", kConfirmPasskeyClass);
confirm->SetBoolean("isTrusted", false);
confirm->SetBoolean("discoverable", false);
confirm->SetBoolean("paired", false);
confirm->SetBoolean("incoming", false);
predefined_devices->Append(std::move(confirm));
std::unique_ptr<base::DictionaryValue> request_passkey(
new base::DictionaryValue);
request_passkey->SetString("path", kRequestPasskeyPath);
request_passkey->SetString("address", kRequestPasskeyAddress);
request_passkey->SetString("name", kRequestPasskeyName);
request_passkey->SetString("alias", kRequestPasskeyName);
request_passkey->SetString("pairingMethod", kPairingMethodPassKey);
request_passkey->SetString("pairingAction", kPairingActionRequest);
request_passkey->SetInteger("pairingAuthToken", kTestPassKey);
request_passkey->SetInteger("classValue", kRequestPasskeyClass);
request_passkey->SetBoolean("isTrusted", false);
request_passkey->SetBoolean("discoverable", false);
request_passkey->SetBoolean("paired", false);
request_passkey->SetBoolean("incoming", false);
predefined_devices->Append(std::move(request_passkey));
std::unique_ptr<base::DictionaryValue> unconnectable(
new base::DictionaryValue);
unconnectable->SetString("path", kUnconnectableDevicePath);
unconnectable->SetString("address", kUnconnectableDeviceAddress);
unconnectable->SetString("name", kUnconnectableDeviceName);
unconnectable->SetString("alias", kUnconnectableDeviceName);
unconnectable->SetString("pairingMethod", "");
unconnectable->SetString("pairingAuthToken", "");
unconnectable->SetString("pairingAction", "");
unconnectable->SetInteger("classValue", kUnconnectableDeviceClass);
unconnectable->SetBoolean("isTrusted", true);
unconnectable->SetBoolean("discoverable", false);
unconnectable->SetBoolean("paired", false);
unconnectable->SetBoolean("incoming", false);
predefined_devices->Append(std::move(unconnectable));
std::unique_ptr<base::DictionaryValue> unpairable(new base::DictionaryValue);
unpairable->SetString("path", kUnpairableDevicePath);
unpairable->SetString("address", kUnpairableDeviceAddress);
unpairable->SetString("name", kUnpairableDeviceName);
unpairable->SetString("alias", kUnpairableDeviceName);
unpairable->SetString("pairingMethod", "");
unpairable->SetString("pairingAuthToken", "");
unpairable->SetString("pairingAction", kPairingActionFail);
unpairable->SetInteger("classValue", kUnpairableDeviceClass);
unpairable->SetBoolean("isTrusted", false);
unpairable->SetBoolean("discoverable", false);
unpairable->SetBoolean("paired", false);
unpairable->SetBoolean("incoming", false);
predefined_devices->Append(std::move(unpairable));
std::unique_ptr<base::DictionaryValue> just_works(new base::DictionaryValue);
just_works->SetString("path", kJustWorksPath);
just_works->SetString("address", kJustWorksAddress);
just_works->SetString("name", kJustWorksName);
just_works->SetString("alias", kJustWorksName);
just_works->SetString("pairingMethod", "");
just_works->SetString("pairingAuthToken", "");
just_works->SetString("pairingAction", "");
just_works->SetInteger("classValue", kJustWorksClass);
just_works->SetBoolean("isTrusted", false);
just_works->SetBoolean("discoverable", false);
just_works->SetBoolean("paired", false);
just_works->SetBoolean("incoming", false);
predefined_devices->Append(std::move(just_works));
std::unique_ptr<base::DictionaryValue> low_energy(new base::DictionaryValue);
low_energy->SetString("path", kLowEnergyPath);
low_energy->SetString("address", kLowEnergyAddress);
low_energy->SetString("name", kLowEnergyName);
low_energy->SetString("alias", kLowEnergyName);
low_energy->SetString("pairingMethod", "");
low_energy->SetString("pairingAuthToken", "");
low_energy->SetString("pairingAction", "");
low_energy->SetInteger("classValue", kLowEnergyClass);
low_energy->SetBoolean("isTrusted", false);
low_energy->SetBoolean("discoverable", false);
low_energy->SetBoolean("paireed", false);
low_energy->SetBoolean("incoming", false);
predefined_devices->Append(std::move(low_energy));
std::unique_ptr<base::DictionaryValue> paired_unconnectable(
new base::DictionaryValue);
paired_unconnectable->SetString("path", kPairedUnconnectableDevicePath);
paired_unconnectable->SetString("address", kPairedUnconnectableDeviceAddress);
paired_unconnectable->SetString("name", kPairedUnconnectableDeviceName);
paired_unconnectable->SetString("pairingMethod", "");
paired_unconnectable->SetString("pairingAuthToken", "");
paired_unconnectable->SetString("pairingAction", "");
paired_unconnectable->SetString("alias", kPairedUnconnectableDeviceName);
paired_unconnectable->SetInteger("classValue",
kPairedUnconnectableDeviceClass);
paired_unconnectable->SetBoolean("isTrusted", false);
paired_unconnectable->SetBoolean("discoverable", true);
paired_unconnectable->SetBoolean("paired", true);
paired_unconnectable->SetBoolean("incoming", false);
predefined_devices->Append(std::move(paired_unconnectable));
std::unique_ptr<base::DictionaryValue> connected_trusted_not_paired(
new base::DictionaryValue);
connected_trusted_not_paired->SetString("path",
kConnectedTrustedNotPairedDevicePath);
connected_trusted_not_paired->SetString(
"address", kConnectedTrustedNotPairedDeviceAddress);
connected_trusted_not_paired->SetString("name",
kConnectedTrustedNotPairedDeviceName);
connected_trusted_not_paired->SetString("pairingMethod", "");
connected_trusted_not_paired->SetString("pairingAuthToken", "");
connected_trusted_not_paired->SetString("pairingAction", "");
connected_trusted_not_paired->SetString("alias",
kConnectedTrustedNotPairedDeviceName);
connected_trusted_not_paired->SetInteger(
"classValue", kConnectedTrustedNotPairedDeviceClass);
connected_trusted_not_paired->SetBoolean("isTrusted", true);
connected_trusted_not_paired->SetBoolean("discoverable", true);
connected_trusted_not_paired->SetBoolean("paired", false);
connected_trusted_not_paired->SetBoolean("incoming", false);
predefined_devices->Append(std::move(connected_trusted_not_paired));
return predefined_devices;
}
void FakeBluetoothDeviceClient::RemoveDevice(
const dbus::ObjectPath& adapter_path,
const dbus::ObjectPath& device_path) {
std::vector<dbus::ObjectPath>::iterator listiter =
std::find(device_list_.begin(), device_list_.end(), device_path);
if (listiter == device_list_.end())
return;
PropertiesMap::const_iterator iter = properties_map_.find(device_path);
Properties* properties = iter->second.get();
VLOG(1) << "removing device: " << properties->name.value();
device_list_.erase(listiter);
// Remove the Input interface if it exists. This should be called before the
// BluetoothDeviceClient::Observer::DeviceRemoved because it deletes the
// BluetoothDeviceBlueZ object, including the device_path referenced here.
FakeBluetoothInputClient* fake_bluetooth_input_client =
static_cast<FakeBluetoothInputClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothInputClient());
fake_bluetooth_input_client->RemoveInputDevice(device_path);
if (device_path == dbus::ObjectPath(kLowEnergyPath)) {
FakeBluetoothGattServiceClient* gatt_service_client =
static_cast<FakeBluetoothGattServiceClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothGattServiceClient());
gatt_service_client->HideHeartRateService();
}
for (auto& observer : observers_)
observer.DeviceRemoved(device_path);
properties_map_.erase(iter);
PairingOptionsMap::const_iterator options_iter =
pairing_options_map_.find(device_path);
if (options_iter != pairing_options_map_.end()) {
pairing_options_map_.erase(options_iter);
}
}
void FakeBluetoothDeviceClient::OnPropertyChanged(
const dbus::ObjectPath& object_path,
const std::string& property_name) {
VLOG(2) << "Fake Bluetooth device property changed: " << object_path.value()
<< ": " << property_name;
for (auto& observer : observers_)
observer.DevicePropertyChanged(object_path, property_name);
}
void FakeBluetoothDeviceClient::DiscoverySimulationTimer() {
if (!discovery_simulation_step_)
return;
// Timer fires every .75s, the numbers below are arbitrary to give a feel
// for a discovery process.
VLOG(1) << "discovery simulation, step " << discovery_simulation_step_;
uint32_t initial_step = delay_start_discovery_ ? 2 : 1;
if (discovery_simulation_step_ == initial_step) {
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kLegacyAutopairPath));
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kLowEnergyPath));
if (!delay_start_discovery_) {
// Include a device that requires a pairing overlay in the UI.
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kRequestPinCodePath));
}
} else if (discovery_simulation_step_ == 4) {
UpdateDeviceRSSI(dbus::ObjectPath(kLowEnergyPath),
base::RandInt(kMinRSSI, kMaxRSSI));
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kDisplayPinCodePath));
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kVanishingDevicePath));
} else if (discovery_simulation_step_ == 7) {
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kConnectUnpairablePath));
UpdateDeviceRSSI(dbus::ObjectPath(kLowEnergyPath),
base::RandInt(kMinRSSI, kMaxRSSI));
} else if (discovery_simulation_step_ == 8) {
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kDisplayPasskeyPath));
if (delay_start_discovery_) {
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kRequestPinCodePath));
}
UpdateDeviceRSSI(dbus::ObjectPath(kLowEnergyPath),
base::RandInt(kMinRSSI, kMaxRSSI));
} else if (discovery_simulation_step_ == 10) {
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kConfirmPasskeyPath));
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kRequestPasskeyPath));
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kUnconnectableDevicePath));
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kUnpairableDevicePath));
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kJustWorksPath));
UpdateDeviceRSSI(dbus::ObjectPath(kLowEnergyPath),
base::RandInt(kMinRSSI, kMaxRSSI));
} else if (discovery_simulation_step_ == 13) {
UpdateDeviceRSSI(dbus::ObjectPath(kLowEnergyPath),
base::RandInt(kMinRSSI, kMaxRSSI));
RemoveDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kVanishingDevicePath));
} else if (discovery_simulation_step_ == 14) {
UpdateDeviceRSSI(dbus::ObjectPath(kLowEnergyPath),
base::RandInt(kMinRSSI, kMaxRSSI));
return;
}
++discovery_simulation_step_;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::DiscoverySimulationTimer,
base::Unretained(this)),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
}
void FakeBluetoothDeviceClient::IncomingPairingSimulationTimer() {
if (!incoming_pairing_simulation_step_)
return;
VLOG(1) << "incoming pairing simulation, step "
<< incoming_pairing_simulation_step_;
switch (incoming_pairing_simulation_step_) {
case 1:
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kConfirmPasskeyPath));
SimulatePairing(dbus::ObjectPath(kConfirmPasskeyPath), true,
base::Bind(&base::DoNothing),
base::Bind(&SimpleErrorCallback));
break;
case 2:
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kJustWorksPath));
SimulatePairing(dbus::ObjectPath(kJustWorksPath), true,
base::Bind(&base::DoNothing),
base::Bind(&SimpleErrorCallback));
break;
case 3:
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kDisplayPinCodePath));
SimulatePairing(dbus::ObjectPath(kDisplayPinCodePath), true,
base::Bind(&base::DoNothing),
base::Bind(&SimpleErrorCallback));
break;
case 4:
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kDisplayPasskeyPath));
SimulatePairing(dbus::ObjectPath(kDisplayPasskeyPath), true,
base::Bind(&base::DoNothing),
base::Bind(&SimpleErrorCallback));
break;
case 5:
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kRequestPinCodePath));
SimulatePairing(dbus::ObjectPath(kRequestPinCodePath), true,
base::Bind(&base::DoNothing),
base::Bind(&SimpleErrorCallback));
break;
case 6:
CreateDevice(dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(kRequestPasskeyPath));
SimulatePairing(dbus::ObjectPath(kRequestPasskeyPath), true,
base::Bind(&base::DoNothing),
base::Bind(&SimpleErrorCallback));
break;
default:
return;
}
++incoming_pairing_simulation_step_;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::IncomingPairingSimulationTimer,
base::Unretained(this)),
base::TimeDelta::FromMilliseconds(kIncomingSimulationPairTimeMultiplier *
simulation_interval_ms_));
}
void FakeBluetoothDeviceClient::SimulatePairing(
const dbus::ObjectPath& object_path,
bool incoming_request,
const base::Closure& callback,
const ErrorCallback& error_callback) {
pairing_cancelled_ = false;
FakeBluetoothAgentManagerClient* fake_bluetooth_agent_manager_client =
static_cast<FakeBluetoothAgentManagerClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothAgentManagerClient());
FakeBluetoothAgentServiceProvider* agent_service_provider =
fake_bluetooth_agent_manager_client->GetAgentServiceProvider();
CHECK(agent_service_provider != NULL);
// Grab the device's pairing properties.
PairingOptionsMap::const_iterator iter =
pairing_options_map_.find(object_path);
// If the device with path |object_path| has simulated pairing properties
// defined, then pair it based on its |pairing_method|.
if (iter != pairing_options_map_.end()) {
if (iter->second->pairing_action == kPairingActionFail) {
// Fails the pairing with an org.bluez.Error.Failed error.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::FailSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
} else if (iter->second->pairing_method == kPairingMethodNone ||
iter->second->pairing_method.empty()) {
if (!iter->second->incoming) {
// Simply pair and connect the device.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
base::Unretained(this), object_path, callback,
error_callback),
base::TimeDelta::FromMilliseconds(
kSimulateNormalPairTimeMultiplier * simulation_interval_ms_));
} else {
agent_service_provider->RequestAuthorization(
object_path,
base::Bind(&FakeBluetoothDeviceClient::ConfirmationCallback,
base::Unretained(this), object_path, callback,
error_callback));
}
} else if (iter->second->pairing_method == kPairingMethodPinCode) {
if (iter->second->pairing_action == kPairingActionDisplay) {
// Display a Pincode, and wait before acting as if the other end
// accepted it.
agent_service_provider->DisplayPinCode(
object_path, iter->second->pairing_auth_token);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
base::Unretained(this), object_path, callback,
error_callback),
base::TimeDelta::FromMilliseconds(kPinCodeDevicePairTimeMultiplier *
simulation_interval_ms_));
} else if (iter->second->pairing_action == kPairingActionRequest) {
// Request a pin code.
agent_service_provider->RequestPinCode(
object_path, base::Bind(&FakeBluetoothDeviceClient::PinCodeCallback,
base::Unretained(this), object_path,
callback, error_callback));
} else if (iter->second->pairing_action == kPairingActionConfirmation) {
error_callback.Run(kNoResponseError, "No confirm for pincode pairing.");
}
} else if (iter->second->pairing_method == kPairingMethodPassKey) {
// Display a passkey, and each interval act as if another key was entered
// for it.
if (iter->second->pairing_action == kPairingActionDisplay) {
agent_service_provider->DisplayPasskey(
object_path, std::stoi(iter->second->pairing_auth_token), 0);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::Bind(&FakeBluetoothDeviceClient::SimulateKeypress,
base::Unretained(this), 1, object_path,
callback, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
} else if (iter->second->pairing_action == kPairingActionRequest) {
agent_service_provider->RequestPasskey(
object_path, base::Bind(&FakeBluetoothDeviceClient::PasskeyCallback,
base::Unretained(this), object_path,
callback, error_callback));
} else if (iter->second->pairing_action == kPairingActionConfirmation) {
agent_service_provider->RequestConfirmation(
object_path, std::stoi(iter->second->pairing_auth_token),
base::Bind(&FakeBluetoothDeviceClient::ConfirmationCallback,
base::Unretained(this), object_path, callback,
error_callback));
}
}
} else {
if (object_path == dbus::ObjectPath(kLegacyAutopairPath) ||
object_path == dbus::ObjectPath(kConnectUnpairablePath) ||
object_path == dbus::ObjectPath(kUnconnectableDevicePath) ||
object_path == dbus::ObjectPath(kLowEnergyPath)) {
// No need to call anything on the pairing delegate, just wait 3 times
// the interval before acting as if the other end accepted it.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
base::Unretained(this), object_path, callback,
error_callback),
base::TimeDelta::FromMilliseconds(kSimulateNormalPairTimeMultiplier *
simulation_interval_ms_));
} else if (object_path == dbus::ObjectPath(kDisplayPinCodePath)) {
// Display a Pincode, and wait before acting as if the other end accepted
// it.
agent_service_provider->DisplayPinCode(object_path, kTestPinCode);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
base::Unretained(this), object_path, callback,
error_callback),
base::TimeDelta::FromMilliseconds(kPinCodeDevicePairTimeMultiplier *
simulation_interval_ms_));
} else if (object_path == dbus::ObjectPath(kVanishingDevicePath)) {
// The vanishing device simulates being too far away, and thus times out.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::TimeoutSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(kVanishingDevicePairTimeMultiplier *
simulation_interval_ms_));
} else if (object_path == dbus::ObjectPath(kDisplayPasskeyPath)) {
// Display a passkey, and each interval act as if another key was entered
// for it.
agent_service_provider->DisplayPasskey(object_path, kTestPassKey, 0);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::Bind(&FakeBluetoothDeviceClient::SimulateKeypress,
base::Unretained(this), 1, object_path,
callback, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
} else if (object_path == dbus::ObjectPath(kRequestPinCodePath)) {
// Request a Pincode.
agent_service_provider->RequestPinCode(
object_path, base::Bind(&FakeBluetoothDeviceClient::PinCodeCallback,
base::Unretained(this), object_path, callback,
error_callback));
} else if (object_path == dbus::ObjectPath(kConfirmPasskeyPath) ||
object_path ==
dbus::ObjectPath(kConnectedTrustedNotPairedDevicePath)) {
// Request confirmation of a Passkey.
agent_service_provider->RequestConfirmation(
object_path, kTestPassKey,
base::Bind(&FakeBluetoothDeviceClient::ConfirmationCallback,
base::Unretained(this), object_path, callback,
error_callback));
} else if (object_path == dbus::ObjectPath(kRequestPasskeyPath)) {
// Request a Passkey from the user.
agent_service_provider->RequestPasskey(
object_path, base::Bind(&FakeBluetoothDeviceClient::PasskeyCallback,
base::Unretained(this), object_path, callback,
error_callback));
} else if (object_path == dbus::ObjectPath(kUnpairableDevicePath)) {
// Fails the pairing with an org.bluez.Error.Failed error.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::FailSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
} else if (object_path == dbus::ObjectPath(kJustWorksPath)) {
if (incoming_request) {
agent_service_provider->RequestAuthorization(
object_path,
base::Bind(&FakeBluetoothDeviceClient::ConfirmationCallback,
base::Unretained(this), object_path, callback,
error_callback));
} else {
// No need to call anything on the pairing delegate, just wait before
// acting as if the other end accepted it.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
base::Unretained(this), object_path, callback,
error_callback),
base::TimeDelta::FromMilliseconds(
kSimulateNormalPairTimeMultiplier * simulation_interval_ms_));
}
} else {
error_callback.Run(kNoResponseError, "No pairing fake");
}
}
}
void FakeBluetoothDeviceClient::CompleteSimulatedPairing(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "CompleteSimulatedPairing: " << object_path.value();
if (pairing_cancelled_) {
pairing_cancelled_ = false;
error_callback.Run(bluetooth_device::kErrorAuthenticationCanceled,
"Cancelled");
} else {
Properties* properties = GetProperties(object_path);
properties->paired.ReplaceValue(true);
callback.Run();
AddInputDeviceIfNeeded(object_path, properties);
}
}
void FakeBluetoothDeviceClient::TimeoutSimulatedPairing(
const dbus::ObjectPath& object_path,
const ErrorCallback& error_callback) {
VLOG(1) << "TimeoutSimulatedPairing: " << object_path.value();
error_callback.Run(bluetooth_device::kErrorAuthenticationTimeout,
"Timed out");
}
void FakeBluetoothDeviceClient::CancelSimulatedPairing(
const dbus::ObjectPath& object_path,
const ErrorCallback& error_callback) {
VLOG(1) << "CancelSimulatedPairing: " << object_path.value();
error_callback.Run(bluetooth_device::kErrorAuthenticationCanceled,
"Canceled");
}
void FakeBluetoothDeviceClient::RejectSimulatedPairing(
const dbus::ObjectPath& object_path,
const ErrorCallback& error_callback) {
VLOG(1) << "RejectSimulatedPairing: " << object_path.value();
error_callback.Run(bluetooth_device::kErrorAuthenticationRejected,
"Rejected");
}
void FakeBluetoothDeviceClient::FailSimulatedPairing(
const dbus::ObjectPath& object_path,
const ErrorCallback& error_callback) {
VLOG(1) << "FailSimulatedPairing: " << object_path.value();
error_callback.Run(bluetooth_device::kErrorFailed, "Failed");
}
void FakeBluetoothDeviceClient::AddInputDeviceIfNeeded(
const dbus::ObjectPath& object_path,
Properties* properties) {
// If the paired device is a HID device based on it's bluetooth class,
// simulate the Input interface.
FakeBluetoothInputClient* fake_bluetooth_input_client =
static_cast<FakeBluetoothInputClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothInputClient());
if ((properties->bluetooth_class.value() & 0x001f03) == 0x000500)
fake_bluetooth_input_client->AddInputDevice(object_path);
}
void FakeBluetoothDeviceClient::InvalidateDeviceRSSI(
const dbus::ObjectPath& object_path) {
PropertiesMap::const_iterator iter = properties_map_.find(object_path);
if (iter == properties_map_.end()) {
VLOG(2) << "Fake device does not exist: " << object_path.value();
return;
}
Properties* properties = iter->second.get();
DCHECK(properties);
// Invalidate the value and notify that it changed.
properties->rssi.set_valid(false);
properties->rssi.ReplaceValue(0);
}
void FakeBluetoothDeviceClient::UpdateDeviceRSSI(
const dbus::ObjectPath& object_path,
int16_t rssi) {
PropertiesMap::const_iterator iter = properties_map_.find(object_path);
if (iter == properties_map_.end()) {
VLOG(2) << "Fake device does not exist: " << object_path.value();
return;
}
Properties* properties = iter->second.get();
DCHECK(properties);
properties->rssi.set_valid(true);
properties->rssi.ReplaceValue(rssi);
}
void FakeBluetoothDeviceClient::UpdateServiceAndManufacturerData(
const dbus::ObjectPath& object_path,
const std::vector<std::string>& service_uuids,
const std::unordered_map<std::string, std::vector<uint8_t>>& service_data,
const std::unordered_map<uint16_t, std::vector<uint8_t>>&
manufacturer_data) {
PropertiesMap::const_iterator iter = properties_map_.find(object_path);
if (iter == properties_map_.end()) {
VLOG(2) << "Fake device does not exist: " << object_path.value();
return;
}
Properties* properties = iter->second.get();
DCHECK(properties);
properties->uuids.set_valid(true);
properties->service_data.set_valid(true);
properties->manufacturer_data.set_valid(true);
// BlueZ caches all the previously received advertisements. To mimic BlueZ
// caching behavior, merge the new data here with the existing data.
// TODO(crbug.com/707039): once the BlueZ caching behavior is changed, this
// needs to be updated as well.
std::vector<std::string> merged_uuids = service_uuids;
merged_uuids.insert(merged_uuids.begin(), properties->uuids.value().begin(),
properties->uuids.value().end());
properties->uuids.ReplaceValue(merged_uuids);
std::unordered_map<std::string, std::vector<uint8_t>> merged_service_data =
service_data;
merged_service_data.insert(properties->service_data.value().begin(),
properties->service_data.value().end());
properties->service_data.ReplaceValue(merged_service_data);
std::unordered_map<uint16_t, std::vector<uint8_t>> merged_manufacturer_data =
manufacturer_data;
merged_manufacturer_data.insert(properties->manufacturer_data.value().begin(),
properties->manufacturer_data.value().end());
properties->manufacturer_data.ReplaceValue(merged_manufacturer_data);
}
void FakeBluetoothDeviceClient::UpdateConnectionInfo(
uint16_t connection_rssi,
uint16_t transmit_power,
uint16_t max_transmit_power) {
connection_rssi_ = connection_rssi;
transmit_power_ = transmit_power;
max_transmit_power_ = max_transmit_power;
}
void FakeBluetoothDeviceClient::PinCodeCallback(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback,
BluetoothAgentServiceProvider::Delegate::Status status,
const std::string& pincode) {
VLOG(1) << "PinCodeCallback: " << object_path.value();
if (status == BluetoothAgentServiceProvider::Delegate::SUCCESS) {
PairingOptionsMap::const_iterator iter =
pairing_options_map_.find(object_path);
bool success = true;
// If the device has pairing options defined
if (iter != pairing_options_map_.end()) {
success = iter->second->pairing_auth_token == pincode;
}
if (success) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
base::Unretained(this), object_path, callback,
error_callback),
base::TimeDelta::FromMilliseconds(kSimulateNormalPairTimeMultiplier *
simulation_interval_ms_));
} else {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::RejectSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
}
} else if (status == BluetoothAgentServiceProvider::Delegate::CANCELLED) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CancelSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
} else if (status == BluetoothAgentServiceProvider::Delegate::REJECTED) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::RejectSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
}
}
void FakeBluetoothDeviceClient::PasskeyCallback(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback,
BluetoothAgentServiceProvider::Delegate::Status status,
uint32_t passkey) {
VLOG(1) << "PasskeyCallback: " << object_path.value();
if (status == BluetoothAgentServiceProvider::Delegate::SUCCESS) {
PairingOptionsMap::const_iterator iter =
pairing_options_map_.find(object_path);
bool success = true;
if (iter != pairing_options_map_.end()) {
success = static_cast<uint32_t>(
std::stoi(iter->second->pairing_auth_token)) == passkey;
}
if (success) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
base::Unretained(this), object_path, callback,
error_callback),
base::TimeDelta::FromMilliseconds(kSimulateNormalPairTimeMultiplier *
simulation_interval_ms_));
} else {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::RejectSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
}
} else if (status == BluetoothAgentServiceProvider::Delegate::CANCELLED) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CancelSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
} else if (status == BluetoothAgentServiceProvider::Delegate::REJECTED) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::RejectSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
}
}
void FakeBluetoothDeviceClient::ConfirmationCallback(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback,
BluetoothAgentServiceProvider::Delegate::Status status) {
VLOG(1) << "ConfirmationCallback: " << object_path.value();
if (status == BluetoothAgentServiceProvider::Delegate::SUCCESS) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
base::Unretained(this), object_path, callback,
error_callback),
base::TimeDelta::FromMilliseconds(kSimulateNormalPairTimeMultiplier *
simulation_interval_ms_));
} else if (status == BluetoothAgentServiceProvider::Delegate::CANCELLED) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CancelSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
} else if (status == BluetoothAgentServiceProvider::Delegate::REJECTED) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::RejectSimulatedPairing,
base::Unretained(this), object_path, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
}
}
void FakeBluetoothDeviceClient::SimulateKeypress(
uint16_t entered,
const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback) {
VLOG(1) << "SimulateKeypress " << entered << ": " << object_path.value();
FakeBluetoothAgentManagerClient* fake_bluetooth_agent_manager_client =
static_cast<FakeBluetoothAgentManagerClient*>(
bluez::BluezDBusManager::Get()->GetBluetoothAgentManagerClient());
FakeBluetoothAgentServiceProvider* agent_service_provider =
fake_bluetooth_agent_manager_client->GetAgentServiceProvider();
// The agent service provider object could have been destroyed after the
// pairing is canceled.
if (!agent_service_provider)
return;
agent_service_provider->DisplayPasskey(object_path, kTestPassKey, entered);
if (entered < 7) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::Bind(&FakeBluetoothDeviceClient::SimulateKeypress,
base::Unretained(this), entered + 1, object_path,
callback, error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
} else {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
base::Unretained(this), object_path, callback,
error_callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
}
}
void FakeBluetoothDeviceClient::ConnectionCallback(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback,
BluetoothProfileServiceProvider::Delegate::Status status) {
VLOG(1) << "ConnectionCallback: " << object_path.value();
if (status == BluetoothProfileServiceProvider::Delegate::SUCCESS) {
callback.Run();
} else if (status == BluetoothProfileServiceProvider::Delegate::CANCELLED) {
// TODO(keybuk): tear down this side of the connection
error_callback.Run(bluetooth_device::kErrorFailed, "Canceled");
} else if (status == BluetoothProfileServiceProvider::Delegate::REJECTED) {
// TODO(keybuk): tear down this side of the connection
error_callback.Run(bluetooth_device::kErrorFailed, "Rejected");
}
}
void FakeBluetoothDeviceClient::DisconnectionCallback(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
const ErrorCallback& error_callback,
BluetoothProfileServiceProvider::Delegate::Status status) {
VLOG(1) << "DisconnectionCallback: " << object_path.value();
if (status == BluetoothProfileServiceProvider::Delegate::SUCCESS) {
// TODO(keybuk): tear down this side of the connection
callback.Run();
} else if (status == BluetoothProfileServiceProvider::Delegate::CANCELLED) {
error_callback.Run(bluetooth_device::kErrorFailed, "Canceled");
} else if (status == BluetoothProfileServiceProvider::Delegate::REJECTED) {
error_callback.Run(bluetooth_device::kErrorFailed, "Rejected");
}
}
void FakeBluetoothDeviceClient::RemoveAllDevices() {
device_list_.clear();
}
void FakeBluetoothDeviceClient::CreateTestDevice(
const dbus::ObjectPath& adapter_path,
const base::Optional<std::string> name,
const std::string alias,
const std::string device_address,
const std::vector<std::string>& service_uuids,
device::BluetoothTransport type,
const std::unordered_map<std::string, std::vector<uint8_t>>& service_data,
const std::unordered_map<uint16_t, std::vector<uint8_t>>&
manufacturer_data) {
// Create a random device path.
dbus::ObjectPath device_path;
std::string id;
do {
// Construct an id that is valid according to the DBUS specification.
base::Base64Encode(base::RandBytesAsString(10), &id);
base::RemoveChars(id, "+/=", &id);
device_path = dbus::ObjectPath(adapter_path.value() + "/dev" + id);
} while (base::ContainsValue(device_list_, device_path));
std::unique_ptr<Properties> properties(
new Properties(base::Bind(&FakeBluetoothDeviceClient::OnPropertyChanged,
base::Unretained(this), device_path)));
properties->adapter.ReplaceValue(adapter_path);
properties->address.ReplaceValue(device_address);
properties->name.ReplaceValue(
name.value_or("Invalid Device Name set in "
"FakeBluetoothDeviceClient::CreateTestDevice"));
properties->name.set_valid(name.has_value());
properties->alias.ReplaceValue(alias);
properties->uuids.ReplaceValue(service_uuids);
properties->bluetooth_class.ReplaceValue(
0x1F00u); // Unspecified Device Class
switch (type) {
case device::BLUETOOTH_TRANSPORT_CLASSIC:
properties->type.ReplaceValue(BluetoothDeviceClient::kTypeBredr);
break;
case device::BLUETOOTH_TRANSPORT_LE:
properties->type.ReplaceValue(BluetoothDeviceClient::kTypeLe);
break;
case device::BLUETOOTH_TRANSPORT_DUAL:
properties->type.ReplaceValue(BluetoothDeviceClient::kTypeDual);
break;
default:
NOTREACHED();
}
properties->type.set_valid(true);
if (!service_data.empty()) {
properties->service_data.ReplaceValue(service_data);
properties->service_data.set_valid(true);
}
if (!manufacturer_data.empty()) {
properties->manufacturer_data.ReplaceValue(manufacturer_data);
properties->manufacturer_data.set_valid(true);
}
properties_map_.insert(std::make_pair(device_path, std::move(properties)));
device_list_.push_back(device_path);
for (auto& observer : observers_)
observer.DeviceAdded(device_path);
}
} // namespace bluez