Chromium Code Reviews| 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 |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..fb4231446397fff67da696be55d629fce5afab9e |
| --- /dev/null |
| +++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.cc |
| @@ -0,0 +1,364 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/logging.h" |
| +#include "base/values.h" |
| +#include "chrome/browser/extensions/api/bluetooth/bluetooth_api_utils.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "device/bluetooth/bluetooth_adapter_factory.h" |
| +#include "extensions/browser/event_router.h" |
| + |
| +using content::BrowserThread; |
| + |
| +using device::BluetoothAdapter; |
| +using device::BluetoothAdapterFactory; |
| +using device::BluetoothDevice; |
| +using device::BluetoothGattCharacteristic; |
| +using device::BluetoothGattService; |
| + |
| +namespace apibt = extensions::api::bluetooth; |
| +namespace apibtle = extensions::api::bluetooth_low_energy; |
| + |
| +namespace { |
| + |
| +void PopulateService(const BluetoothGattService* service, |
| + apibtle::Service* out) { |
| + DCHECK(out); |
| + |
| + out->uuid = service->GetUUID().canonical_value(); |
| + out->is_primary = service->IsPrimary(); |
| + out->is_local = service->IsLocal(); |
| + out->instance_id.reset(new std::string(service->GetIdentifier())); |
| + |
| + if (!service->GetDevice()) |
| + return; |
| + |
| + apibt::Device* device = new apibt::Device(); |
| + apibt::BluetoothDeviceToApiDevice(*service->GetDevice(), device); |
|
keybuk
2014/04/24 15:05:20
I'm thinking now that this is overkill, we should
armansito
2014/04/24 20:51:22
Done.
|
| + out->device.reset(device); |
| +} |
| + |
| +} // namespace |
| + |
| +namespace extensions { |
| + |
| +BluetoothLowEnergyEventRouter::BluetoothLowEnergyEventRouter( |
| + content::BrowserContext* context) |
| + : adapter_(NULL), browser_context_(context), weak_ptr_factory_(this) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK(browser_context_); |
| + VLOG(1) << "Initializing BluetoothLowEnergyEventRouter."; |
| + |
| + if (!IsBluetoothSupported()) { |
| + VLOG(1) << "Bluetooth not supported on the current platform."; |
| + return; |
| + } |
| +} |
| + |
| +BluetoothLowEnergyEventRouter::~BluetoothLowEnergyEventRouter() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + if (!adapter_.get()) |
| + return; |
| + |
| + adapter_->RemoveObserver(this); |
| + |
| + for (std::set<std::string>::const_iterator iter = observed_devices_.begin(); |
| + iter != observed_devices_.end(); |
| + ++iter) { |
| + BluetoothDevice* device = adapter_->GetDevice(*iter); |
| + if (!device) |
| + continue; |
| + device->RemoveObserver(this); |
| + } |
| + |
| + for (std::set<std::string>::const_iterator iter = |
| + observed_gatt_services_.begin(); |
| + iter != observed_gatt_services_.end(); |
| + ++iter) { |
| + InstanceIdToObjectDataMap::const_iterator id_iter = |
| + service_ids_to_objects_.find(*iter); |
| + if (id_iter == service_ids_to_objects_.end()) |
| + continue; |
| + |
| + GattObjectData data = id_iter->second; |
| + BluetoothDevice* device = adapter_->GetDevice(data.device_address); |
| + if (!device) |
| + continue; |
| + |
| + BluetoothGattService* service = device->GetGattService(data.service_id); |
| + if (!service) |
| + continue; |
| + |
| + service->RemoveObserver(this); |
| + } |
| + |
| + adapter_ = NULL; |
| +} |
| + |
| +bool BluetoothLowEnergyEventRouter::IsBluetoothSupported() const { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + return adapter_.get() || |
| + BluetoothAdapterFactory::IsBluetoothAdapterAvailable(); |
| +} |
| + |
| +bool BluetoothLowEnergyEventRouter::InitializeAdapterAndInvokeCallback( |
| + const base::Closure& callback) { |
| + if (!IsBluetoothSupported()) |
| + return false; |
| + |
| + if (adapter_.get()) { |
| + callback.Run(); |
| + return true; |
| + } |
| + |
| + BluetoothAdapterFactory::GetAdapter( |
| + base::Bind(&BluetoothLowEnergyEventRouter::OnGetAdapter, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback)); |
| + return true; |
| +} |
| + |
| +bool BluetoothLowEnergyEventRouter::HasAdapter() const { |
| + return adapter_.get(); |
| +} |
| + |
| +base::ListValue* BluetoothLowEnergyEventRouter::GetServices( |
| + const std::string& device_address) const { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + if (!adapter_) { |
| + VLOG(1) << "BluetoothAdapter not ready."; |
| + return NULL; |
| + } |
| + |
| + BluetoothDevice* device = adapter_->GetDevice(device_address); |
| + if (!device) { |
| + VLOG(1) << "Bluetooth device not found: " << device_address; |
| + return NULL; |
| + } |
| + |
| + base::ListValue* service_list = new base::ListValue(); |
|
rpaquay
2014/04/24 20:38:45
You should not have to build the list manually, yo
armansito
2014/04/24 22:02:00
Done.
|
| + |
| + const std::vector<BluetoothGattService*>& services = |
| + device->GetGattServices(); |
| + for (std::vector<BluetoothGattService*>::const_iterator iter = |
| + services.begin(); |
| + iter != services.end(); |
| + ++iter) { |
| + // Populate an API service and add it to the return value. |
| + const BluetoothGattService* service = *iter; |
| + apibtle::Service api_service; |
| + PopulateService(service, &api_service); |
| + service_list->Append(api_service.ToValue().release()); |
| + } |
| + |
| + return service_list; |
| +} |
| + |
| +bool BluetoothLowEnergyEventRouter::GetService( |
| + const std::string& instance_id, |
| + apibtle::Service* service) const { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + if (!adapter_) { |
| + VLOG(1) << "BluetoothAdapter not ready."; |
| + return false; |
| + } |
| + |
| + BluetoothGattService* gatt_service = FindServiceById(instance_id); |
| + if (!gatt_service) { |
| + VLOG(1) << "Service not found: " << instance_id; |
| + return false; |
| + } |
| + |
| + PopulateService(gatt_service, service); |
| + return true; |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::SetAdapterForTesting( |
| + device::BluetoothAdapter* adapter) { |
| + adapter_ = adapter; |
| + InitializeIdentifierMappings(); |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::DeviceAdded(BluetoothAdapter* adapter, |
| + BluetoothDevice* device) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK(observed_devices_.find(device->GetAddress()) == |
| + observed_devices_.end()); |
| + device->AddObserver(this); |
| + observed_devices_.insert(device->GetAddress()); |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::DeviceRemoved(BluetoothAdapter* adapter, |
| + BluetoothDevice* device) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK(observed_devices_.find(device->GetAddress()) != |
| + observed_devices_.end()); |
| + device->RemoveObserver(this); |
| + observed_devices_.erase(device->GetAddress()); |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::GattServiceAdded( |
| + BluetoothDevice* device, |
| + BluetoothGattService* service) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + VLOG(2) << "GATT service added: " << service->GetIdentifier(); |
| + |
| + DCHECK(observed_gatt_services_.find(service->GetIdentifier()) == |
| + observed_gatt_services_.end()); |
| + DCHECK(service_ids_to_objects_.find(service->GetIdentifier()) == |
| + service_ids_to_objects_.end()); |
| + |
| + service->AddObserver(this); |
| + observed_gatt_services_.insert(service->GetIdentifier()); |
| + |
| + GattObjectData data; |
| + data.device_address = device->GetAddress(); |
| + data.service_id = service->GetIdentifier(); |
| + service_ids_to_objects_[data.service_id] = data; |
| + |
| + // Signal API event. |
| + apibtle::Service api_service; |
| + PopulateService(service, &api_service); |
| + |
| + scoped_ptr<base::ListValue> args = |
| + apibtle::OnServiceAdded::Create(api_service); |
| + scoped_ptr<Event> event( |
| + new Event(apibtle::OnServiceAdded::kEventName, args.Pass())); |
| + EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::GattServiceRemoved( |
| + BluetoothDevice* device, |
| + BluetoothGattService* service) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + VLOG(2) << "GATT service removed: " << service->GetIdentifier(); |
| + |
| + DCHECK(observed_gatt_services_.find(service->GetIdentifier()) != |
| + observed_gatt_services_.end()); |
| + DCHECK(service_ids_to_objects_.find(service->GetIdentifier()) != |
| + service_ids_to_objects_.end()); |
| + |
| + service->RemoveObserver(this); |
| + observed_gatt_services_.erase(service->GetIdentifier()); |
| + |
| + DCHECK(device->GetAddress() == |
| + service_ids_to_objects_[service->GetIdentifier()].device_address); |
| + service_ids_to_objects_.erase(service->GetIdentifier()); |
| + |
| + // Signal API event. |
| + apibtle::Service api_service; |
| + PopulateService(service, &api_service); |
| + |
| + scoped_ptr<base::ListValue> args = |
| + apibtle::OnServiceRemoved::Create(api_service); |
| + scoped_ptr<Event> event( |
| + new Event(apibtle::OnServiceRemoved::kEventName, args.Pass())); |
| + EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::GattServiceChanged( |
| + BluetoothGattService* service) { |
| + // TODO |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::GattCharacteristicAdded( |
| + BluetoothGattService* service, |
| + BluetoothGattCharacteristic* characteristic) { |
| + // TODO(armansito): Implement. |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::GattCharacteristicRemoved( |
| + BluetoothGattService* service, |
| + BluetoothGattCharacteristic* characteristic) { |
| + // TODO(armansito): Implement. |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::GattCharacteristicValueChanged( |
| + BluetoothGattService* service, |
| + BluetoothGattCharacteristic* characteristic, |
| + const std::vector<uint8>& value) { |
| + // TODO(armansito): Implement. |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::OnGetAdapter( |
| + const base::Closure& callback, |
| + scoped_refptr<device::BluetoothAdapter> adapter) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK(service_ids_to_objects_.empty()); |
| + DCHECK(observed_devices_.empty()); |
| + DCHECK(observed_gatt_services_.empty()); |
| + |
| + // TODO: Observe adapter and all devices. |
| + adapter_ = adapter; |
| + |
| + // Initialize instance ID mappings for all discovered GATT objects and add |
| + // observers. |
| + InitializeIdentifierMappings(); |
| + adapter_->AddObserver(this); |
| + |
| + callback.Run(); |
| +} |
| + |
| +void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() { |
| + BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); |
| + for (BluetoothAdapter::DeviceList::iterator iter = devices.begin(); |
| + iter != devices.end(); |
| + ++iter) { |
| + BluetoothDevice* device = *iter; |
| + device->AddObserver(this); |
| + observed_devices_.insert(device->GetAddress()); |
| + |
| + std::vector<BluetoothGattService*> services = device->GetGattServices(); |
| + for (std::vector<BluetoothGattService*>::iterator siter = services.begin(); |
| + siter != services.end(); |
| + ++siter) { |
| + BluetoothGattService* service = *siter; |
| + service->AddObserver(this); |
| + observed_gatt_services_.insert(service->GetIdentifier()); |
| + |
| + GattObjectData service_data; |
| + service_data.device_address = device->GetAddress(); |
| + service_data.service_id = service->GetIdentifier(); |
| + service_ids_to_objects_[service_data.service_id] = service_data; |
| + |
| + // TODO(armansito): Initialize mapping for characteristics & descriptors. |
| + } |
| + } |
| +} |
| + |
| +BluetoothGattService* BluetoothLowEnergyEventRouter::FindServiceById( |
| + const std::string& instance_id) const { |
| + InstanceIdToObjectDataMap::const_iterator iter = |
| + service_ids_to_objects_.find(instance_id); |
| + if (iter == service_ids_to_objects_.end()) { |
| + VLOG(1) << "GATT service identifier unknown: " << instance_id; |
| + return NULL; |
| + } |
| + |
| + GattObjectData data = iter->second; |
| + DCHECK(!data.device_address.empty()); |
| + DCHECK(!data.service_id.empty()); |
| + DCHECK(data.characteristic_id.empty()); |
| + DCHECK(data.descriptor_id.empty()); |
| + |
| + BluetoothDevice* device = adapter_->GetDevice(data.device_address); |
| + if (!device) { |
| + VLOG(1) << "Bluetooth device not found: " << data.device_address; |
| + return NULL; |
| + } |
| + |
| + BluetoothGattService* service = device->GetGattService(data.service_id); |
| + if (!service) { |
| + VLOG(1) << "GATT service with ID \"" << data.service_id |
| + << "\" not found on device \"" << data.device_address << "\""; |
| + return NULL; |
| + } |
| + |
| + return service; |
| +} |
| + |
| +} // namespace extensions |