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( ...@@ -100,10 +100,27 @@ void BluetoothDispatcherHost::OnConnectGATT(
int request_id, int request_id,
const std::string& device_instance_id) { const std::string& device_instance_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
// TODO(ortuno): Add actual implementation of connectGATT. This needs to be // TODO(ortuno): Right now it's pointless to check if the domain has access to
// done after the "allowed devices map" is implemented. // the device, because any domain can connect to any device. But once
Send(new BluetoothMsg_ConnectGATTSuccess(thread_id, request_id, // permissions are implemented we should check that the domain has access to
device_instance_id)); // 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( void BluetoothDispatcherHost::OnDiscoverySessionStarted(
...@@ -172,4 +189,27 @@ void BluetoothDispatcherHost::OnDiscoverySessionStoppedError(int thread_id, ...@@ -172,4 +189,27 @@ void BluetoothDispatcherHost::OnDiscoverySessionStoppedError(int thread_id,
BluetoothError::NOT_FOUND)); 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 } // namespace content
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "content/common/bluetooth/bluetooth_error.h" #include "content/common/bluetooth/bluetooth_error.h"
#include "content/public/browser/browser_message_filter.h" #include "content/public/browser/browser_message_filter.h"
#include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_gatt_connection.h"
namespace content { namespace content {
...@@ -70,6 +71,18 @@ class CONTENT_EXPORT BluetoothDispatcherHost final ...@@ -70,6 +71,18 @@ class CONTENT_EXPORT BluetoothDispatcherHost final
void OnDiscoverySessionStopped(int thread_id, int request_id); void OnDiscoverySessionStopped(int thread_id, int request_id);
void OnDiscoverySessionStoppedError(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. // Defines how long to scan for.
int current_scan_time_; int current_scan_time_;
......
...@@ -101,6 +101,7 @@ void BluetoothDispatcher::OnMessageReceived(const IPC::Message& msg) { ...@@ -101,6 +101,7 @@ void BluetoothDispatcher::OnMessageReceived(const IPC::Message& msg) {
OnRequestDeviceSuccess); OnRequestDeviceSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceError, OnRequestDeviceError); IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceError, OnRequestDeviceError);
IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTSuccess, OnConnectGATTSuccess); IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTSuccess, OnConnectGATTSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTError, OnConnectGATTError);
IPC_MESSAGE_UNHANDLED(handled = false) IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP() IPC_END_MESSAGE_MAP()
DCHECK(handled) << "Unhandled message:" << msg.type(); DCHECK(handled) << "Unhandled message:" << msg.type();
...@@ -143,6 +144,18 @@ void BluetoothDispatcher::OnRequestDeviceSuccess( ...@@ -143,6 +144,18 @@ void BluetoothDispatcher::OnRequestDeviceSuccess(
pending_requests_.Remove(request_id); 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( void BluetoothDispatcher::OnConnectGATTSuccess(
int thread_id, int thread_id,
int request_id, int request_id,
...@@ -154,14 +167,16 @@ void BluetoothDispatcher::OnConnectGATTSuccess( ...@@ -154,14 +167,16 @@ void BluetoothDispatcher::OnConnectGATTSuccess(
pending_connect_requests_.Remove(request_id); pending_connect_requests_.Remove(request_id);
} }
void BluetoothDispatcher::OnRequestDeviceError(int thread_id, void BluetoothDispatcher::OnConnectGATTError(int thread_id,
int request_id, int request_id,
BluetoothError error_type) { BluetoothError error_type) {
DCHECK(pending_requests_.Lookup(request_id)) << request_id; DCHECK(pending_connect_requests_.Lookup(request_id)) << request_id;
pending_requests_.Lookup(request_id) pending_connect_requests_.Lookup(request_id)
->onError(new WebBluetoothError( ->onError(new WebBluetoothError(
// TODO(ortuno): Return more descriptive error messages.
// http://crbug.com/490419
WebBluetoothErrorFromBluetoothError(error_type), "")); WebBluetoothErrorFromBluetoothError(error_type), ""));
pending_requests_.Remove(request_id); pending_connect_requests_.Remove(request_id);
} }
} // namespace content } // namespace content
...@@ -67,6 +67,10 @@ class BluetoothDispatcher : public WorkerTaskRunner::Observer { ...@@ -67,6 +67,10 @@ class BluetoothDispatcher : public WorkerTaskRunner::Observer {
int request_id, int request_id,
const std::string& message); const std::string& message);
void OnConnectGATTError(int thread_id,
int request_id,
BluetoothError error_type);
scoped_refptr<ThreadSafeSender> thread_safe_sender_; scoped_refptr<ThreadSafeSender> thread_safe_sender_;
// Tracks device requests sent to browser to match replies with callbacks. // Tracks device requests sent to browser to match replies with callbacks.
......
...@@ -123,6 +123,12 @@ IPC_MESSAGE_CONTROL3(BluetoothMsg_ConnectGATTSuccess, ...@@ -123,6 +123,12 @@ IPC_MESSAGE_CONTROL3(BluetoothMsg_ConnectGATTSuccess,
int /* request_id */, int /* request_id */,
std::string /* device_instance_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. // Messages sent from the renderer to the browser.
// Requests a bluetooth device from the browser. // Requests a bluetooth device from the browser.
......
...@@ -10,16 +10,20 @@ ...@@ -10,16 +10,20 @@
#include "device/bluetooth/bluetooth_uuid.h" #include "device/bluetooth/bluetooth_uuid.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_discovery_session.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" #include "testing/gmock/include/gmock/gmock.h"
using device::BluetoothAdapter; using device::BluetoothAdapter;
using device::BluetoothAdapterFactory; using device::BluetoothAdapterFactory;
using device::BluetoothDevice; using device::BluetoothDevice;
using device::BluetoothDiscoverySession; using device::BluetoothDiscoverySession;
using device::BluetoothGattConnection;
using device::BluetoothUUID; using device::BluetoothUUID;
using device::MockBluetoothAdapter; using device::MockBluetoothAdapter;
using device::MockBluetoothDevice; using device::MockBluetoothDevice;
using device::MockBluetoothDiscoverySession; using device::MockBluetoothDiscoverySession;
using device::MockBluetoothGattConnection;
using testing::Between;
using testing::Invoke; using testing::Invoke;
using testing::Return; using testing::Return;
using testing::NiceMock; using testing::NiceMock;
...@@ -33,6 +37,13 @@ ACTION_TEMPLATE(RunCallback, ...@@ -33,6 +37,13 @@ ACTION_TEMPLATE(RunCallback,
return ::testing::get<k>(args).Run(); 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 // Invokes Run() on the k-th argument of the function with the result
// of |func| as an argument. // of |func| as an argument.
ACTION_TEMPLATE(RunCallbackWithResult, ACTION_TEMPLATE(RunCallbackWithResult,
...@@ -40,6 +51,17 @@ ACTION_TEMPLATE(RunCallbackWithResult, ...@@ -40,6 +51,17 @@ ACTION_TEMPLATE(RunCallbackWithResult,
AND_1_VALUE_PARAMS(func)) { AND_1_VALUE_PARAMS(func)) {
return ::testing::get<k>(args).Run(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 { namespace content {
...@@ -57,6 +79,10 @@ LayoutTestBluetoothAdapterProvider::GetBluetoothAdapter( ...@@ -57,6 +79,10 @@ LayoutTestBluetoothAdapterProvider::GetBluetoothAdapter(
else if (fake_adapter_name == "Single Empty Device" || else if (fake_adapter_name == "Single Empty Device" ||
fake_adapter_name == "SingleEmptyDeviceAdapter") { fake_adapter_name == "SingleEmptyDeviceAdapter") {
return GetSingleEmptyDeviceAdapter(); return GetSingleEmptyDeviceAdapter();
} else if (fake_adapter_name == "ConnectableDeviceAdapter") {
return GetConnectableDeviceAdapter();
} else if (fake_adapter_name == "UnconnectableDeviceAdapter") {
return GetUnconnectableDeviceAdapter();
} else if (fake_adapter_name == "") { } else if (fake_adapter_name == "") {
return NULL; return NULL;
} }
...@@ -81,6 +107,10 @@ LayoutTestBluetoothAdapterProvider::GetEmptyAdapter() { ...@@ -81,6 +107,10 @@ LayoutTestBluetoothAdapterProvider::GetEmptyAdapter() {
.WillByDefault( .WillByDefault(
Invoke(adapter.get(), &MockBluetoothAdapter::GetConstMockDevices)); 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(); return adapter.Pass();
} }
...@@ -94,6 +124,38 @@ LayoutTestBluetoothAdapterProvider::GetSingleEmptyDeviceAdapter() { ...@@ -94,6 +124,38 @@ LayoutTestBluetoothAdapterProvider::GetSingleEmptyDeviceAdapter() {
return adapter.Pass(); 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 // static
scoped_ptr<NiceMock<MockBluetoothDevice>> scoped_ptr<NiceMock<MockBluetoothDevice>>
LayoutTestBluetoothAdapterProvider::GetEmptyDevice( LayoutTestBluetoothAdapterProvider::GetEmptyDevice(
...@@ -118,15 +180,34 @@ LayoutTestBluetoothAdapterProvider::GetEmptyDevice( ...@@ -118,15 +180,34 @@ LayoutTestBluetoothAdapterProvider::GetEmptyDevice(
} }
// static // static
scoped_ptr<NiceMock<MockBluetoothDiscoverySession>> scoped_ptr<NiceMock<MockBluetoothDevice>>
LayoutTestBluetoothAdapterProvider::GetDiscoverySession() { LayoutTestBluetoothAdapterProvider::GetConnectableDevice(
scoped_ptr<NiceMock<MockBluetoothDiscoverySession>> discovery_session( MockBluetoothAdapter* adapter) {
new NiceMock<MockBluetoothDiscoverySession>()); scoped_ptr<NiceMock<MockBluetoothDevice>> device(GetEmptyDevice(adapter));
ON_CALL(*discovery_session, Stop(_, _)) BluetoothDevice* device_ptr = device.get();
.WillByDefault(RunCallback<0 /* success_callback */>());
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 } // namespace content
...@@ -38,7 +38,23 @@ class LayoutTestBluetoothAdapterProvider { ...@@ -38,7 +38,23 @@ class LayoutTestBluetoothAdapterProvider {
static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
GetSingleEmptyDeviceAdapter(); 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. // - |Stop| runs the first argument.
static scoped_ptr<testing::NiceMock<device::MockBluetoothDiscoverySession>> static scoped_ptr<testing::NiceMock<device::MockBluetoothDiscoverySession>>
GetDiscoverySession(); GetDiscoverySession();
...@@ -56,6 +72,20 @@ class LayoutTestBluetoothAdapterProvider { ...@@ -56,6 +72,20 @@ class LayoutTestBluetoothAdapterProvider {
// - |GetUUIDs| returns a list with two UUIDs: "1800" and "1801". // - |GetUUIDs| returns a list with two UUIDs: "1800" and "1801".
static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>> static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>>
GetEmptyDevice(device::MockBluetoothAdapter* adapter); 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 } // 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