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 |