| Index: chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
|
| diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
|
| index 9e2761ece155b53db7bb6a730aaf1cd018b60865..b419e276453cd03824ee9d0b2ac58f8d1bc2e213 100644
|
| --- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
|
| +++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc
|
| @@ -7,11 +7,13 @@
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| #include "base/values.h"
|
| +#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.h"
|
| #include "chrome/browser/extensions/api/bluetooth_low_energy/utils.h"
|
| #include "chrome/common/extensions/api/bluetooth/bluetooth_manifest_data.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "device/bluetooth/bluetooth_adapter_factory.h"
|
| #include "device/bluetooth/bluetooth_gatt_characteristic.h"
|
| +#include "device/bluetooth/bluetooth_gatt_connection.h"
|
| #include "device/bluetooth/bluetooth_gatt_descriptor.h"
|
| #include "extensions/browser/event_router.h"
|
| #include "extensions/browser/extension_registry.h"
|
| @@ -22,6 +24,7 @@ using device::BluetoothAdapter;
|
| using device::BluetoothAdapterFactory;
|
| using device::BluetoothDevice;
|
| using device::BluetoothGattCharacteristic;
|
| +using device::BluetoothGattConnection;
|
| using device::BluetoothGattDescriptor;
|
| using device::BluetoothGattService;
|
|
|
| @@ -120,6 +123,19 @@ void PopulateDescriptor(const BluetoothGattDescriptor* descriptor,
|
| out->value.reset(new std::string(value.begin(), value.end()));
|
| }
|
|
|
| +typedef extensions::ApiResourceManager<extensions::BluetoothLowEnergyConnection>
|
| + ConnectionResourceManager;
|
| +ConnectionResourceManager* GetConnectionResourceManager(
|
| + content::BrowserContext* context) {
|
| + ConnectionResourceManager* manager = ConnectionResourceManager::Get(context);
|
| + DCHECK(manager)
|
| + << "There is no Bluetooth low energy connection manager. "
|
| + "If this assertion is failing during a test, then it is likely that "
|
| + "TestExtensionSystem is failing to provide an instance of "
|
| + "ApiResourceManager<BluetoothLowEnergyConnection>.";
|
| + return manager;
|
| +}
|
| +
|
| } // namespace
|
|
|
| namespace extensions {
|
| @@ -193,6 +209,86 @@ bool BluetoothLowEnergyEventRouter::HasAdapter() const {
|
| return (adapter_.get() != NULL);
|
| }
|
|
|
| +BluetoothLowEnergyEventRouter::Status BluetoothLowEnergyEventRouter::Connect(
|
| + const Extension* extension,
|
| + const std::string& device_address,
|
| + const base::Closure& callback,
|
| + const ErrorCallback& error_callback) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + if (!adapter_) {
|
| + VLOG(1) << "BluetoothAdapter not ready.";
|
| + return kStatusErrorFailed;
|
| + }
|
| +
|
| + if (connecting_devices_.count(device_address) != 0)
|
| + return kStatusErrorInProgress;
|
| +
|
| + const std::string extension_id = extension->id();
|
| + BluetoothLowEnergyConnection* conn =
|
| + FindConnection(extension_id, device_address);
|
| + if (conn) {
|
| + if (conn->GetConnection()->IsConnected()) {
|
| + VLOG(1) << "Application already connected to device: " << device_address;
|
| + return kStatusErrorAlreadyConnected;
|
| + }
|
| +
|
| + // There is a connection object but it's no longer active. Simply remove it.
|
| + RemoveConnection(extension_id, device_address);
|
| + }
|
| +
|
| + BluetoothDevice* device = adapter_->GetDevice(device_address);
|
| + if (!device) {
|
| + VLOG(1) << "Bluetooth device not found: " << device_address;
|
| + return kStatusErrorNotFound;
|
| + }
|
| +
|
| + connecting_devices_.insert(device_address);
|
| + device->CreateGattConnection(
|
| + base::Bind(&BluetoothLowEnergyEventRouter::OnCreateGattConnection,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + extension_id,
|
| + device_address,
|
| + callback),
|
| + base::Bind(&BluetoothLowEnergyEventRouter::OnConnectError,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + device_address,
|
| + error_callback));
|
| +
|
| + return kStatusSuccess;
|
| +}
|
| +
|
| +BluetoothLowEnergyEventRouter::Status BluetoothLowEnergyEventRouter::Disconnect(
|
| + const Extension* extension,
|
| + const std::string& device_address,
|
| + const base::Closure& callback) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| + if (!adapter_) {
|
| + VLOG(1) << "BluetoothAdapter not ready.";
|
| + return kStatusErrorFailed;
|
| + }
|
| +
|
| + if (disconnecting_devices_.count(device_address) != 0)
|
| + return kStatusErrorInProgress;
|
| +
|
| + const std::string& extension_id = extension->id();
|
| + BluetoothLowEnergyConnection* conn =
|
| + FindConnection(extension_id, device_address);
|
| + if (!conn || !conn->GetConnection()->IsConnected()) {
|
| + VLOG(1) << "Application not connected to device: " << device_address;
|
| + return kStatusErrorNotConnected;
|
| + }
|
| +
|
| + disconnecting_devices_.insert(device_address);
|
| + conn->GetConnection()->Disconnect(
|
| + base::Bind(&BluetoothLowEnergyEventRouter::OnDisconnect,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + extension_id,
|
| + device_address,
|
| + callback));
|
| +
|
| + return kStatusSuccess;
|
| +}
|
| +
|
| bool BluetoothLowEnergyEventRouter::GetServices(
|
| const std::string& device_address,
|
| ServiceList* out_services) const {
|
| @@ -1007,10 +1103,107 @@ void BluetoothLowEnergyEventRouter::OnValueSuccess(
|
| callback.Run();
|
| }
|
|
|
| +void BluetoothLowEnergyEventRouter::OnCreateGattConnection(
|
| + const std::string& extension_id,
|
| + const std::string& device_address,
|
| + const base::Closure& callback,
|
| + scoped_ptr<BluetoothGattConnection> connection) {
|
| + VLOG(2) << "GATT connection created.";
|
| + DCHECK(connection.get());
|
| + DCHECK(!FindConnection(extension_id, device_address));
|
| + DCHECK_EQ(device_address, connection->GetDeviceAddress());
|
| + DCHECK_NE(0U, connecting_devices_.count(device_address));
|
| +
|
| + BluetoothLowEnergyConnection* conn =
|
| + new BluetoothLowEnergyConnection(extension_id, connection.Pass());
|
| + ConnectionResourceManager* manager =
|
| + GetConnectionResourceManager(browser_context_);
|
| + manager->Add(conn);
|
| +
|
| + connecting_devices_.erase(device_address);
|
| + callback.Run();
|
| +}
|
| +
|
| +void BluetoothLowEnergyEventRouter::OnDisconnect(
|
| + const std::string& extension_id,
|
| + const std::string& device_address,
|
| + const base::Closure& callback) {
|
| + VLOG(2) << "GATT connection terminated.";
|
| + DCHECK_NE(0U, disconnecting_devices_.count(device_address));
|
| + if (!RemoveConnection(extension_id, device_address)) {
|
| + VLOG(1) << "The connection was removed before disconnect completed, id: "
|
| + << extension_id << ", device: " << device_address;
|
| + }
|
| +
|
| + disconnecting_devices_.erase(device_address);
|
| + callback.Run();
|
| +}
|
| +
|
| void BluetoothLowEnergyEventRouter::OnError(
|
| const ErrorCallback& error_callback) {
|
| VLOG(2) << "Remote characteristic/descriptor value read/write failed.";
|
| error_callback.Run(kStatusErrorFailed);
|
| }
|
|
|
| +void BluetoothLowEnergyEventRouter::OnConnectError(
|
| + const std::string& device_address,
|
| + const ErrorCallback& error_callback,
|
| + BluetoothDevice::ConnectErrorCode error_code) {
|
| + VLOG(2) << "Failed to create GATT connection: " << error_code;
|
| + DCHECK_NE(0U, connecting_devices_.count(device_address));
|
| +
|
| + connecting_devices_.erase(device_address);
|
| + error_callback.Run(kStatusErrorFailed);
|
| +}
|
| +
|
| +BluetoothLowEnergyConnection* BluetoothLowEnergyEventRouter::FindConnection(
|
| + const std::string& extension_id,
|
| + const std::string& device_address) {
|
| + ConnectionResourceManager* manager =
|
| + GetConnectionResourceManager(browser_context_);
|
| +
|
| + base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
|
| + if (!connection_ids)
|
| + return NULL;
|
| +
|
| + for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
|
| + iter != connection_ids->end();
|
| + ++iter) {
|
| + extensions::BluetoothLowEnergyConnection* conn =
|
| + manager->Get(extension_id, *iter);
|
| + if (!conn)
|
| + continue;
|
| +
|
| + if (conn->GetConnection()->GetDeviceAddress() == device_address)
|
| + return conn;
|
| + }
|
| +
|
| + return NULL;
|
| +}
|
| +
|
| +bool BluetoothLowEnergyEventRouter::RemoveConnection(
|
| + const std::string& extension_id,
|
| + const std::string& device_address) {
|
| + ConnectionResourceManager* manager =
|
| + GetConnectionResourceManager(browser_context_);
|
| +
|
| + base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
|
| + if (!connection_ids)
|
| + return false;
|
| +
|
| + for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
|
| + iter != connection_ids->end();
|
| + ++iter) {
|
| + extensions::BluetoothLowEnergyConnection* conn =
|
| + manager->Get(extension_id, *iter);
|
| + if (!conn || conn->GetConnection()->GetDeviceAddress() != device_address)
|
| + continue;
|
| +
|
| + manager->Remove(extension_id, *iter);
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| } // namespace extensions
|
|
|