Commit 87896a75 authored by ortuno's avatar ortuno Committed by Commit bot

bluetooth: Partial implementation of connectGATT.

Now connectGATT connects to the BLE device. This is the first
step towards fully implementing connectGATT.

Also adds BluetoothMsg_ConnectGATTError.

Layout tests are in:

http://crrev.com/1150523004

BUG=421668

Review URL: https://codereview.chromium.org/1120373004

Cr-Commit-Position: refs/heads/master@{#330883}
parent c415dfed
......@@ -100,10 +100,27 @@ void BluetoothDispatcherHost::OnConnectGATT(
int request_id,
const std::string& device_instance_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// TODO(ortuno): Add actual implementation of connectGATT. This needs to be
// done after the "allowed devices map" is implemented.
Send(new BluetoothMsg_ConnectGATTSuccess(thread_id, request_id,
device_instance_id));
// TODO(ortuno): Right now it's pointless to check if the domain has access to
// the device, because any domain can connect to any device. But once
// permissions are implemented we should check that the domain has access to
// the device. https://crbug.com/484745
device::BluetoothDevice* device = adapter_->GetDevice(device_instance_id);
if (device == NULL) {
// Device could have gone out of range so it's no longer in
// BluetoothAdapter. Since we can't create a ATT Bearer without a device we
// reject with NetworkError.
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-connectgatt
Send(new BluetoothMsg_ConnectGATTError(thread_id, request_id,
BluetoothError::NETWORK_ERROR));
return;
}
device->CreateGattConnection(
base::Bind(&BluetoothDispatcherHost::OnGATTConnectionCreated,
weak_ptr_factory_.GetWeakPtr(), thread_id, request_id,
device_instance_id),
base::Bind(&BluetoothDispatcherHost::OnCreateGATTConnectionError,
weak_ptr_factory_.GetWeakPtr(), thread_id, request_id,
device_instance_id));
}
void BluetoothDispatcherHost::OnDiscoverySessionStarted(
......@@ -172,4 +189,27 @@ void BluetoothDispatcherHost::OnDiscoverySessionStoppedError(int thread_id,
BluetoothError::NOT_FOUND));
}
void BluetoothDispatcherHost::OnGATTConnectionCreated(
int thread_id,
int request_id,
const std::string& device_instance_id,
scoped_ptr<device::BluetoothGattConnection> connection) {
// TODO(ortuno): Save the BluetoothGattConnection so we can disconnect
// from it.
Send(new BluetoothMsg_ConnectGATTSuccess(thread_id, request_id,
device_instance_id));
}
void BluetoothDispatcherHost::OnCreateGATTConnectionError(
int thread_id,
int request_id,
const std::string& device_instance_id,
device::BluetoothDevice::ConnectErrorCode error_code) {
// There was an error creating the ATT Bearer so we reject with
// NetworkError.
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-connectgatt
Send(new BluetoothMsg_ConnectGATTError(thread_id, request_id,
BluetoothError::NETWORK_ERROR));
}
} // namespace content
......@@ -10,6 +10,7 @@
#include "content/common/bluetooth/bluetooth_error.h"
#include "content/public/browser/browser_message_filter.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_gatt_connection.h"
namespace content {
......@@ -70,6 +71,18 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
void OnDiscoverySessionStopped(int thread_id, int request_id);
void OnDiscoverySessionStoppedError(int thread_id, int request_id);
// Callbacks for BluetoothDevice::CreateGattConnection
void OnGATTConnectionCreated(
int thread_id,
int request_id,
const std::string& device_instance_id,
scoped_ptr<device::BluetoothGattConnection> connection);
void OnCreateGATTConnectionError(
int thread_id,
int request_id,
const std::string& device_instance_id,
device::BluetoothDevice::ConnectErrorCode error_code);
// Defines how long to scan for.
int current_scan_time_;
......
......@@ -101,6 +101,7 @@ void BluetoothDispatcher::OnMessageReceived(const IPC::Message& msg) {
OnRequestDeviceSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceError, OnRequestDeviceError);
IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTSuccess, OnConnectGATTSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTError, OnConnectGATTError);
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
DCHECK(handled) << "Unhandled message:" << msg.type();
......@@ -143,6 +144,18 @@ void BluetoothDispatcher::OnRequestDeviceSuccess(
pending_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnRequestDeviceError(int thread_id,
int request_id,
BluetoothError error_type) {
DCHECK(pending_requests_.Lookup(request_id)) << request_id;
pending_requests_.Lookup(request_id)
->onError(new WebBluetoothError(
// TODO(ortuno): Return more descriptive error messages.
// http://crbug.com/490419
WebBluetoothErrorFromBluetoothError(error_type), ""));
pending_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnConnectGATTSuccess(
int thread_id,
int request_id,
......@@ -154,14 +167,16 @@ void BluetoothDispatcher::OnConnectGATTSuccess(
pending_connect_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnRequestDeviceError(int thread_id,
int request_id,
BluetoothError error_type) {
DCHECK(pending_requests_.Lookup(request_id)) << request_id;
pending_requests_.Lookup(request_id)
void BluetoothDispatcher::OnConnectGATTError(int thread_id,
int request_id,
BluetoothError error_type) {
DCHECK(pending_connect_requests_.Lookup(request_id)) << request_id;
pending_connect_requests_.Lookup(request_id)
->onError(new WebBluetoothError(
// TODO(ortuno): Return more descriptive error messages.
// http://crbug.com/490419
WebBluetoothErrorFromBluetoothError(error_type), ""));
pending_requests_.Remove(request_id);
pending_connect_requests_.Remove(request_id);
}
} // namespace content
......@@ -67,6 +67,10 @@ class BluetoothDispatcher : public WorkerTaskRunner::Observer {
int request_id,
const std::string& message);
void OnConnectGATTError(int thread_id,
int request_id,
BluetoothError error_type);
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
// Tracks device requests sent to browser to match replies with callbacks.
......
......@@ -123,6 +123,12 @@ IPC_MESSAGE_CONTROL3(BluetoothMsg_ConnectGATTSuccess,
int /* request_id */,
std::string /* device_instance_id */)
// Informs the renderer that the connection request |request_id| failed.
IPC_MESSAGE_CONTROL3(BluetoothMsg_ConnectGATTError,
int /* thread_id */,
int /* request_id */,
content::BluetoothError /* result */)
// Messages sent from the renderer to the browser.
// Requests a bluetooth device from the browser.
......
......@@ -10,16 +10,20 @@
#include "device/bluetooth/bluetooth_uuid.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_discovery_session.h"
#include "device/bluetooth/test/mock_bluetooth_gatt_connection.h"
#include "testing/gmock/include/gmock/gmock.h"
using device::BluetoothAdapter;
using device::BluetoothAdapterFactory;
using device::BluetoothDevice;
using device::BluetoothDiscoverySession;
using device::BluetoothGattConnection;
using device::BluetoothUUID;
using device::MockBluetoothAdapter;
using device::MockBluetoothDevice;
using device::MockBluetoothDiscoverySession;
using device::MockBluetoothGattConnection;
using testing::Between;
using testing::Invoke;
using testing::Return;
using testing::NiceMock;
......@@ -33,6 +37,13 @@ ACTION_TEMPLATE(RunCallback,
return ::testing::get<k>(args).Run();
}
// Invokes Run() on the k-th argument of the function with 1 argument.
ACTION_TEMPLATE(RunCallback,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(p0)) {
return ::testing::get<k>(args).Run(p0);
}
// Invokes Run() on the k-th argument of the function with the result
// of |func| as an argument.
ACTION_TEMPLATE(RunCallbackWithResult,
......@@ -40,6 +51,17 @@ ACTION_TEMPLATE(RunCallbackWithResult,
AND_1_VALUE_PARAMS(func)) {
return ::testing::get<k>(args).Run(func());
}
// Function to iterate over the adapter's devices and return the one
// that matches the address.
ACTION_P(GetMockDevice, adapter) {
std::string address = arg0;
for (BluetoothDevice* device : adapter->GetMockDevices()) {
if (device->GetAddress() == address)
return device;
}
return NULL;
}
}
namespace content {
......@@ -57,6 +79,10 @@ LayoutTestBluetoothAdapterProvider::GetBluetoothAdapter(
else if (fake_adapter_name == "Single Empty Device" ||
fake_adapter_name == "SingleEmptyDeviceAdapter") {
return GetSingleEmptyDeviceAdapter();
} else if (fake_adapter_name == "ConnectableDeviceAdapter") {
return GetConnectableDeviceAdapter();
} else if (fake_adapter_name == "UnconnectableDeviceAdapter") {
return GetUnconnectableDeviceAdapter();
} else if (fake_adapter_name == "") {
return NULL;
}
......@@ -81,6 +107,10 @@ LayoutTestBluetoothAdapterProvider::GetEmptyAdapter() {
.WillByDefault(
Invoke(adapter.get(), &MockBluetoothAdapter::GetConstMockDevices));
// The call to ::GetDevice will invoke GetMockDevice which returns a device
// matching the address provided if the device was added to the mock.
ON_CALL(*adapter, GetDevice(_)).WillByDefault(GetMockDevice(adapter.get()));
return adapter.Pass();
}
......@@ -94,6 +124,38 @@ LayoutTestBluetoothAdapterProvider::GetSingleEmptyDeviceAdapter() {
return adapter.Pass();
}
// static
scoped_refptr<NiceMock<MockBluetoothAdapter>>
LayoutTestBluetoothAdapterProvider::GetConnectableDeviceAdapter() {
scoped_refptr<NiceMock<MockBluetoothAdapter>> adapter(GetEmptyAdapter());
adapter->AddMockDevice(GetConnectableDevice(adapter.get()));
return adapter.Pass();
}
// static
scoped_refptr<NiceMock<MockBluetoothAdapter>>
LayoutTestBluetoothAdapterProvider::GetUnconnectableDeviceAdapter() {
scoped_refptr<NiceMock<MockBluetoothAdapter>> adapter(GetEmptyAdapter());
adapter->AddMockDevice(GetUnconnectableDevice(adapter.get()));
return adapter.Pass();
}
// static
scoped_ptr<NiceMock<MockBluetoothDiscoverySession>>
LayoutTestBluetoothAdapterProvider::GetDiscoverySession() {
scoped_ptr<NiceMock<MockBluetoothDiscoverySession>> discovery_session(
new NiceMock<MockBluetoothDiscoverySession>());
ON_CALL(*discovery_session, Stop(_, _))
.WillByDefault(RunCallback<0 /* success_callback */>());
return discovery_session.Pass();
}
// static
scoped_ptr<NiceMock<MockBluetoothDevice>>
LayoutTestBluetoothAdapterProvider::GetEmptyDevice(
......@@ -118,15 +180,34 @@ LayoutTestBluetoothAdapterProvider::GetEmptyDevice(
}
// static
scoped_ptr<NiceMock<MockBluetoothDiscoverySession>>
LayoutTestBluetoothAdapterProvider::GetDiscoverySession() {
scoped_ptr<NiceMock<MockBluetoothDiscoverySession>> discovery_session(
new NiceMock<MockBluetoothDiscoverySession>());
scoped_ptr<NiceMock<MockBluetoothDevice>>
LayoutTestBluetoothAdapterProvider::GetConnectableDevice(
MockBluetoothAdapter* adapter) {
scoped_ptr<NiceMock<MockBluetoothDevice>> device(GetEmptyDevice(adapter));
ON_CALL(*discovery_session, Stop(_, _))
.WillByDefault(RunCallback<0 /* success_callback */>());
BluetoothDevice* device_ptr = device.get();
return discovery_session.Pass();
ON_CALL(*device, CreateGattConnection(_, _))
.WillByDefault(
RunCallbackWithResult<0 /* success_callback */>([device_ptr]() {
return make_scoped_ptr(new NiceMock<MockBluetoothGattConnection>(
device_ptr->GetAddress()));
}));
return device.Pass();
}
// static
scoped_ptr<NiceMock<MockBluetoothDevice>>
LayoutTestBluetoothAdapterProvider::GetUnconnectableDevice(
MockBluetoothAdapter* adapter) {
scoped_ptr<NiceMock<MockBluetoothDevice>> device(GetEmptyDevice(adapter));
ON_CALL(*device, CreateGattConnection(_, _))
.WillByDefault(
RunCallback<1 /* error_callback */>(BluetoothDevice::ERROR_FAILED));
return device.Pass();
}
} // namespace content
......@@ -38,7 +38,23 @@ class LayoutTestBluetoothAdapterProvider {
static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
GetSingleEmptyDeviceAdapter();
// Returns a fake DiscoverySession with the following characteristics:
// Returns "ConnectableDeviceAdapter" fake BluetoothAdapter with the
// following characteristics:
// - |StartDiscoverySession| runs the first argument with |DiscoverySession|
// as argument.
// - |GetDevices| returns a list with a |ConnectableDevice|.
static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
GetConnectableDeviceAdapter();
// Returns "UnconnectableDeviceAdapter" fake BluetoothAdapter with the
// following characteristics:
// - |StartDiscoverySession| runs the first argument with |DiscoverySession|
// as argument.
// - |GetDevices| returns a list with an |UnconnectableDevice|.
static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
GetUnconnectableDeviceAdapter();
// Returns a fake |DiscoverySession| with the following characteristics:
// - |Stop| runs the first argument.
static scoped_ptr<testing::NiceMock<device::MockBluetoothDiscoverySession>>
GetDiscoverySession();
......@@ -56,6 +72,20 @@ class LayoutTestBluetoothAdapterProvider {
// - |GetUUIDs| returns a list with two UUIDs: "1800" and "1801".
static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>>
GetEmptyDevice(device::MockBluetoothAdapter* adapter);
// Returns a fake |ConnectableDevice| with the same characteristics as
// |EmptyDevice| except:
// - |CreateGattConnection| runs success callback with a
// fake BluetoothGattConnection as argument.
static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>>
GetConnectableDevice(device::MockBluetoothAdapter* adapter);
// Returns a fake |UnconnectableDevice| with the same characteristics as
// |EmptyDevice| except:
// - |CreateGattConnection| runs error callback with
// |BluetoothDevice::ERROR_FAILED| as argument.
static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>>
GetUnconnectableDevice(device::MockBluetoothAdapter* adapter);
};
} // namespace content
......
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