Commit 543bb910 authored by Ryan Hansberry's avatar Ryan Hansberry Committed by Commit Bot

[Bluetooth] Implement and use ConnectDevice().

Consume the org.bluez.Adapter1 ConnectDevice() method [1] to
allow Chrome clients to connect to a remote device (via their MAC
address) which they know is available and nearby, but is not known
to the lower-level Bluetooth stack (likely because the device is
not discoverable).

This change is motivated by a core flow of the Nearby Share feature.
In this flow, Nearby Share discovers a remote device via a
non-connectable BLE advertisement, determines that remote device's
BR/EDR MAC address by deciphering the BLE advertisement with
previously downloaded certificates, and then connects via RFCOMM.
In this situation, Nearby Share knows a device with the MAC address
is available and nearby, but bluez does not -- hence the need for
this change. More details at go/nearby-chrome-bt.

1) https://source.chromium.org/chromiumos/chromiumos/codesearch/+/master:src/third_party/bluez/next/doc/adapter-api.txt;l=187

Bug: 1140471
Change-Id: Ibb67f5ca2def444799205394767892b8d651b539
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2491131
Commit-Queue: Ryan Hansberry <hansberry@chromium.org>
Reviewed-by: default avatarSonny Sasaka <sonnysasaka@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Reviewed-by: default avatarMiao-chen Chou <mcchou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821461}
parent d037c97b
......@@ -175,13 +175,28 @@ void Adapter::ConnectToServiceInsecurely(
const std::string& address,
const device::BluetoothUUID& service_uuid,
ConnectToServiceInsecurelyCallback callback) {
auto* device = adapter_->GetDevice(address);
if (device) {
OnDeviceFetchedForInsecureServiceConnection(service_uuid,
std::move(callback), device);
return;
}
// This device has neither been discovered, nor has it been paired/connected
// to previously. Use the ConnectDevice() API, if available, to connect to it.
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
adapter_->GetDevice(address)->ConnectToServiceInsecurely(
service_uuid,
base::BindOnce(&Adapter::OnConnectToService,
weak_ptr_factory_.GetWeakPtr(), copyable_callback),
adapter_->ConnectDevice(
address, /*address_type=*/base::nullopt,
base::BindOnce(&Adapter::OnDeviceFetchedForInsecureServiceConnection,
weak_ptr_factory_.GetWeakPtr(), service_uuid,
copyable_callback),
base::BindOnce(&Adapter::OnConnectToServiceError,
weak_ptr_factory_.GetWeakPtr(), copyable_callback));
weak_ptr_factory_.GetWeakPtr(), copyable_callback,
"Cannot connect to device."));
#else
OnConnectToServiceError(std::move(callback), "Device does not exist.");
#endif
}
void Adapter::CreateRfcommService(const std::string& service_name,
......@@ -244,6 +259,56 @@ void Adapter::DeviceRemoved(device::BluetoothAdapter* adapter,
observer->DeviceRemoved(device_info->Clone());
}
void Adapter::GattServicesDiscovered(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
// GattServicesDiscovered() and IsGattServicesDiscoveryComplete() actually
// indicate that all services on the remote device, including SDP, are
// resolved. Once service probing for a device within a cached request (in
// |pending_connect_to_service_args_|) concludes, attempt socket creation
// again via OnDeviceFetchedForInsecureServiceConnection().
if (!device->IsGattServicesDiscoveryComplete())
return;
const std::string& address = device->GetAddress();
auto it = pending_connect_to_service_args_.begin();
while (it != pending_connect_to_service_args_.end()) {
if (address == std::get<0>(*it)) {
OnDeviceFetchedForInsecureServiceConnection(
/*service_uuid=*/std::get<1>(*it),
/*callback=*/std::move(std::get<2>(*it)), device);
it = pending_connect_to_service_args_.erase(it);
} else {
++it;
}
}
}
void Adapter::OnDeviceFetchedForInsecureServiceConnection(
const device::BluetoothUUID& service_uuid,
ConnectToServiceInsecurelyCallback callback,
device::BluetoothDevice* device) {
if (device->IsConnected() && !device->IsGattServicesDiscoveryComplete()) {
// This provided device is most likely a result of calling ConnectDevice():
// it's connected, but the remote device's services are still being probed
// (IsGattServicesDiscoveryComplete() refers to all services, not just GATT
// services). That means attempting ConnectToServiceInsecurely() right now
// would fail with an "InProgress" error. Wait for GattServicesDiscovered()
// to be called to signal that ConnectToServiceInsecurely() can be called.
pending_connect_to_service_args_.emplace_back(
device->GetAddress(), service_uuid, std::move(callback));
return;
}
auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
device->ConnectToServiceInsecurely(
service_uuid,
base::BindOnce(&Adapter::OnConnectToService,
weak_ptr_factory_.GetWeakPtr(), copyable_callback),
base::BindOnce(&Adapter::OnConnectToServiceError,
weak_ptr_factory_.GetWeakPtr(), copyable_callback));
}
void Adapter::OnGattConnected(
ConnectToDeviceCallback callback,
std::unique_ptr<device::BluetoothGattConnection> connection) {
......
......@@ -7,6 +7,8 @@
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
......@@ -71,8 +73,15 @@ class Adapter : public mojom::Adapter,
device::BluetoothDevice* device) override;
void DeviceRemoved(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override;
void GattServicesDiscovered(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override;
private:
void OnDeviceFetchedForInsecureServiceConnection(
const device::BluetoothUUID& service_uuid,
ConnectToServiceInsecurelyCallback callback,
device::BluetoothDevice* device);
void OnGattConnected(
ConnectToDeviceCallback callback,
std::unique_ptr<device::BluetoothGattConnection> connection);
......@@ -113,6 +122,13 @@ class Adapter : public mojom::Adapter,
// The adapter observers that listen to this service.
mojo::RemoteSet<mojom::AdapterObserver> observers_;
// Arguments provided to ConnectToServiceInsecurely(), cached until the
// device is ready to be connected to.
std::vector<std::tuple<std::string,
device::BluetoothUUID,
ConnectToServiceInsecurelyCallback>>
pending_connect_to_service_args_;
base::WeakPtrFactory<Adapter> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(Adapter);
......
......@@ -6,21 +6,32 @@
#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/task/thread_pool.h"
#include "base/test/bind_test_util.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "device/bluetooth/bluetooth_advertisement.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_advertisement.h"
#include "device/bluetooth/test/mock_bluetooth_device.h"
#include "device/bluetooth/test/mock_bluetooth_socket.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using base::test::RunOnceCallback;
using testing::_;
using testing::DoAll;
using testing::InvokeWithoutArgs;
using testing::NiceMock;
using testing::Return;
namespace {
const char kKnownDeviceAddress[] = "00:00:00:00:01";
const char kUnknownDeviceAddress[] = "00:00:00:00:02";
const char kServiceId[] = "0000abcd-0000-0000-0000-000000000001";
const char kDeviceServiceDataStr[] = "ServiceData";
......@@ -73,6 +84,30 @@ class AdapterTest : public testing::Test {
ON_CALL(*mock_bluetooth_adapter_, IsPresent()).WillByDefault(Return(true));
ON_CALL(*mock_bluetooth_adapter_, IsPowered()).WillByDefault(Return(true));
// |mock_known_bluetooth_device_| is a device found via discovery.
mock_known_bluetooth_device_ =
std::make_unique<testing::NiceMock<device::MockBluetoothDevice>>(
mock_bluetooth_adapter_.get(),
/*class=*/0, "Known Device", kKnownDeviceAddress,
/*paired=*/false,
/*connected=*/false);
// |mock_unknown_bluetooth_device_| is |connected| because it is created
// as a result of calling ConnectDevice().
mock_unknown_bluetooth_device_ =
std::make_unique<testing::NiceMock<device::MockBluetoothDevice>>(
mock_bluetooth_adapter_.get(),
/*class=*/0, "Unknown Device", kUnknownDeviceAddress,
/*paired=*/false,
/*connected=*/true);
// |mock_bluetooth_adapter_| can only find |mock_known_bluetooth_device_|
// via GetDevice(), not |mock_unknown_bluetooth_device_|.
ON_CALL(*mock_bluetooth_adapter_, GetDevice(kKnownDeviceAddress))
.WillByDefault(Return(mock_known_bluetooth_device_.get()));
mock_bluetooth_socket_ =
base::MakeRefCounted<NiceMock<device::MockBluetoothSocket>>();
adapter_ = std::make_unique<Adapter>(mock_bluetooth_adapter_);
}
......@@ -131,6 +166,11 @@ class AdapterTest : public testing::Test {
scoped_refptr<NiceMock<MockBluetoothAdapterWithAdvertisements>>
mock_bluetooth_adapter_;
std::unique_ptr<NiceMock<device::MockBluetoothDevice>>
mock_known_bluetooth_device_;
std::unique_ptr<NiceMock<device::MockBluetoothDevice>>
mock_unknown_bluetooth_device_;
scoped_refptr<NiceMock<device::MockBluetoothSocket>> mock_bluetooth_socket_;
std::unique_ptr<Adapter> adapter_;
private:
......@@ -152,4 +192,131 @@ TEST_F(AdapterTest, TestRegisterAdvertisement_ScanResponseData) {
VerifyAdvertisementWithScanData();
}
TEST_F(AdapterTest, TestConnectToServiceInsecurely_KnownDevice_Success) {
EXPECT_CALL(
*mock_known_bluetooth_device_,
ConnectToServiceInsecurely(device::BluetoothUUID(kServiceId), _, _))
.WillOnce(RunOnceCallback<1>(mock_bluetooth_socket_));
base::RunLoop run_loop;
adapter_->ConnectToServiceInsecurely(
kKnownDeviceAddress, device::BluetoothUUID(kServiceId),
base::BindLambdaForTesting(
[&](mojom::ConnectToServiceResultPtr connect_to_service_result) {
EXPECT_TRUE(connect_to_service_result);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(AdapterTest, TestConnectToServiceInsecurely_KnownDevice_Error) {
EXPECT_CALL(
*mock_known_bluetooth_device_,
ConnectToServiceInsecurely(device::BluetoothUUID(kServiceId), _, _))
.WillOnce(RunOnceCallback<2>("Error"));
base::RunLoop run_loop;
adapter_->ConnectToServiceInsecurely(
kKnownDeviceAddress, device::BluetoothUUID(kServiceId),
base::BindLambdaForTesting(
[&](mojom::ConnectToServiceResultPtr connect_to_service_result) {
EXPECT_FALSE(connect_to_service_result);
run_loop.Quit();
}));
run_loop.Run();
}
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
TEST_F(
AdapterTest,
TestConnectToServiceInsecurely_UnknownDevice_Success_ServicesAlreadyResolved) {
EXPECT_CALL(*mock_bluetooth_adapter_,
ConnectDevice(kUnknownDeviceAddress, _, _, _))
.WillOnce(RunOnceCallback<2>(mock_unknown_bluetooth_device_.get()));
EXPECT_CALL(
*mock_unknown_bluetooth_device_,
ConnectToServiceInsecurely(device::BluetoothUUID(kServiceId), _, _))
.WillOnce(RunOnceCallback<1>(mock_bluetooth_socket_));
EXPECT_CALL(*mock_unknown_bluetooth_device_,
IsGattServicesDiscoveryComplete())
.WillOnce(Return(true));
base::RunLoop run_loop;
adapter_->ConnectToServiceInsecurely(
kUnknownDeviceAddress, device::BluetoothUUID(kServiceId),
base::BindLambdaForTesting(
[&](mojom::ConnectToServiceResultPtr connect_to_service_result) {
EXPECT_TRUE(connect_to_service_result);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(
AdapterTest,
TestConnectToServiceInsecurely_UnknownDevice_Success_WaitForServicesToResolve) {
EXPECT_CALL(*mock_bluetooth_adapter_,
ConnectDevice(kUnknownDeviceAddress, _, _, _))
.WillOnce(RunOnceCallback<2>(mock_unknown_bluetooth_device_.get()));
EXPECT_CALL(
*mock_unknown_bluetooth_device_,
ConnectToServiceInsecurely(device::BluetoothUUID(kServiceId), _, _))
.WillOnce(RunOnceCallback<1>(mock_bluetooth_socket_));
// At first, return false to force |adapter_| to wait for the value to change,
// but subsequently return true. On that first call, post a task to trigger
// a notification that services are now resolved.
EXPECT_CALL(*mock_unknown_bluetooth_device_,
IsGattServicesDiscoveryComplete())
.WillOnce(DoAll(InvokeWithoutArgs([this]() {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
adapter_->GattServicesDiscovered(
mock_bluetooth_adapter_.get(),
mock_unknown_bluetooth_device_.get());
}));
}),
Return(false)))
.WillRepeatedly(Return(true));
base::RunLoop run_loop;
adapter_->ConnectToServiceInsecurely(
kUnknownDeviceAddress, device::BluetoothUUID(kServiceId),
base::BindLambdaForTesting(
[&](mojom::ConnectToServiceResultPtr connect_to_service_result) {
EXPECT_TRUE(connect_to_service_result);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(AdapterTest, TestConnectToServiceInsecurely_UnknownDevice_Error) {
EXPECT_CALL(*mock_bluetooth_adapter_,
ConnectDevice(kUnknownDeviceAddress, _, _, _))
.WillOnce(RunOnceCallback<3>());
base::RunLoop run_loop;
adapter_->ConnectToServiceInsecurely(
kUnknownDeviceAddress, device::BluetoothUUID(kServiceId),
base::BindLambdaForTesting(
[&](mojom::ConnectToServiceResultPtr connect_to_service_result) {
EXPECT_FALSE(connect_to_service_result);
run_loop.Quit();
}));
run_loop.Run();
}
#else
TEST_F(AdapterTest, TestConnectToServiceInsecurely_UnknownDevice) {
base::RunLoop run_loop;
adapter_->ConnectToServiceInsecurely(
kUnknownDeviceAddress, device::BluetoothUUID(kServiceId),
base::BindLambdaForTesting(
[&](mojom::ConnectToServiceResultPtr connect_to_service_result) {
EXPECT_FALSE(connect_to_service_result);
run_loop.Quit();
}));
run_loop.Run();
}
#endif
} // namespace bluetooth
......@@ -333,6 +333,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
using CreateAdvertisementCallback =
base::OnceCallback<void(scoped_refptr<BluetoothAdvertisement>)>;
using AdvertisementErrorCallback = BluetoothAdvertisement::ErrorCallback;
using ConnectDeviceCallback = base::OnceCallback<void(BluetoothDevice*)>;
using DiscoverySessionErrorCallback =
base::OnceCallback<void(UMABluetoothDiscoverySessionOutcome)>;
// The is_error bool is a flag to indicate if the result is an error(true)
......@@ -578,6 +579,17 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
// advertisements and will stop advertising them.
virtual void ResetAdvertising(base::OnceClosure callback,
AdvertisementErrorCallback error_callback) = 0;
// Connect to a device with |address| that is either undiscovered or not
// previously paired or connected. Callers are responsible for ensuring that
// the device with |address| is available and nearby via their own out-of-band
// mechanism, and should not call this method if GetDevice(address) returns
// a valid reference (in which case this method will fail).
virtual void ConnectDevice(
const std::string& address,
const base::Optional<BluetoothDevice::AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) = 0;
#endif
// Returns the list of pending advertisements that are not registered yet.
......
......@@ -121,6 +121,11 @@ class TestBluetoothAdapter final : public BluetoothAdapter {
AdvertisementErrorCallback error_callback) override {}
void ResetAdvertising(base::OnceClosure callback,
AdvertisementErrorCallback error_callback) override {}
void ConnectDevice(
const std::string& address,
const base::Optional<BluetoothDevice::AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) override {}
#endif
BluetoothLocalGattService* GetGattService(
......
......@@ -594,6 +594,38 @@ void BluetoothAdapterBlueZ::ResetAdvertising(
std::move(error_callback)));
}
void BluetoothAdapterBlueZ::ConnectDevice(
const std::string& address,
const base::Optional<device::BluetoothDevice::AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) {
DCHECK(bluez::BluezDBusManager::Get());
base::Optional<BluetoothAdapterClient::AddressType> client_address_type;
if (address_type) {
switch (*address_type) {
case device::BluetoothDevice::AddressType::ADDR_TYPE_PUBLIC:
client_address_type = BluetoothAdapterClient::AddressType::kPublic;
break;
case device::BluetoothDevice::AddressType::ADDR_TYPE_RANDOM:
client_address_type = BluetoothAdapterClient::AddressType::kRandom;
break;
case device::BluetoothDevice::AddressType::ADDR_TYPE_UNKNOWN:
default:
// Keep |client_address_type| unset.
break;
};
}
bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->ConnectDevice(
object_path_, address, client_address_type,
base::BindOnce(&BluetoothAdapterBlueZ::OnConnectDevice,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
base::BindOnce(&BluetoothAdapterBlueZ::OnConnectDeviceError,
weak_ptr_factory_.GetWeakPtr(),
std::move(error_callback)));
}
device::BluetoothLocalGattService* BluetoothAdapterBlueZ::GetGattService(
const std::string& identifier) const {
const auto& service = owned_gatt_services_.find(dbus::ObjectPath(identifier));
......@@ -1885,6 +1917,19 @@ void BluetoothAdapterBlueZ::ServiceRecordErrorConnector(
std::move(error_callback).Run(code);
}
void BluetoothAdapterBlueZ::OnConnectDevice(
ConnectDeviceCallback callback,
const dbus::ObjectPath& object_path) {
std::move(callback).Run(GetDeviceWithPath(object_path));
}
void BluetoothAdapterBlueZ::OnConnectDeviceError(
ErrorCallback error_callback,
const std::string& error_name,
const std::string& error_message) {
std::move(error_callback).Run();
}
void BluetoothAdapterBlueZ::UpdateDeviceBatteryLevelFromBatteryClient(
const dbus::ObjectPath& object_path) {
BluetoothDevice* device = GetDeviceWithPath(object_path);
......
......@@ -149,6 +149,12 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ final
void ResetAdvertising(base::OnceClosure callback,
AdvertisementErrorCallback error_callback) override;
void ConnectDevice(
const std::string& address,
const base::Optional<device::BluetoothDevice::AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) override;
device::BluetoothLocalGattService* GetGattService(
const std::string& identifier) const override;
......@@ -467,6 +473,12 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ final
const std::string& error_name,
const std::string& error_message);
void OnConnectDevice(ConnectDeviceCallback callback,
const dbus::ObjectPath& object_path);
void OnConnectDeviceError(ErrorCallback error_callback,
const std::string& error_name,
const std::string& error_message);
// Updates |battery_percentage| field of a device based on its corresponding
// value in Battery interface. Should be called when receiving events about
// battery object addition, change, or removal.
......
......@@ -28,6 +28,9 @@ namespace bluez {
// Automatically determine transport mode.
constexpr char kBluezAutoTransport[] = "auto";
constexpr char kBluezAddressTypePublic[] = "public";
constexpr char kBluezAddressTypeRandom[] = "random";
namespace {
// TODO(rkc) Find better way to do this.
......@@ -190,7 +193,7 @@ BluetoothAdapterClient::Properties::~Properties() = default;
class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
public dbus::ObjectManager::Interface {
public:
BluetoothAdapterClientImpl() : object_manager_(nullptr) {}
BluetoothAdapterClientImpl() = default;
~BluetoothAdapterClientImpl() override {
// There is an instance of this client that is created but not initialized
......@@ -495,6 +498,52 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
std::move(error_callback)));
}
// BluetoothAdapterClient override.
void ConnectDevice(const dbus::ObjectPath& object_path,
const std::string& address,
const base::Optional<AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) override {
dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kConnectDevice);
dbus::MessageWriter writer(&method_call);
base::DictionaryValue dict;
dict.SetStringKey(bluetooth_device::kAddressProperty, address);
if (address_type) {
std::string address_type_value;
switch (*address_type) {
case AddressType::kPublic:
address_type_value = kBluezAddressTypePublic;
break;
case AddressType::kRandom:
address_type_value = kBluezAddressTypeRandom;
break;
default:
NOTREACHED();
break;
};
dict.SetStringKey(bluetooth_device::kAddressTypeProperty,
address_type_value);
}
dbus::AppendValueData(&writer, dict);
dbus::ObjectProxy* object_proxy =
object_manager_->GetObjectProxy(object_path);
if (!object_proxy) {
std::move(error_callback).Run(kUnknownAdapterError, "");
return;
}
object_proxy->CallMethodWithErrorCallback(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&BluetoothAdapterClientImpl::OnConnectDevice,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
base::BindOnce(&BluetoothAdapterClientImpl::OnError,
weak_ptr_factory_.GetWeakPtr(),
std::move(error_callback)));
}
protected:
void Init(dbus::Bus* bus,
const std::string& bluetooth_service_name) override {
......@@ -532,17 +581,6 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
observer.AdapterPropertyChanged(object_path, property_name);
}
// Called when a response for successful method call is received.
void OnCreateServiceRecord(ServiceRecordCallback callback,
dbus::Response* response) {
DCHECK(response);
dbus::MessageReader reader(response);
uint32_t handle = 0;
if (!reader.PopUint32(&handle))
LOG(ERROR) << "Invalid response from CreateServiceRecord.";
std::move(callback).Run(handle);
}
// Called when a response for successful method call is received.
void OnSuccess(base::OnceClosure callback, dbus::Response* response) {
DCHECK(response);
......@@ -576,7 +614,29 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
std::move(callback).Run(ErrorResponseToError(error_response));
}
dbus::ObjectManager* object_manager_;
// Called when CreateServiceRecord() succeeds.
void OnCreateServiceRecord(ServiceRecordCallback callback,
dbus::Response* response) {
DCHECK(response);
dbus::MessageReader reader(response);
uint32_t handle = 0;
if (!reader.PopUint32(&handle))
LOG(ERROR) << "Invalid response from CreateServiceRecord.";
std::move(callback).Run(handle);
}
// Called when ConnectDevice() succeeds.
void OnConnectDevice(ConnectDeviceCallback callback,
dbus::Response* response) {
DCHECK(response);
dbus::MessageReader reader(response);
dbus::ObjectPath device_path;
if (!reader.PopObjectPath(&device_path))
LOG(ERROR) << "Invalid response from ConnectDevice.";
std::move(callback).Run(device_path);
}
dbus::ObjectManager* object_manager_ = nullptr;
// List of observers interested in event notifications from us.
base::ObserverList<BluetoothAdapterClient::Observer>::Unchecked observers_;
......
......@@ -30,6 +30,11 @@ class BluetoothServiceRecordBlueZ;
// local Bluetooth Adapters.
class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterClient : public BluezDBusClient {
public:
enum AddressType {
kPublic,
kRandom,
};
// A DiscoveryFilter represents a filter passed to the SetDiscoveryFilter
// method.
struct DiscoveryFilter {
......@@ -149,6 +154,10 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterClient : public BluezDBusClient {
// Callback used to send back the handle of a created service record.
using ServiceRecordCallback = base::OnceCallback<void(uint32_t)>;
// Callback used to send back the device resulting from ConnectDevice().
using ConnectDeviceCallback =
base::OnceCallback<void(const dbus::ObjectPath& device_path)>;
// The ErrorCallback is used by adapter methods to indicate failure.
// It receives two arguments: the name of the error in |error_name| and
// an optional message in |error_message|.
......@@ -221,6 +230,15 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterClient : public BluezDBusClient {
base::OnceClosure callback,
ErrorCallback error_callback) = 0;
// Connects to specified device, even if the device has not been discovered,
// on the adapter with the object path |object_path|. Not providing an
// |address_type| will create a BR/EDR device.
virtual void ConnectDevice(const dbus::ObjectPath& object_path,
const std::string& address,
const base::Optional<AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) = 0;
// Creates the instance.
static BluetoothAdapterClient* Create();
......
......@@ -302,6 +302,15 @@ void FakeBluetoothAdapterClient::RemoveServiceRecord(
std::move(callback).Run();
}
void FakeBluetoothAdapterClient::ConnectDevice(
const dbus::ObjectPath& object_path,
const std::string& address,
const base::Optional<AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) {
NOTIMPLEMENTED();
}
void FakeBluetoothAdapterClient::SetSimulationIntervalMs(int interval_ms) {
simulation_interval_ms_ = interval_ms;
}
......
......@@ -75,6 +75,11 @@ class DEVICE_BLUETOOTH_EXPORT FakeBluetoothAdapterClient
uint32_t handle,
base::OnceClosure callback,
ErrorCallback error_callback) override;
void ConnectDevice(const dbus::ObjectPath& object_path,
const std::string& address,
const base::Optional<AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) override;
// Sets the current simulation timeout interval.
void SetSimulationIntervalMs(int interval_ms);
......
......@@ -591,6 +591,13 @@ void FakeCentral::ResetAdvertising(base::OnceClosure callback,
AdvertisementErrorCallback error_callback) {
NOTREACHED();
}
void FakeCentral::ConnectDevice(
const std::string& address,
const base::Optional<device::BluetoothDevice::AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) {
NOTREACHED();
}
#endif
device::BluetoothLocalGattService* FakeCentral::GetGattService(
......
......@@ -179,6 +179,11 @@ class FakeCentral final : public mojom::FakeCentral,
AdvertisementErrorCallback error_callback) override;
void ResetAdvertising(base::OnceClosure callback,
AdvertisementErrorCallback error_callback) override;
void ConnectDevice(
const std::string& address,
const base::Optional<device::BluetoothDevice::AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) override;
#endif
device::BluetoothLocalGattService* GetGattService(
const std::string& identifier) const override;
......
......@@ -113,6 +113,15 @@ class MockBluetoothAdapter : public BluetoothAdapter {
CreateServiceErrorCallback error_callback));
MOCK_CONST_METHOD1(GetGattService,
BluetoothLocalGattService*(const std::string& identifier));
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
MOCK_METHOD4(
ConnectDevice,
void(const std::string& address,
const base::Optional<BluetoothDevice::AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback));
#endif
// BluetoothAdapter is supposed to manage the lifetime of BluetoothDevices.
// This method takes ownership of the MockBluetoothDevice. This is only for
......
......@@ -417,6 +417,14 @@ class DEVICE_BLUETOOTH_EXPORT TestBluetoothAdapterClient
NOTIMPLEMENTED();
}
void ConnectDevice(const dbus::ObjectPath& object_path,
const std::string& address,
const base::Optional<AddressType>& address_type,
ConnectDeviceCallback callback,
ErrorCallback error_callback) override {
NOTIMPLEMENTED();
}
private:
// Keeps track of how many times methods have been called.
struct CallCounts {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment