blob: 947d84e880ff37f30bd487f5831470455fb6f001 [file] [log] [blame]
// 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_low_energy/utils.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_descriptor.h"
#include "extensions/browser/event_router.h"
using content::BrowserThread;
using device::BluetoothAdapter;
using device::BluetoothAdapterFactory;
using device::BluetoothDevice;
using device::BluetoothGattCharacteristic;
using device::BluetoothGattDescriptor;
using device::BluetoothGattService;
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;
out->device_address.reset(
new std::string(service->GetDevice()->GetAddress()));
}
void PopulateCharacteristicProperties(
BluetoothGattCharacteristic::Properties properties,
std::vector<apibtle::CharacteristicProperty>* api_properties) {
DCHECK(api_properties && api_properties->empty());
if (properties == BluetoothGattCharacteristic::kPropertyNone)
return;
if (properties & BluetoothGattCharacteristic::kPropertyBroadcast)
api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_BROADCAST);
if (properties & BluetoothGattCharacteristic::kPropertyRead)
api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_READ);
if (properties & BluetoothGattCharacteristic::kPropertyWriteWithoutResponse) {
api_properties->push_back(
apibtle::CHARACTERISTIC_PROPERTY_WRITEWITHOUTRESPONSE);
}
if (properties & BluetoothGattCharacteristic::kPropertyWrite)
api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_WRITE);
if (properties & BluetoothGattCharacteristic::kPropertyNotify)
api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_NOTIFY);
if (properties & BluetoothGattCharacteristic::kPropertyIndicate)
api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_INDICATE);
if (properties &
BluetoothGattCharacteristic::kPropertyAuthenticatedSignedWrites) {
api_properties->push_back(
apibtle::CHARACTERISTIC_PROPERTY_AUTHENTICATEDSIGNEDWRITES);
}
if (properties & BluetoothGattCharacteristic::kPropertyExtendedProperties) {
api_properties->push_back(
apibtle::CHARACTERISTIC_PROPERTY_EXTENDEDPROPERTIES);
}
if (properties & BluetoothGattCharacteristic::kPropertyReliableWrite)
api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_RELIABLEWRITE);
if (properties & BluetoothGattCharacteristic::kPropertyWriteableAuxiliaries) {
api_properties->push_back(
apibtle::CHARACTERISTIC_PROPERTY_WRITEABLEAUXILIARIES);
}
}
void PopulateCharacteristic(const BluetoothGattCharacteristic* characteristic,
apibtle::Characteristic* out) {
DCHECK(out);
out->uuid = characteristic->GetUUID().canonical_value();
out->is_local = characteristic->IsLocal();
out->instance_id.reset(new std::string(characteristic->GetIdentifier()));
PopulateService(characteristic->GetService(), &out->service);
PopulateCharacteristicProperties(characteristic->GetProperties(),
&out->properties);
const std::vector<uint8>& value = characteristic->GetValue();
if (value.empty())
return;
out->value.reset(new std::string(value.begin(), value.end()));
}
void PopulateDescriptor(const BluetoothGattDescriptor* descriptor,
apibtle::Descriptor* out) {
DCHECK(out);
out->uuid = descriptor->GetUUID().canonical_value();
out->is_local = descriptor->IsLocal();
out->instance_id.reset(new std::string(descriptor->GetIdentifier()));
PopulateCharacteristic(descriptor->GetCharacteristic(), &out->characteristic);
const std::vector<uint8>& value = descriptor->GetValue();
if (value.empty())
return;
out->value.reset(new std::string(value.begin(), value.end()));
}
} // 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) {
BluetoothGattService* service = FindServiceById(*iter);
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() != NULL);
}
bool BluetoothLowEnergyEventRouter::GetServices(
const std::string& device_address,
ServiceList* out_services) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(out_services);
if (!adapter_) {
VLOG(1) << "BluetoothAdapter not ready.";
return false;
}
BluetoothDevice* device = adapter_->GetDevice(device_address);
if (!device) {
VLOG(1) << "Bluetooth device not found: " << device_address;
return false;
}
out_services->clear();
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;
linked_ptr<apibtle::Service> api_service(new apibtle::Service());
PopulateService(service, api_service.get());
out_services->push_back(api_service);
}
return true;
}
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;
}
bool BluetoothLowEnergyEventRouter::GetIncludedServices(
const std::string& instance_id,
ServiceList* out_services) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(out_services);
if (!adapter_) {
VLOG(1) << "BluetoothAdapter not ready.";
return false;
}
BluetoothGattService* service = FindServiceById(instance_id);
if (!service) {
VLOG(1) << "Service not found: " << instance_id;
return false;
}
out_services->clear();
const std::vector<BluetoothGattService*>& includes =
service->GetIncludedServices();
for (std::vector<BluetoothGattService*>::const_iterator iter =
includes.begin();
iter != includes.end();
++iter) {
// Populate an API service and add it to the return value.
const BluetoothGattService* included = *iter;
linked_ptr<apibtle::Service> api_service(new apibtle::Service());
PopulateService(included, api_service.get());
out_services->push_back(api_service);
}
return true;
}
bool BluetoothLowEnergyEventRouter::GetCharacteristics(
const std::string& instance_id,
CharacteristicList* out_characteristics) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(out_characteristics);
if (!adapter_) {
VLOG(1) << "BlutoothAdapter not ready.";
return false;
}
BluetoothGattService* service = FindServiceById(instance_id);
if (!service) {
VLOG(1) << "Service not found: " << instance_id;
return false;
}
out_characteristics->clear();
const std::vector<BluetoothGattCharacteristic*>& characteristics =
service->GetCharacteristics();
for (std::vector<BluetoothGattCharacteristic*>::const_iterator iter =
characteristics.begin();
iter != characteristics.end();
++iter) {
// Populate an API characteristic and add it to the return value.
const BluetoothGattCharacteristic* characteristic = *iter;
linked_ptr<apibtle::Characteristic> api_characteristic(
new apibtle::Characteristic());
PopulateCharacteristic(characteristic, api_characteristic.get());
out_characteristics->push_back(api_characteristic);
}
return true;
}
bool BluetoothLowEnergyEventRouter::GetCharacteristic(
const std::string& instance_id,
apibtle::Characteristic* out_characteristic) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(out_characteristic);
if (!adapter_) {
VLOG(1) << "BluetoothAdapter not ready.";
return false;
}
BluetoothGattCharacteristic* characteristic =
FindCharacteristicById(instance_id);
if (!characteristic) {
VLOG(1) << "Characteristic not found: " << instance_id;
return false;
}
PopulateCharacteristic(characteristic, out_characteristic);
return true;
}
bool BluetoothLowEnergyEventRouter::GetDescriptors(
const std::string& instance_id,
DescriptorList* out_descriptors) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(out_descriptors);
if (!adapter_) {
VLOG(1) << "BlutoothAdapter not ready.";
return false;
}
BluetoothGattCharacteristic* characteristic =
FindCharacteristicById(instance_id);
if (!characteristic) {
VLOG(1) << "Characteristic not found: " << instance_id;
return false;
}
out_descriptors->clear();
const std::vector<BluetoothGattDescriptor*>& descriptors =
characteristic->GetDescriptors();
for (std::vector<BluetoothGattDescriptor*>::const_iterator iter =
descriptors.begin();
iter != descriptors.end();
++iter) {
// Populate an API descriptor and add it to the return value.
const BluetoothGattDescriptor* descriptor = *iter;
linked_ptr<apibtle::Descriptor> api_descriptor(new apibtle::Descriptor());
PopulateDescriptor(descriptor, api_descriptor.get());
out_descriptors->push_back(api_descriptor);
}
return true;
}
bool BluetoothLowEnergyEventRouter::GetDescriptor(
const std::string& instance_id,
api::bluetooth_low_energy::Descriptor* out_descriptor) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(out_descriptor);
if (!adapter_) {
VLOG(1) << "BluetoothAdapter not ready.";
return false;
}
BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
if (!descriptor) {
VLOG(1) << "Descriptor not found: " << instance_id;
return false;
}
PopulateDescriptor(descriptor, out_descriptor);
return true;
}
bool BluetoothLowEnergyEventRouter::ReadCharacteristicValue(
const std::string& instance_id,
const base::Closure& callback,
const base::Closure& error_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!adapter_) {
VLOG(1) << "BluetoothAdapter not ready.";
return false;
}
BluetoothGattCharacteristic* characteristic =
FindCharacteristicById(instance_id);
if (!characteristic) {
VLOG(1) << "Characteristic not found: " << instance_id;
return false;
}
characteristic->ReadRemoteCharacteristic(
base::Bind(&BluetoothLowEnergyEventRouter::ValueCallback,
weak_ptr_factory_.GetWeakPtr(),
callback),
error_callback);
return true;
}
bool BluetoothLowEnergyEventRouter::WriteCharacteristicValue(
const std::string& instance_id,
const std::vector<uint8>& value,
const base::Closure& callback,
const base::Closure& error_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!adapter_) {
VLOG(1) << "BluetoothAdapter not ready.";
return false;
}
BluetoothGattCharacteristic* characteristic =
FindCharacteristicById(instance_id);
if (!characteristic) {
VLOG(1) << "Characteristic not found: " << instance_id;
return false;
}
characteristic->WriteRemoteCharacteristic(value, callback, error_callback);
return true;
}
bool BluetoothLowEnergyEventRouter::ReadDescriptorValue(
const std::string& instance_id,
const base::Closure& callback,
const base::Closure& error_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!adapter_) {
VLOG(1) << "BluetoothAdapter not ready.";
return false;
}
BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
if (!descriptor) {
VLOG(1) << "Descriptor not found: " << instance_id;
return false;
}
descriptor->ReadRemoteDescriptor(
base::Bind(&BluetoothLowEnergyEventRouter::ValueCallback,
weak_ptr_factory_.GetWeakPtr(),
callback),
error_callback);
return true;
}
bool BluetoothLowEnergyEventRouter::WriteDescriptorValue(
const std::string& instance_id,
const std::vector<uint8>& value,
const base::Closure& callback,
const base::Closure& error_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!adapter_) {
VLOG(1) << "BluetoothAdapter not ready.";
return false;
}
BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
if (!descriptor) {
VLOG(1) << "Descriptor not found: " << instance_id;
return false;
}
descriptor->WriteRemoteDescriptor(value, callback, error_callback);
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_id_to_device_address_.find(service->GetIdentifier()) ==
service_id_to_device_address_.end());
service->AddObserver(this);
const std::string& service_id = service->GetIdentifier();
observed_gatt_services_.insert(service_id);
service_id_to_device_address_[service_id] = device->GetAddress();
// 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_id_to_device_address_.find(service->GetIdentifier()) !=
service_id_to_device_address_.end());
service->RemoveObserver(this);
observed_gatt_services_.erase(service->GetIdentifier());
DCHECK(device->GetAddress() ==
service_id_to_device_address_[service->GetIdentifier()]);
service_id_to_device_address_.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) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(2) << "GATT service changed: " << service->GetIdentifier();
DCHECK(observed_gatt_services_.find(service->GetIdentifier()) !=
observed_gatt_services_.end());
DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
service_id_to_device_address_.end());
// Signal API event.
apibtle::Service api_service;
PopulateService(service, &api_service);
scoped_ptr<base::ListValue> args =
apibtle::OnServiceChanged::Create(api_service);
scoped_ptr<Event> event(
new Event(apibtle::OnServiceChanged::kEventName, args.Pass()));
EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
}
void BluetoothLowEnergyEventRouter::GattCharacteristicAdded(
BluetoothGattService* service,
BluetoothGattCharacteristic* characteristic) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(2) << "GATT characteristic added: " << characteristic->GetIdentifier();
DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) ==
chrc_id_to_service_id_.end());
DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
service_id_to_device_address_.end());
chrc_id_to_service_id_[characteristic->GetIdentifier()] =
service->GetIdentifier();
}
void BluetoothLowEnergyEventRouter::GattCharacteristicRemoved(
BluetoothGattService* service,
BluetoothGattCharacteristic* characteristic) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(2) << "GATT characteristic removed: " << characteristic->GetIdentifier();
DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
chrc_id_to_service_id_.end());
DCHECK(service->GetIdentifier() ==
chrc_id_to_service_id_[characteristic->GetIdentifier()]);
chrc_id_to_service_id_.erase(characteristic->GetIdentifier());
}
void BluetoothLowEnergyEventRouter::GattDescriptorAdded(
BluetoothGattCharacteristic* characteristic,
BluetoothGattDescriptor* descriptor) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(2) << "GATT descriptor added: " << descriptor->GetIdentifier();
DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) ==
desc_id_to_chrc_id_.end());
DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
chrc_id_to_service_id_.end());
desc_id_to_chrc_id_[descriptor->GetIdentifier()] =
characteristic->GetIdentifier();
}
void BluetoothLowEnergyEventRouter::GattDescriptorRemoved(
BluetoothGattCharacteristic* characteristic,
BluetoothGattDescriptor* descriptor) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(2) << "GATT descriptor removed: " << descriptor->GetIdentifier();
DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) !=
desc_id_to_chrc_id_.end());
DCHECK(characteristic->GetIdentifier() ==
desc_id_to_chrc_id_[descriptor->GetIdentifier()]);
desc_id_to_chrc_id_.erase(descriptor->GetIdentifier());
}
void BluetoothLowEnergyEventRouter::GattCharacteristicValueChanged(
BluetoothGattService* service,
BluetoothGattCharacteristic* characteristic,
const std::vector<uint8>& value) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(2) << "GATT characteristic value changed: "
<< characteristic->GetIdentifier();
DCHECK(observed_gatt_services_.find(service->GetIdentifier()) !=
observed_gatt_services_.end());
DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
service_id_to_device_address_.end());
DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
chrc_id_to_service_id_.end());
DCHECK(chrc_id_to_service_id_[characteristic->GetIdentifier()] ==
service->GetIdentifier());
// Signal API event.
apibtle::Characteristic api_characteristic;
PopulateCharacteristic(characteristic, &api_characteristic);
// Manually construct the arguments, instead of using
// apibtle::OnCharacteristicValueChanged::Create, as it doesn't convert lists
// of enums correctly.
scoped_ptr<base::ListValue> args(new base::ListValue());
args->Append(apibtle::CharacteristicToValue(&api_characteristic).release());
scoped_ptr<Event> event(new Event(
apibtle::OnCharacteristicValueChanged::kEventName, args.Pass()));
EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
}
void BluetoothLowEnergyEventRouter::GattDescriptorValueChanged(
BluetoothGattCharacteristic* characteristic,
BluetoothGattDescriptor* descriptor,
const std::vector<uint8>& value) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(2) << "GATT descriptor value changed: " << descriptor->GetIdentifier();
DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) !=
desc_id_to_chrc_id_.end());
DCHECK(characteristic->GetIdentifier() ==
desc_id_to_chrc_id_[descriptor->GetIdentifier()]);
// Signal API event.
apibtle::Descriptor api_descriptor;
PopulateDescriptor(descriptor, &api_descriptor);
// Manually construct the arguments, instead of using
// apibtle::OnDescriptorValueChanged::Create, as it doesn't convert lists of
// enums correctly.
scoped_ptr<base::ListValue> args(new base::ListValue());
args->Append(apibtle::DescriptorToValue(&api_descriptor).release());
scoped_ptr<Event> event(
new Event(apibtle::OnDescriptorValueChanged::kEventName, args.Pass()));
EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
}
void BluetoothLowEnergyEventRouter::OnGetAdapter(
const base::Closure& callback,
scoped_refptr<device::BluetoothAdapter> adapter) {
adapter_ = adapter;
// Initialize instance ID mappings for all discovered GATT objects and add
// observers.
InitializeIdentifierMappings();
adapter_->AddObserver(this);
callback.Run();
}
void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(service_id_to_device_address_.empty());
DCHECK(chrc_id_to_service_id_.empty());
DCHECK(observed_devices_.empty());
DCHECK(observed_gatt_services_.empty());
// Devices
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());
// Services
std::vector<BluetoothGattService*> services = device->GetGattServices();
for (std::vector<BluetoothGattService*>::iterator siter = services.begin();
siter != services.end();
++siter) {
BluetoothGattService* service = *siter;
service->AddObserver(this);
const std::string& service_id = service->GetIdentifier();
observed_gatt_services_.insert(service_id);
service_id_to_device_address_[service_id] = device->GetAddress();
// Characteristics
const std::vector<BluetoothGattCharacteristic*>& characteristics =
service->GetCharacteristics();
for (std::vector<BluetoothGattCharacteristic*>::const_iterator citer =
characteristics.begin();
citer != characteristics.end();
++citer) {
BluetoothGattCharacteristic* characteristic = *citer;
const std::string& chrc_id = characteristic->GetIdentifier();
chrc_id_to_service_id_[chrc_id] = service_id;
// Descriptors
const std::vector<BluetoothGattDescriptor*>& descriptors =
characteristic->GetDescriptors();
for (std::vector<BluetoothGattDescriptor*>::const_iterator diter =
descriptors.begin();
diter != descriptors.end();
++diter) {
BluetoothGattDescriptor* descriptor = *diter;
const std::string& desc_id = descriptor->GetIdentifier();
desc_id_to_chrc_id_[desc_id] = chrc_id;
}
}
}
}
}
BluetoothGattService* BluetoothLowEnergyEventRouter::FindServiceById(
const std::string& instance_id) const {
InstanceIdMap::const_iterator iter =
service_id_to_device_address_.find(instance_id);
if (iter == service_id_to_device_address_.end()) {
VLOG(1) << "GATT service identifier unknown: " << instance_id;
return NULL;
}
const std::string& address = iter->second;
BluetoothDevice* device = adapter_->GetDevice(address);
if (!device) {
VLOG(1) << "Bluetooth device not found: " << address;
return NULL;
}
BluetoothGattService* service = device->GetGattService(instance_id);
if (!service) {
VLOG(1) << "GATT service with ID \"" << instance_id
<< "\" not found on device \"" << address << "\"";
return NULL;
}
return service;
}
BluetoothGattCharacteristic*
BluetoothLowEnergyEventRouter::FindCharacteristicById(
const std::string& instance_id) const {
InstanceIdMap::const_iterator iter = chrc_id_to_service_id_.find(instance_id);
if (iter == chrc_id_to_service_id_.end()) {
VLOG(1) << "GATT characteristic identifier unknown: " << instance_id;
return NULL;
}
const std::string& service_id = iter->second;
BluetoothGattService* service = FindServiceById(service_id);
if (!service) {
VLOG(1) << "Failed to obtain service for characteristic: " << instance_id;
return NULL;
}
BluetoothGattCharacteristic* characteristic =
service->GetCharacteristic(instance_id);
if (!characteristic) {
VLOG(1) << "GATT characteristic with ID \"" << instance_id
<< "\" not found on service \"" << service_id << "\"";
return NULL;
}
return characteristic;
}
BluetoothGattDescriptor* BluetoothLowEnergyEventRouter::FindDescriptorById(
const std::string& instance_id) const {
InstanceIdMap::const_iterator iter = desc_id_to_chrc_id_.find(instance_id);
if (iter == desc_id_to_chrc_id_.end()) {
VLOG(1) << "GATT descriptor identifier unknown: " << instance_id;
return NULL;
}
const std::string& chrc_id = iter->second;
BluetoothGattCharacteristic* chrc = FindCharacteristicById(chrc_id);
if (!chrc) {
VLOG(1) << "Failed to obtain characteristic for descriptor: "
<< instance_id;
return NULL;
}
BluetoothGattDescriptor* descriptor = chrc->GetDescriptor(instance_id);
if (!descriptor) {
VLOG(1) << "GATT descriptor with ID \"" << instance_id
<< "\" not found on characteristic \"" << chrc_id << "\"";
return NULL;
}
return descriptor;
}
void BluetoothLowEnergyEventRouter::ValueCallback(
const base::Closure& callback,
const std::vector<uint8>& value) {
VLOG(2) << "Remote characteristic/descriptor value read successful.";
callback.Run();
}
} // namespace extensions