Home | History | Annotate | Download | only in bluetooth_low_energy
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/values.h"
     10 #include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.h"
     11 #include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h"
     12 #include "chrome/browser/extensions/api/bluetooth_low_energy/utils.h"
     13 #include "chrome/common/extensions/api/bluetooth/bluetooth_manifest_data.h"
     14 #include "content/public/browser/browser_thread.h"
     15 #include "device/bluetooth/bluetooth_adapter_factory.h"
     16 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
     17 #include "device/bluetooth/bluetooth_gatt_connection.h"
     18 #include "device/bluetooth/bluetooth_gatt_descriptor.h"
     19 #include "extensions/browser/event_router.h"
     20 #include "extensions/browser/extension_registry.h"
     21 
     22 using content::BrowserThread;
     23 
     24 using device::BluetoothAdapter;
     25 using device::BluetoothAdapterFactory;
     26 using device::BluetoothDevice;
     27 using device::BluetoothGattCharacteristic;
     28 using device::BluetoothGattConnection;
     29 using device::BluetoothGattDescriptor;
     30 using device::BluetoothGattService;
     31 
     32 namespace apibtle = extensions::api::bluetooth_low_energy;
     33 
     34 namespace {
     35 
     36 void PopulateService(const BluetoothGattService* service,
     37                      apibtle::Service* out) {
     38   DCHECK(out);
     39 
     40   out->uuid = service->GetUUID().canonical_value();
     41   out->is_primary = service->IsPrimary();
     42   out->is_local = service->IsLocal();
     43   out->instance_id.reset(new std::string(service->GetIdentifier()));
     44 
     45   if (!service->GetDevice())
     46     return;
     47 
     48   out->device_address.reset(
     49       new std::string(service->GetDevice()->GetAddress()));
     50 }
     51 
     52 void PopulateCharacteristicProperties(
     53     BluetoothGattCharacteristic::Properties properties,
     54     std::vector<apibtle::CharacteristicProperty>* api_properties) {
     55   DCHECK(api_properties && api_properties->empty());
     56 
     57   if (properties == BluetoothGattCharacteristic::kPropertyNone)
     58     return;
     59 
     60   if (properties & BluetoothGattCharacteristic::kPropertyBroadcast)
     61     api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_BROADCAST);
     62   if (properties & BluetoothGattCharacteristic::kPropertyRead)
     63     api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_READ);
     64   if (properties & BluetoothGattCharacteristic::kPropertyWriteWithoutResponse) {
     65     api_properties->push_back(
     66         apibtle::CHARACTERISTIC_PROPERTY_WRITEWITHOUTRESPONSE);
     67   }
     68   if (properties & BluetoothGattCharacteristic::kPropertyWrite)
     69     api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_WRITE);
     70   if (properties & BluetoothGattCharacteristic::kPropertyNotify)
     71     api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_NOTIFY);
     72   if (properties & BluetoothGattCharacteristic::kPropertyIndicate)
     73     api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_INDICATE);
     74   if (properties &
     75       BluetoothGattCharacteristic::kPropertyAuthenticatedSignedWrites) {
     76     api_properties->push_back(
     77         apibtle::CHARACTERISTIC_PROPERTY_AUTHENTICATEDSIGNEDWRITES);
     78   }
     79   if (properties & BluetoothGattCharacteristic::kPropertyExtendedProperties) {
     80     api_properties->push_back(
     81         apibtle::CHARACTERISTIC_PROPERTY_EXTENDEDPROPERTIES);
     82   }
     83   if (properties & BluetoothGattCharacteristic::kPropertyReliableWrite)
     84     api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_RELIABLEWRITE);
     85   if (properties & BluetoothGattCharacteristic::kPropertyWritableAuxiliaries) {
     86     api_properties->push_back(
     87         apibtle::CHARACTERISTIC_PROPERTY_WRITABLEAUXILIARIES);
     88   }
     89 }
     90 
     91 void PopulateCharacteristic(const BluetoothGattCharacteristic* characteristic,
     92                             apibtle::Characteristic* out) {
     93   DCHECK(out);
     94 
     95   out->uuid = characteristic->GetUUID().canonical_value();
     96   out->is_local = characteristic->IsLocal();
     97   out->instance_id.reset(new std::string(characteristic->GetIdentifier()));
     98 
     99   PopulateService(characteristic->GetService(), &out->service);
    100   PopulateCharacteristicProperties(characteristic->GetProperties(),
    101                                    &out->properties);
    102 
    103   const std::vector<uint8>& value = characteristic->GetValue();
    104   if (value.empty())
    105     return;
    106 
    107   out->value.reset(new std::string(value.begin(), value.end()));
    108 }
    109 
    110 void PopulateDescriptor(const BluetoothGattDescriptor* descriptor,
    111                         apibtle::Descriptor* out) {
    112   DCHECK(out);
    113 
    114   out->uuid = descriptor->GetUUID().canonical_value();
    115   out->is_local = descriptor->IsLocal();
    116   out->instance_id.reset(new std::string(descriptor->GetIdentifier()));
    117 
    118   PopulateCharacteristic(descriptor->GetCharacteristic(), &out->characteristic);
    119 
    120   const std::vector<uint8>& value = descriptor->GetValue();
    121   if (value.empty())
    122     return;
    123 
    124   out->value.reset(new std::string(value.begin(), value.end()));
    125 }
    126 
    127 typedef extensions::ApiResourceManager<extensions::BluetoothLowEnergyConnection>
    128     ConnectionResourceManager;
    129 ConnectionResourceManager* GetConnectionResourceManager(
    130     content::BrowserContext* context) {
    131   ConnectionResourceManager* manager = ConnectionResourceManager::Get(context);
    132   DCHECK(manager)
    133       << "There is no Bluetooth low energy connection manager. "
    134          "If this assertion is failing during a test, then it is likely that "
    135          "TestExtensionSystem is failing to provide an instance of "
    136          "ApiResourceManager<BluetoothLowEnergyConnection>.";
    137   return manager;
    138 }
    139 
    140 typedef extensions::ApiResourceManager<
    141     extensions::BluetoothLowEnergyNotifySession> NotifySessionResourceManager;
    142 NotifySessionResourceManager* GetNotifySessionResourceManager(
    143     content::BrowserContext* context) {
    144   NotifySessionResourceManager* manager =
    145       NotifySessionResourceManager::Get(context);
    146   DCHECK(manager)
    147       << "There is no Bluetooth low energy value update session manager."
    148          "If this assertion is failing during a test, then it is likely that "
    149          "TestExtensionSystem is failing to provide an instance of "
    150          "ApiResourceManager<BluetoothLowEnergyNotifySession>.";
    151   return manager;
    152 }
    153 
    154 }  // namespace
    155 
    156 namespace extensions {
    157 
    158 BluetoothLowEnergyEventRouter::BluetoothLowEnergyEventRouter(
    159     content::BrowserContext* context)
    160     : adapter_(NULL), browser_context_(context), weak_ptr_factory_(this) {
    161   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    162   DCHECK(browser_context_);
    163   VLOG(1) << "Initializing BluetoothLowEnergyEventRouter.";
    164 
    165   if (!IsBluetoothSupported()) {
    166     VLOG(1) << "Bluetooth not supported on the current platform.";
    167     return;
    168   }
    169 }
    170 
    171 BluetoothLowEnergyEventRouter::~BluetoothLowEnergyEventRouter() {
    172   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    173   if (!adapter_.get())
    174     return;
    175 
    176   adapter_->RemoveObserver(this);
    177 
    178   for (std::set<std::string>::const_iterator iter = observed_devices_.begin();
    179        iter != observed_devices_.end();
    180        ++iter) {
    181     BluetoothDevice* device = adapter_->GetDevice(*iter);
    182     if (!device)
    183       continue;
    184     device->RemoveObserver(this);
    185   }
    186 
    187   for (std::set<std::string>::const_iterator iter =
    188            observed_gatt_services_.begin();
    189        iter != observed_gatt_services_.end();
    190        ++iter) {
    191     BluetoothGattService* service = FindServiceById(*iter);
    192     if (!service)
    193       continue;
    194     service->RemoveObserver(this);
    195   }
    196 
    197   adapter_ = NULL;
    198 }
    199 
    200 bool BluetoothLowEnergyEventRouter::IsBluetoothSupported() const {
    201   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    202   return adapter_.get() ||
    203          BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
    204 }
    205 
    206 bool BluetoothLowEnergyEventRouter::InitializeAdapterAndInvokeCallback(
    207     const base::Closure& callback) {
    208   if (!IsBluetoothSupported())
    209     return false;
    210 
    211   if (adapter_.get()) {
    212     callback.Run();
    213     return true;
    214   }
    215 
    216   BluetoothAdapterFactory::GetAdapter(
    217       base::Bind(&BluetoothLowEnergyEventRouter::OnGetAdapter,
    218                  weak_ptr_factory_.GetWeakPtr(),
    219                  callback));
    220   return true;
    221 }
    222 
    223 bool BluetoothLowEnergyEventRouter::HasAdapter() const {
    224   return (adapter_.get() != NULL);
    225 }
    226 
    227 void BluetoothLowEnergyEventRouter::Connect(
    228     bool persistent,
    229     const Extension* extension,
    230     const std::string& device_address,
    231     const base::Closure& callback,
    232     const ErrorCallback& error_callback) {
    233   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    234   if (!adapter_) {
    235     VLOG(1) << "BluetoothAdapter not ready.";
    236     error_callback.Run(kStatusErrorFailed);
    237     return;
    238   }
    239 
    240   const std::string extension_id = extension->id();
    241   const std::string connect_id = extension_id + device_address;
    242 
    243   if (connecting_devices_.count(connect_id) != 0) {
    244     error_callback.Run(kStatusErrorInProgress);
    245     return;
    246   }
    247 
    248   BluetoothLowEnergyConnection* conn =
    249       FindConnection(extension_id, device_address);
    250   if (conn) {
    251     if (conn->GetConnection()->IsConnected()) {
    252       VLOG(1) << "Application already connected to device: " << device_address;
    253       error_callback.Run(kStatusErrorAlreadyConnected);
    254       return;
    255     }
    256 
    257     // There is a connection object but it's no longer active. Simply remove it.
    258     RemoveConnection(extension_id, device_address);
    259   }
    260 
    261   BluetoothDevice* device = adapter_->GetDevice(device_address);
    262   if (!device) {
    263     VLOG(1) << "Bluetooth device not found: " << device_address;
    264     error_callback.Run(kStatusErrorNotFound);
    265     return;
    266   }
    267 
    268   connecting_devices_.insert(connect_id);
    269   device->CreateGattConnection(
    270       base::Bind(&BluetoothLowEnergyEventRouter::OnCreateGattConnection,
    271                  weak_ptr_factory_.GetWeakPtr(),
    272                  persistent,
    273                  extension_id,
    274                  device_address,
    275                  callback),
    276       base::Bind(&BluetoothLowEnergyEventRouter::OnConnectError,
    277                  weak_ptr_factory_.GetWeakPtr(),
    278                  extension_id,
    279                  device_address,
    280                  error_callback));
    281 }
    282 
    283 void BluetoothLowEnergyEventRouter::Disconnect(
    284     const Extension* extension,
    285     const std::string& device_address,
    286     const base::Closure& callback,
    287     const ErrorCallback& error_callback) {
    288   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    289   if (!adapter_) {
    290     VLOG(1) << "BluetoothAdapter not ready.";
    291     error_callback.Run(kStatusErrorFailed);
    292     return;
    293   }
    294 
    295   const std::string extension_id = extension->id();
    296   const std::string disconnect_id = extension_id + device_address;
    297 
    298   if (disconnecting_devices_.count(disconnect_id) != 0) {
    299     error_callback.Run(kStatusErrorInProgress);
    300     return;
    301   }
    302 
    303   BluetoothLowEnergyConnection* conn =
    304       FindConnection(extension_id, device_address);
    305   if (!conn || !conn->GetConnection()->IsConnected()) {
    306     VLOG(1) << "Application not connected to device: " << device_address;
    307     error_callback.Run(kStatusErrorNotConnected);
    308     return;
    309   }
    310 
    311   disconnecting_devices_.insert(disconnect_id);
    312   conn->GetConnection()->Disconnect(
    313       base::Bind(&BluetoothLowEnergyEventRouter::OnDisconnect,
    314                  weak_ptr_factory_.GetWeakPtr(),
    315                  extension_id,
    316                  device_address,
    317                  callback));
    318 }
    319 
    320 bool BluetoothLowEnergyEventRouter::GetServices(
    321     const std::string& device_address,
    322     ServiceList* out_services) const {
    323   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    324   DCHECK(out_services);
    325   if (!adapter_) {
    326     VLOG(1) << "BluetoothAdapter not ready.";
    327     return false;
    328   }
    329 
    330   BluetoothDevice* device = adapter_->GetDevice(device_address);
    331   if (!device) {
    332     VLOG(1) << "Bluetooth device not found: " << device_address;
    333     return false;
    334   }
    335 
    336   out_services->clear();
    337 
    338   const std::vector<BluetoothGattService*>& services =
    339       device->GetGattServices();
    340   for (std::vector<BluetoothGattService*>::const_iterator iter =
    341            services.begin();
    342        iter != services.end();
    343        ++iter) {
    344     // Populate an API service and add it to the return value.
    345     const BluetoothGattService* service = *iter;
    346     linked_ptr<apibtle::Service> api_service(new apibtle::Service());
    347     PopulateService(service, api_service.get());
    348 
    349     out_services->push_back(api_service);
    350   }
    351 
    352   return true;
    353 }
    354 
    355 BluetoothLowEnergyEventRouter::Status BluetoothLowEnergyEventRouter::GetService(
    356     const std::string& instance_id,
    357     apibtle::Service* out_service) const {
    358   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    359   DCHECK(out_service);
    360   if (!adapter_) {
    361     VLOG(1) << "BluetoothAdapter not ready.";
    362     return kStatusErrorFailed;
    363   }
    364 
    365   BluetoothGattService* gatt_service = FindServiceById(instance_id);
    366   if (!gatt_service) {
    367     VLOG(1) << "Service not found: " << instance_id;
    368     return kStatusErrorNotFound;
    369   }
    370 
    371   PopulateService(gatt_service, out_service);
    372   return kStatusSuccess;
    373 }
    374 
    375 BluetoothLowEnergyEventRouter::Status
    376 BluetoothLowEnergyEventRouter::GetIncludedServices(
    377     const std::string& instance_id,
    378     ServiceList* out_services) const {
    379   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    380   DCHECK(out_services);
    381   if (!adapter_) {
    382     VLOG(1) << "BluetoothAdapter not ready.";
    383     return kStatusErrorFailed;
    384   }
    385 
    386   BluetoothGattService* service = FindServiceById(instance_id);
    387   if (!service) {
    388     VLOG(1) << "Service not found: " << instance_id;
    389     return kStatusErrorNotFound;
    390   }
    391 
    392   out_services->clear();
    393 
    394   const std::vector<BluetoothGattService*>& includes =
    395       service->GetIncludedServices();
    396   for (std::vector<BluetoothGattService*>::const_iterator iter =
    397            includes.begin();
    398        iter != includes.end();
    399        ++iter) {
    400     // Populate an API service and add it to the return value.
    401     const BluetoothGattService* included = *iter;
    402     linked_ptr<apibtle::Service> api_service(new apibtle::Service());
    403     PopulateService(included, api_service.get());
    404 
    405     out_services->push_back(api_service);
    406   }
    407 
    408   return kStatusSuccess;
    409 }
    410 
    411 BluetoothLowEnergyEventRouter::Status
    412 BluetoothLowEnergyEventRouter::GetCharacteristics(
    413     const Extension* extension,
    414     const std::string& instance_id,
    415     CharacteristicList* out_characteristics) const {
    416   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    417   DCHECK(extension);
    418   DCHECK(out_characteristics);
    419   if (!adapter_) {
    420     VLOG(1) << "BlutoothAdapter not ready.";
    421     return kStatusErrorFailed;
    422   }
    423 
    424   BluetoothGattService* service = FindServiceById(instance_id);
    425   if (!service) {
    426     VLOG(1) << "Service not found: " << instance_id;
    427     return kStatusErrorNotFound;
    428   }
    429 
    430   BluetoothPermissionRequest request(service->GetUUID().value());
    431   if (!BluetoothManifestData::CheckRequest(extension, request)) {
    432     VLOG(1) << "App has no permission to access the characteristics of this "
    433             << "service: " << instance_id;
    434     return kStatusErrorPermissionDenied;
    435   }
    436 
    437   out_characteristics->clear();
    438 
    439   const std::vector<BluetoothGattCharacteristic*>& characteristics =
    440       service->GetCharacteristics();
    441   for (std::vector<BluetoothGattCharacteristic*>::const_iterator iter =
    442            characteristics.begin();
    443        iter != characteristics.end();
    444        ++iter) {
    445     // Populate an API characteristic and add it to the return value.
    446     const BluetoothGattCharacteristic* characteristic = *iter;
    447     linked_ptr<apibtle::Characteristic> api_characteristic(
    448         new apibtle::Characteristic());
    449     PopulateCharacteristic(characteristic, api_characteristic.get());
    450 
    451     out_characteristics->push_back(api_characteristic);
    452   }
    453 
    454   return kStatusSuccess;
    455 }
    456 
    457 BluetoothLowEnergyEventRouter::Status
    458 BluetoothLowEnergyEventRouter::GetCharacteristic(
    459     const Extension* extension,
    460     const std::string& instance_id,
    461     apibtle::Characteristic* out_characteristic) const {
    462   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    463   DCHECK(extension);
    464   DCHECK(out_characteristic);
    465   if (!adapter_) {
    466     VLOG(1) << "BluetoothAdapter not ready.";
    467     return kStatusErrorFailed;
    468   }
    469 
    470   BluetoothGattCharacteristic* characteristic =
    471       FindCharacteristicById(instance_id);
    472   if (!characteristic) {
    473     VLOG(1) << "Characteristic not found: " << instance_id;
    474     return kStatusErrorNotFound;
    475   }
    476 
    477   BluetoothPermissionRequest request(
    478       characteristic->GetService()->GetUUID().value());
    479   if (!BluetoothManifestData::CheckRequest(extension, request)) {
    480     VLOG(1) << "App has no permission to access this characteristic: "
    481             << instance_id;
    482     return kStatusErrorPermissionDenied;
    483   }
    484 
    485   PopulateCharacteristic(characteristic, out_characteristic);
    486   return kStatusSuccess;
    487 }
    488 
    489 BluetoothLowEnergyEventRouter::Status
    490 BluetoothLowEnergyEventRouter::GetDescriptors(
    491     const Extension* extension,
    492     const std::string& instance_id,
    493     DescriptorList* out_descriptors) const {
    494   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    495   DCHECK(extension);
    496   DCHECK(out_descriptors);
    497   if (!adapter_) {
    498     VLOG(1) << "BlutoothAdapter not ready.";
    499     return kStatusErrorFailed;
    500   }
    501 
    502   BluetoothGattCharacteristic* characteristic =
    503       FindCharacteristicById(instance_id);
    504   if (!characteristic) {
    505     VLOG(1) << "Characteristic not found: " << instance_id;
    506     return kStatusErrorNotFound;
    507   }
    508 
    509   BluetoothPermissionRequest request(
    510       characteristic->GetService()->GetUUID().value());
    511   if (!BluetoothManifestData::CheckRequest(extension, request)) {
    512     VLOG(1) << "App has no permission to access the descriptors of this "
    513             << "characteristic: " << instance_id;
    514     return kStatusErrorPermissionDenied;
    515   }
    516 
    517   out_descriptors->clear();
    518 
    519   const std::vector<BluetoothGattDescriptor*>& descriptors =
    520       characteristic->GetDescriptors();
    521   for (std::vector<BluetoothGattDescriptor*>::const_iterator iter =
    522            descriptors.begin();
    523        iter != descriptors.end();
    524        ++iter) {
    525     // Populate an API descriptor and add it to the return value.
    526     const BluetoothGattDescriptor* descriptor = *iter;
    527     linked_ptr<apibtle::Descriptor> api_descriptor(new apibtle::Descriptor());
    528     PopulateDescriptor(descriptor, api_descriptor.get());
    529 
    530     out_descriptors->push_back(api_descriptor);
    531   }
    532 
    533   return kStatusSuccess;
    534 }
    535 
    536 BluetoothLowEnergyEventRouter::Status
    537 BluetoothLowEnergyEventRouter::GetDescriptor(
    538     const Extension* extension,
    539     const std::string& instance_id,
    540     api::bluetooth_low_energy::Descriptor* out_descriptor) const {
    541   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    542   DCHECK(extension);
    543   DCHECK(out_descriptor);
    544   if (!adapter_) {
    545     VLOG(1) << "BluetoothAdapter not ready.";
    546     return kStatusErrorFailed;
    547   }
    548 
    549   BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
    550   if (!descriptor) {
    551     VLOG(1) << "Descriptor not found: " << instance_id;
    552     return kStatusErrorNotFound;
    553   }
    554 
    555   BluetoothPermissionRequest request(
    556       descriptor->GetCharacteristic()->GetService()->GetUUID().value());
    557   if (!BluetoothManifestData::CheckRequest(extension, request)) {
    558     VLOG(1) << "App has no permission to access this descriptor: "
    559             << instance_id;
    560     return kStatusErrorPermissionDenied;
    561   }
    562 
    563   PopulateDescriptor(descriptor, out_descriptor);
    564   return kStatusSuccess;
    565 }
    566 
    567 void BluetoothLowEnergyEventRouter::ReadCharacteristicValue(
    568     const Extension* extension,
    569     const std::string& instance_id,
    570     const base::Closure& callback,
    571     const ErrorCallback& error_callback) {
    572   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    573   DCHECK(extension);
    574   if (!adapter_) {
    575     VLOG(1) << "BluetoothAdapter not ready.";
    576     error_callback.Run(kStatusErrorFailed);
    577     return;
    578   }
    579 
    580   BluetoothGattCharacteristic* characteristic =
    581       FindCharacteristicById(instance_id);
    582   if (!characteristic) {
    583     VLOG(1) << "Characteristic not found: " << instance_id;
    584     error_callback.Run(kStatusErrorNotFound);
    585     return;
    586   }
    587 
    588   BluetoothPermissionRequest request(
    589       characteristic->GetService()->GetUUID().value());
    590   if (!BluetoothManifestData::CheckRequest(extension, request)) {
    591     VLOG(1) << "App has no permission to access this characteristic: "
    592             << instance_id;
    593     error_callback.Run(kStatusErrorPermissionDenied);
    594     return;
    595   }
    596 
    597   characteristic->ReadRemoteCharacteristic(
    598       base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
    599                  weak_ptr_factory_.GetWeakPtr(),
    600                  callback),
    601       base::Bind(&BluetoothLowEnergyEventRouter::OnError,
    602                  weak_ptr_factory_.GetWeakPtr(),
    603                  error_callback));
    604 }
    605 
    606 void BluetoothLowEnergyEventRouter::WriteCharacteristicValue(
    607     const Extension* extension,
    608     const std::string& instance_id,
    609     const std::vector<uint8>& value,
    610     const base::Closure& callback,
    611     const ErrorCallback& error_callback) {
    612   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    613   DCHECK(extension);
    614   if (!adapter_) {
    615     VLOG(1) << "BluetoothAdapter not ready.";
    616     error_callback.Run(kStatusErrorFailed);
    617     return;
    618   }
    619 
    620   BluetoothGattCharacteristic* characteristic =
    621       FindCharacteristicById(instance_id);
    622   if (!characteristic) {
    623     VLOG(1) << "Characteristic not found: " << instance_id;
    624     error_callback.Run(kStatusErrorNotFound);
    625     return;
    626   }
    627 
    628   BluetoothPermissionRequest request(
    629       characteristic->GetService()->GetUUID().value());
    630   if (!BluetoothManifestData::CheckRequest(extension, request)) {
    631     VLOG(1) << "App has no permission to access this characteristic: "
    632             << instance_id;
    633     error_callback.Run(kStatusErrorPermissionDenied);
    634     return;
    635   }
    636 
    637   characteristic->WriteRemoteCharacteristic(
    638       value,
    639       callback,
    640       base::Bind(&BluetoothLowEnergyEventRouter::OnError,
    641                  weak_ptr_factory_.GetWeakPtr(),
    642                  error_callback));
    643 }
    644 
    645 void BluetoothLowEnergyEventRouter::StartCharacteristicNotifications(
    646     bool persistent,
    647     const Extension* extension,
    648     const std::string& instance_id,
    649     const base::Closure& callback,
    650     const ErrorCallback& error_callback) {
    651   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    652   if (!adapter_) {
    653     VLOG(1) << "BluetoothAdapter not ready.";
    654     error_callback.Run(kStatusErrorFailed);
    655     return;
    656   }
    657 
    658   const std::string extension_id = extension->id();
    659   const std::string session_id = extension_id + instance_id;
    660 
    661   if (pending_session_calls_.count(session_id) != 0) {
    662     error_callback.Run(kStatusErrorInProgress);
    663     return;
    664   }
    665 
    666   BluetoothLowEnergyNotifySession* session =
    667       FindNotifySession(extension_id, instance_id);
    668   if (session) {
    669     if (session->GetSession()->IsActive()) {
    670       VLOG(1) << "Application has already enabled notifications from "
    671               << "characteristic: " << instance_id;
    672       error_callback.Run(kStatusErrorAlreadyNotifying);
    673       return;
    674     }
    675 
    676     RemoveNotifySession(extension_id, instance_id);
    677   }
    678 
    679   BluetoothGattCharacteristic* characteristic =
    680       FindCharacteristicById(instance_id);
    681   if (!characteristic) {
    682     VLOG(1) << "Characteristic not found: " << instance_id;
    683     error_callback.Run(kStatusErrorNotFound);
    684     return;
    685   }
    686 
    687   BluetoothPermissionRequest request(
    688       characteristic->GetService()->GetUUID().value());
    689   if (!BluetoothManifestData::CheckRequest(extension, request)) {
    690     VLOG(1) << "App has no permission to access this characteristic: "
    691             << instance_id;
    692     error_callback.Run(kStatusErrorPermissionDenied);
    693     return;
    694   }
    695 
    696   pending_session_calls_.insert(session_id);
    697   characteristic->StartNotifySession(
    698       base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySession,
    699                  weak_ptr_factory_.GetWeakPtr(),
    700                  persistent,
    701                  extension_id,
    702                  instance_id,
    703                  callback),
    704       base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySessionError,
    705                  weak_ptr_factory_.GetWeakPtr(),
    706                  extension_id,
    707                  instance_id,
    708                  error_callback));
    709 }
    710 
    711 void BluetoothLowEnergyEventRouter::StopCharacteristicNotifications(
    712     const Extension* extension,
    713     const std::string& instance_id,
    714     const base::Closure& callback,
    715     const ErrorCallback& error_callback) {
    716   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    717   if (!adapter_) {
    718     VLOG(1) << "BluetoothAdapter not ready.";
    719     error_callback.Run(kStatusErrorFailed);
    720     return;
    721   }
    722 
    723   const std::string extension_id = extension->id();
    724 
    725   BluetoothLowEnergyNotifySession* session =
    726       FindNotifySession(extension_id, instance_id);
    727   if (!session || !session->GetSession()->IsActive()) {
    728     VLOG(1) << "Application has not enabled notifications from "
    729             << "characteristic: " << instance_id;
    730     error_callback.Run(kStatusErrorNotNotifying);
    731     return;
    732   }
    733 
    734   session->GetSession()->Stop(
    735       base::Bind(&BluetoothLowEnergyEventRouter::OnStopNotifySession,
    736                  weak_ptr_factory_.GetWeakPtr(),
    737                  extension_id,
    738                  instance_id,
    739                  callback));
    740 }
    741 
    742 void BluetoothLowEnergyEventRouter::ReadDescriptorValue(
    743     const Extension* extension,
    744     const std::string& instance_id,
    745     const base::Closure& callback,
    746     const ErrorCallback& error_callback) {
    747   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    748   DCHECK(extension);
    749   if (!adapter_) {
    750     VLOG(1) << "BluetoothAdapter not ready.";
    751     error_callback.Run(kStatusErrorFailed);
    752     return;
    753   }
    754 
    755   BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
    756   if (!descriptor) {
    757     VLOG(1) << "Descriptor not found: " << instance_id;
    758     error_callback.Run(kStatusErrorNotFound);
    759     return;
    760   }
    761 
    762   BluetoothPermissionRequest request(
    763       descriptor->GetCharacteristic()->GetService()->GetUUID().value());
    764   if (!BluetoothManifestData::CheckRequest(extension, request)) {
    765     VLOG(1) << "App has no permission to access this descriptor: "
    766             << instance_id;
    767     error_callback.Run(kStatusErrorPermissionDenied);
    768     return;
    769   }
    770 
    771   descriptor->ReadRemoteDescriptor(
    772       base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
    773                  weak_ptr_factory_.GetWeakPtr(),
    774                  callback),
    775       base::Bind(&BluetoothLowEnergyEventRouter::OnError,
    776                  weak_ptr_factory_.GetWeakPtr(),
    777                  error_callback));
    778 }
    779 
    780 void BluetoothLowEnergyEventRouter::WriteDescriptorValue(
    781     const Extension* extension,
    782     const std::string& instance_id,
    783     const std::vector<uint8>& value,
    784     const base::Closure& callback,
    785     const ErrorCallback& error_callback) {
    786   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    787   DCHECK(extension);
    788   if (!adapter_) {
    789     VLOG(1) << "BluetoothAdapter not ready.";
    790     error_callback.Run(kStatusErrorFailed);
    791     return;
    792   }
    793 
    794   BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
    795   if (!descriptor) {
    796     VLOG(1) << "Descriptor not found: " << instance_id;
    797     error_callback.Run(kStatusErrorNotFound);
    798     return;
    799   }
    800 
    801   BluetoothPermissionRequest request(
    802       descriptor->GetCharacteristic()->GetService()->GetUUID().value());
    803   if (!BluetoothManifestData::CheckRequest(extension, request)) {
    804     VLOG(1) << "App has no permission to access this descriptor: "
    805             << instance_id;
    806     error_callback.Run(kStatusErrorPermissionDenied);
    807     return;
    808   }
    809 
    810   descriptor->WriteRemoteDescriptor(
    811       value,
    812       callback,
    813       base::Bind(&BluetoothLowEnergyEventRouter::OnError,
    814                  weak_ptr_factory_.GetWeakPtr(),
    815                  error_callback));
    816 }
    817 
    818 void BluetoothLowEnergyEventRouter::SetAdapterForTesting(
    819     device::BluetoothAdapter* adapter) {
    820   adapter_ = adapter;
    821   InitializeIdentifierMappings();
    822 }
    823 
    824 void BluetoothLowEnergyEventRouter::DeviceAdded(BluetoothAdapter* adapter,
    825                                                 BluetoothDevice* device) {
    826   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    827   DCHECK(observed_devices_.find(device->GetAddress()) ==
    828          observed_devices_.end());
    829   device->AddObserver(this);
    830   observed_devices_.insert(device->GetAddress());
    831 }
    832 
    833 void BluetoothLowEnergyEventRouter::DeviceRemoved(BluetoothAdapter* adapter,
    834                                                   BluetoothDevice* device) {
    835   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    836   DCHECK(observed_devices_.find(device->GetAddress()) !=
    837          observed_devices_.end());
    838   device->RemoveObserver(this);
    839   observed_devices_.erase(device->GetAddress());
    840 }
    841 
    842 void BluetoothLowEnergyEventRouter::GattServiceAdded(
    843     BluetoothDevice* device,
    844     BluetoothGattService* service) {
    845   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    846   VLOG(2) << "GATT service added: " << service->GetIdentifier();
    847 
    848   DCHECK(observed_gatt_services_.find(service->GetIdentifier()) ==
    849          observed_gatt_services_.end());
    850   DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) ==
    851          service_id_to_device_address_.end());
    852 
    853   service->AddObserver(this);
    854 
    855   const std::string& service_id = service->GetIdentifier();
    856   observed_gatt_services_.insert(service_id);
    857   service_id_to_device_address_[service_id] = device->GetAddress();
    858 
    859   // Signal API event.
    860   apibtle::Service api_service;
    861   PopulateService(service, &api_service);
    862 
    863   scoped_ptr<base::ListValue> args =
    864       apibtle::OnServiceAdded::Create(api_service);
    865   scoped_ptr<Event> event(
    866       new Event(apibtle::OnServiceAdded::kEventName, args.Pass()));
    867   EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
    868 }
    869 
    870 void BluetoothLowEnergyEventRouter::GattServiceRemoved(
    871     BluetoothDevice* device,
    872     BluetoothGattService* service) {
    873   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    874   VLOG(2) << "GATT service removed: " << service->GetIdentifier();
    875 
    876   DCHECK(observed_gatt_services_.find(service->GetIdentifier()) !=
    877          observed_gatt_services_.end());
    878   DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
    879          service_id_to_device_address_.end());
    880 
    881   service->RemoveObserver(this);
    882   observed_gatt_services_.erase(service->GetIdentifier());
    883 
    884   DCHECK(device->GetAddress() ==
    885          service_id_to_device_address_[service->GetIdentifier()]);
    886   service_id_to_device_address_.erase(service->GetIdentifier());
    887 
    888   // Signal API event.
    889   apibtle::Service api_service;
    890   PopulateService(service, &api_service);
    891 
    892   scoped_ptr<base::ListValue> args =
    893       apibtle::OnServiceRemoved::Create(api_service);
    894   scoped_ptr<Event> event(
    895       new Event(apibtle::OnServiceRemoved::kEventName, args.Pass()));
    896   EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
    897 }
    898 
    899 void BluetoothLowEnergyEventRouter::GattServiceChanged(
    900     BluetoothGattService* service) {
    901   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    902   VLOG(2) << "GATT service changed: " << service->GetIdentifier();
    903 
    904   DCHECK(observed_gatt_services_.find(service->GetIdentifier()) !=
    905          observed_gatt_services_.end());
    906   DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
    907          service_id_to_device_address_.end());
    908 
    909   // Signal API event.
    910   apibtle::Service api_service;
    911   PopulateService(service, &api_service);
    912 
    913   DispatchEventToExtensionsWithPermission(
    914       apibtle::OnServiceChanged::kEventName,
    915       service->GetUUID(),
    916       "" /* characteristic_id */,
    917       apibtle::OnServiceChanged::Create(api_service));
    918 }
    919 
    920 void BluetoothLowEnergyEventRouter::GattCharacteristicAdded(
    921     BluetoothGattService* service,
    922     BluetoothGattCharacteristic* characteristic) {
    923   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    924   VLOG(2) << "GATT characteristic added: " << characteristic->GetIdentifier();
    925 
    926   DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) ==
    927          chrc_id_to_service_id_.end());
    928   DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
    929          service_id_to_device_address_.end());
    930 
    931   chrc_id_to_service_id_[characteristic->GetIdentifier()] =
    932       service->GetIdentifier();
    933 }
    934 
    935 void BluetoothLowEnergyEventRouter::GattCharacteristicRemoved(
    936     BluetoothGattService* service,
    937     BluetoothGattCharacteristic* characteristic) {
    938   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    939   VLOG(2) << "GATT characteristic removed: " << characteristic->GetIdentifier();
    940 
    941   DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
    942          chrc_id_to_service_id_.end());
    943   DCHECK(service->GetIdentifier() ==
    944          chrc_id_to_service_id_[characteristic->GetIdentifier()]);
    945 
    946   chrc_id_to_service_id_.erase(characteristic->GetIdentifier());
    947 }
    948 
    949 void BluetoothLowEnergyEventRouter::GattDescriptorAdded(
    950     BluetoothGattCharacteristic* characteristic,
    951     BluetoothGattDescriptor* descriptor) {
    952   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    953   VLOG(2) << "GATT descriptor added: " << descriptor->GetIdentifier();
    954 
    955   DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) ==
    956          desc_id_to_chrc_id_.end());
    957   DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
    958          chrc_id_to_service_id_.end());
    959 
    960   desc_id_to_chrc_id_[descriptor->GetIdentifier()] =
    961       characteristic->GetIdentifier();
    962 }
    963 
    964 void BluetoothLowEnergyEventRouter::GattDescriptorRemoved(
    965     BluetoothGattCharacteristic* characteristic,
    966     BluetoothGattDescriptor* descriptor) {
    967   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    968   VLOG(2) << "GATT descriptor removed: " << descriptor->GetIdentifier();
    969 
    970   DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) !=
    971          desc_id_to_chrc_id_.end());
    972   DCHECK(characteristic->GetIdentifier() ==
    973          desc_id_to_chrc_id_[descriptor->GetIdentifier()]);
    974 
    975   desc_id_to_chrc_id_.erase(descriptor->GetIdentifier());
    976 }
    977 
    978 void BluetoothLowEnergyEventRouter::GattCharacteristicValueChanged(
    979     BluetoothGattService* service,
    980     BluetoothGattCharacteristic* characteristic,
    981     const std::vector<uint8>& value) {
    982   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    983   VLOG(2) << "GATT characteristic value changed: "
    984           << characteristic->GetIdentifier();
    985 
    986   DCHECK(observed_gatt_services_.find(service->GetIdentifier()) !=
    987          observed_gatt_services_.end());
    988   DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
    989          service_id_to_device_address_.end());
    990   DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
    991          chrc_id_to_service_id_.end());
    992   DCHECK(chrc_id_to_service_id_[characteristic->GetIdentifier()] ==
    993          service->GetIdentifier());
    994 
    995   // Send the event; manually construct the arguments, instead of using
    996   // apibtle::OnCharacteristicValueChanged::Create, as it doesn't convert
    997   // lists of enums correctly.
    998   apibtle::Characteristic api_characteristic;
    999   PopulateCharacteristic(characteristic, &api_characteristic);
   1000   scoped_ptr<base::ListValue> args(new base::ListValue());
   1001   args->Append(apibtle::CharacteristicToValue(&api_characteristic).release());
   1002 
   1003   DispatchEventToExtensionsWithPermission(
   1004       apibtle::OnCharacteristicValueChanged::kEventName,
   1005       service->GetUUID(),
   1006       characteristic->GetIdentifier(),
   1007       args.Pass());
   1008 }
   1009 
   1010 void BluetoothLowEnergyEventRouter::GattDescriptorValueChanged(
   1011     BluetoothGattCharacteristic* characteristic,
   1012     BluetoothGattDescriptor* descriptor,
   1013     const std::vector<uint8>& value) {
   1014   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1015   VLOG(2) << "GATT descriptor value changed: " << descriptor->GetIdentifier();
   1016 
   1017   DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) !=
   1018          desc_id_to_chrc_id_.end());
   1019   DCHECK(characteristic->GetIdentifier() ==
   1020          desc_id_to_chrc_id_[descriptor->GetIdentifier()]);
   1021 
   1022   // Send the event; manually construct the arguments, instead of using
   1023   // apibtle::OnDescriptorValueChanged::Create, as it doesn't convert
   1024   // lists of enums correctly.
   1025   apibtle::Descriptor api_descriptor;
   1026   PopulateDescriptor(descriptor, &api_descriptor);
   1027   scoped_ptr<base::ListValue> args(new base::ListValue());
   1028   args->Append(apibtle::DescriptorToValue(&api_descriptor).release());
   1029 
   1030   DispatchEventToExtensionsWithPermission(
   1031       apibtle::OnDescriptorValueChanged::kEventName,
   1032       characteristic->GetService()->GetUUID(),
   1033       "" /* characteristic_id */,
   1034       args.Pass());
   1035 }
   1036 
   1037 void BluetoothLowEnergyEventRouter::OnGetAdapter(
   1038     const base::Closure& callback,
   1039     scoped_refptr<device::BluetoothAdapter> adapter) {
   1040   adapter_ = adapter;
   1041 
   1042   // Initialize instance ID mappings for all discovered GATT objects and add
   1043   // observers.
   1044   InitializeIdentifierMappings();
   1045   adapter_->AddObserver(this);
   1046 
   1047   callback.Run();
   1048 }
   1049 
   1050 void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() {
   1051   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1052   DCHECK(service_id_to_device_address_.empty());
   1053   DCHECK(chrc_id_to_service_id_.empty());
   1054   DCHECK(observed_devices_.empty());
   1055   DCHECK(observed_gatt_services_.empty());
   1056 
   1057   // Devices
   1058   BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
   1059   for (BluetoothAdapter::DeviceList::iterator iter = devices.begin();
   1060        iter != devices.end();
   1061        ++iter) {
   1062     BluetoothDevice* device = *iter;
   1063     device->AddObserver(this);
   1064     observed_devices_.insert(device->GetAddress());
   1065 
   1066     // Services
   1067     std::vector<BluetoothGattService*> services = device->GetGattServices();
   1068     for (std::vector<BluetoothGattService*>::iterator siter = services.begin();
   1069          siter != services.end();
   1070          ++siter) {
   1071       BluetoothGattService* service = *siter;
   1072       service->AddObserver(this);
   1073 
   1074       const std::string& service_id = service->GetIdentifier();
   1075       observed_gatt_services_.insert(service_id);
   1076       service_id_to_device_address_[service_id] = device->GetAddress();
   1077 
   1078       // Characteristics
   1079       const std::vector<BluetoothGattCharacteristic*>& characteristics =
   1080           service->GetCharacteristics();
   1081       for (std::vector<BluetoothGattCharacteristic*>::const_iterator citer =
   1082                characteristics.begin();
   1083            citer != characteristics.end();
   1084            ++citer) {
   1085         BluetoothGattCharacteristic* characteristic = *citer;
   1086 
   1087         const std::string& chrc_id = characteristic->GetIdentifier();
   1088         chrc_id_to_service_id_[chrc_id] = service_id;
   1089 
   1090         // Descriptors
   1091         const std::vector<BluetoothGattDescriptor*>& descriptors =
   1092             characteristic->GetDescriptors();
   1093         for (std::vector<BluetoothGattDescriptor*>::const_iterator diter =
   1094                  descriptors.begin();
   1095              diter != descriptors.end();
   1096              ++diter) {
   1097           BluetoothGattDescriptor* descriptor = *diter;
   1098 
   1099           const std::string& desc_id = descriptor->GetIdentifier();
   1100           desc_id_to_chrc_id_[desc_id] = chrc_id;
   1101         }
   1102       }
   1103     }
   1104   }
   1105 }
   1106 
   1107 void BluetoothLowEnergyEventRouter::DispatchEventToExtensionsWithPermission(
   1108     const std::string& event_name,
   1109     const device::BluetoothUUID& uuid,
   1110     const std::string& characteristic_id,
   1111     scoped_ptr<base::ListValue> args) {
   1112   // Obtain the listeners of |event_name|. The list can contain multiple
   1113   // entries for the same extension, so we keep track of the extensions that we
   1114   // already sent the event to, since we want the send an event to an extension
   1115   // only once.
   1116   BluetoothPermissionRequest request(uuid.value());
   1117   std::set<std::string> handled_extensions;
   1118   const EventListenerMap::ListenerList listeners =
   1119       EventRouter::Get(browser_context_)->listeners().GetEventListenersByName(
   1120           event_name);
   1121 
   1122   for (EventListenerMap::ListenerList::const_iterator iter = listeners.begin();
   1123        iter != listeners.end();
   1124        ++iter) {
   1125     const std::string extension_id = (*iter)->extension_id();
   1126     if (handled_extensions.find(extension_id) != handled_extensions.end())
   1127       continue;
   1128 
   1129     handled_extensions.insert(extension_id);
   1130 
   1131     const Extension* extension =
   1132         ExtensionRegistry::Get(browser_context_)
   1133             ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
   1134 
   1135     // For all API methods, the "low_energy" permission check is handled by
   1136     // BluetoothLowEnergyExtensionFunction but for events we have to do the
   1137     // check here.
   1138     if (!BluetoothManifestData::CheckRequest(extension, request) ||
   1139         !BluetoothManifestData::CheckLowEnergyPermitted(extension))
   1140       continue;
   1141 
   1142     // If |event_name| is "onCharacteristicValueChanged", then send the
   1143     // event only if the extension has requested notifications from the
   1144     // related characteristic.
   1145     if (event_name == apibtle::OnCharacteristicValueChanged::kEventName &&
   1146         !characteristic_id.empty() &&
   1147         !FindNotifySession(extension_id, characteristic_id))
   1148       continue;
   1149 
   1150     // Send the event.
   1151     scoped_ptr<base::ListValue> args_copy(args->DeepCopy());
   1152     scoped_ptr<Event> event(new Event(event_name, args_copy.Pass()));
   1153     EventRouter::Get(browser_context_)->DispatchEventToExtension(
   1154         extension_id, event.Pass());
   1155   }
   1156 }
   1157 
   1158 BluetoothGattService* BluetoothLowEnergyEventRouter::FindServiceById(
   1159     const std::string& instance_id) const {
   1160   InstanceIdMap::const_iterator iter =
   1161       service_id_to_device_address_.find(instance_id);
   1162   if (iter == service_id_to_device_address_.end()) {
   1163     VLOG(1) << "GATT service identifier unknown: " << instance_id;
   1164     return NULL;
   1165   }
   1166 
   1167   const std::string& address = iter->second;
   1168 
   1169   BluetoothDevice* device = adapter_->GetDevice(address);
   1170   if (!device) {
   1171     VLOG(1) << "Bluetooth device not found: " << address;
   1172     return NULL;
   1173   }
   1174 
   1175   BluetoothGattService* service = device->GetGattService(instance_id);
   1176   if (!service) {
   1177     VLOG(1) << "GATT service with ID \"" << instance_id
   1178             << "\" not found on device \"" << address << "\"";
   1179     return NULL;
   1180   }
   1181 
   1182   return service;
   1183 }
   1184 
   1185 BluetoothGattCharacteristic*
   1186 BluetoothLowEnergyEventRouter::FindCharacteristicById(
   1187     const std::string& instance_id) const {
   1188   InstanceIdMap::const_iterator iter = chrc_id_to_service_id_.find(instance_id);
   1189   if (iter == chrc_id_to_service_id_.end()) {
   1190     VLOG(1) << "GATT characteristic identifier unknown: " << instance_id;
   1191     return NULL;
   1192   }
   1193 
   1194   const std::string& service_id = iter->second;
   1195 
   1196   BluetoothGattService* service = FindServiceById(service_id);
   1197   if (!service) {
   1198     VLOG(1) << "Failed to obtain service for characteristic: " << instance_id;
   1199     return NULL;
   1200   }
   1201 
   1202   BluetoothGattCharacteristic* characteristic =
   1203       service->GetCharacteristic(instance_id);
   1204   if (!characteristic) {
   1205     VLOG(1) << "GATT characteristic with ID \"" << instance_id
   1206             << "\" not found on service \"" << service_id << "\"";
   1207     return NULL;
   1208   }
   1209 
   1210   return characteristic;
   1211 }
   1212 
   1213 BluetoothGattDescriptor* BluetoothLowEnergyEventRouter::FindDescriptorById(
   1214     const std::string& instance_id) const {
   1215   InstanceIdMap::const_iterator iter = desc_id_to_chrc_id_.find(instance_id);
   1216   if (iter == desc_id_to_chrc_id_.end()) {
   1217     VLOG(1) << "GATT descriptor identifier unknown: " << instance_id;
   1218     return NULL;
   1219   }
   1220 
   1221   const std::string& chrc_id = iter->second;
   1222   BluetoothGattCharacteristic* chrc = FindCharacteristicById(chrc_id);
   1223   if (!chrc) {
   1224     VLOG(1) << "Failed to obtain characteristic for descriptor: "
   1225             << instance_id;
   1226     return NULL;
   1227   }
   1228 
   1229   BluetoothGattDescriptor* descriptor = chrc->GetDescriptor(instance_id);
   1230   if (!descriptor) {
   1231     VLOG(1) << "GATT descriptor with ID \"" << instance_id
   1232             << "\" not found on characteristic \"" << chrc_id << "\"";
   1233     return NULL;
   1234   }
   1235 
   1236   return descriptor;
   1237 }
   1238 
   1239 void BluetoothLowEnergyEventRouter::OnValueSuccess(
   1240     const base::Closure& callback,
   1241     const std::vector<uint8>& value) {
   1242   VLOG(2) << "Remote characteristic/descriptor value read successful.";
   1243   callback.Run();
   1244 }
   1245 
   1246 void BluetoothLowEnergyEventRouter::OnCreateGattConnection(
   1247     bool persistent,
   1248     const std::string& extension_id,
   1249     const std::string& device_address,
   1250     const base::Closure& callback,
   1251     scoped_ptr<BluetoothGattConnection> connection) {
   1252   VLOG(2) << "GATT connection created.";
   1253   DCHECK(connection.get());
   1254   DCHECK(!FindConnection(extension_id, device_address));
   1255   DCHECK_EQ(device_address, connection->GetDeviceAddress());
   1256 
   1257   const std::string connect_id = extension_id + device_address;
   1258   DCHECK_NE(0U, connecting_devices_.count(connect_id));
   1259 
   1260   BluetoothLowEnergyConnection* conn = new BluetoothLowEnergyConnection(
   1261       persistent, extension_id, connection.Pass());
   1262   ConnectionResourceManager* manager =
   1263       GetConnectionResourceManager(browser_context_);
   1264   manager->Add(conn);
   1265 
   1266   connecting_devices_.erase(connect_id);
   1267   callback.Run();
   1268 }
   1269 
   1270 void BluetoothLowEnergyEventRouter::OnDisconnect(
   1271     const std::string& extension_id,
   1272     const std::string& device_address,
   1273     const base::Closure& callback) {
   1274   VLOG(2) << "GATT connection terminated.";
   1275 
   1276   const std::string disconnect_id = extension_id + device_address;
   1277   DCHECK_NE(0U, disconnecting_devices_.count(disconnect_id));
   1278 
   1279   if (!RemoveConnection(extension_id, device_address)) {
   1280     VLOG(1) << "The connection was removed before disconnect completed, id: "
   1281             << extension_id << ", device: " << device_address;
   1282   }
   1283 
   1284   disconnecting_devices_.erase(disconnect_id);
   1285   callback.Run();
   1286 }
   1287 
   1288 void BluetoothLowEnergyEventRouter::OnError(
   1289     const ErrorCallback& error_callback) {
   1290   VLOG(2) << "Remote characteristic/descriptor value read/write failed.";
   1291   error_callback.Run(kStatusErrorFailed);
   1292 }
   1293 
   1294 void BluetoothLowEnergyEventRouter::OnConnectError(
   1295     const std::string& extension_id,
   1296     const std::string& device_address,
   1297     const ErrorCallback& error_callback,
   1298     BluetoothDevice::ConnectErrorCode error_code) {
   1299   VLOG(2) << "Failed to create GATT connection: " << error_code;
   1300 
   1301   const std::string connect_id = extension_id + device_address;
   1302   DCHECK_NE(0U, connecting_devices_.count(connect_id));
   1303 
   1304   connecting_devices_.erase(connect_id);
   1305   error_callback.Run(kStatusErrorFailed);
   1306 }
   1307 
   1308 void BluetoothLowEnergyEventRouter::OnStartNotifySession(
   1309     bool persistent,
   1310     const std::string& extension_id,
   1311     const std::string& characteristic_id,
   1312     const base::Closure& callback,
   1313     scoped_ptr<device::BluetoothGattNotifySession> session) {
   1314   VLOG(2) << "Value update session created for characteristic: "
   1315           << characteristic_id;
   1316   DCHECK(session.get());
   1317   DCHECK(!FindNotifySession(extension_id, characteristic_id));
   1318   DCHECK_EQ(characteristic_id, session->GetCharacteristicIdentifier());
   1319 
   1320   const std::string session_id = extension_id + characteristic_id;
   1321   DCHECK_NE(0U, pending_session_calls_.count(session_id));
   1322 
   1323   BluetoothLowEnergyNotifySession* resource =
   1324       new BluetoothLowEnergyNotifySession(
   1325           persistent, extension_id, session.Pass());
   1326 
   1327   NotifySessionResourceManager* manager =
   1328       GetNotifySessionResourceManager(browser_context_);
   1329   manager->Add(resource);
   1330 
   1331   pending_session_calls_.erase(session_id);
   1332   callback.Run();
   1333 }
   1334 
   1335 void BluetoothLowEnergyEventRouter::OnStartNotifySessionError(
   1336     const std::string& extension_id,
   1337     const std::string& characteristic_id,
   1338     const ErrorCallback& error_callback) {
   1339   VLOG(2) << "Failed to create value update session for characteristic: "
   1340           << characteristic_id;
   1341 
   1342   const std::string session_id = extension_id + characteristic_id;
   1343   DCHECK_NE(0U, pending_session_calls_.count(session_id));
   1344 
   1345   pending_session_calls_.erase(session_id);
   1346   error_callback.Run(kStatusErrorFailed);
   1347 }
   1348 
   1349 void BluetoothLowEnergyEventRouter::OnStopNotifySession(
   1350     const std::string& extension_id,
   1351     const std::string& characteristic_id,
   1352     const base::Closure& callback) {
   1353   VLOG(2) << "Value update session terminated.";
   1354 
   1355   if (!RemoveNotifySession(extension_id, characteristic_id)) {
   1356     VLOG(1) << "The value update session was removed before Stop completed, "
   1357             << "id: " << extension_id
   1358             << ", characteristic: " << characteristic_id;
   1359   }
   1360 
   1361   callback.Run();
   1362 }
   1363 
   1364 BluetoothLowEnergyConnection* BluetoothLowEnergyEventRouter::FindConnection(
   1365     const std::string& extension_id,
   1366     const std::string& device_address) {
   1367   ConnectionResourceManager* manager =
   1368       GetConnectionResourceManager(browser_context_);
   1369 
   1370   base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
   1371   if (!connection_ids)
   1372     return NULL;
   1373 
   1374   for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
   1375        iter != connection_ids->end();
   1376        ++iter) {
   1377     extensions::BluetoothLowEnergyConnection* conn =
   1378         manager->Get(extension_id, *iter);
   1379     if (!conn)
   1380       continue;
   1381 
   1382     if (conn->GetConnection()->GetDeviceAddress() == device_address)
   1383       return conn;
   1384   }
   1385 
   1386   return NULL;
   1387 }
   1388 
   1389 bool BluetoothLowEnergyEventRouter::RemoveConnection(
   1390     const std::string& extension_id,
   1391     const std::string& device_address) {
   1392   ConnectionResourceManager* manager =
   1393       GetConnectionResourceManager(browser_context_);
   1394 
   1395   base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
   1396   if (!connection_ids)
   1397     return false;
   1398 
   1399   for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
   1400        iter != connection_ids->end();
   1401        ++iter) {
   1402     extensions::BluetoothLowEnergyConnection* conn =
   1403         manager->Get(extension_id, *iter);
   1404     if (!conn || conn->GetConnection()->GetDeviceAddress() != device_address)
   1405       continue;
   1406 
   1407     manager->Remove(extension_id, *iter);
   1408     return true;
   1409   }
   1410 
   1411   return false;
   1412 }
   1413 
   1414 BluetoothLowEnergyNotifySession*
   1415 BluetoothLowEnergyEventRouter::FindNotifySession(
   1416     const std::string& extension_id,
   1417     const std::string& characteristic_id) {
   1418   NotifySessionResourceManager* manager =
   1419       GetNotifySessionResourceManager(browser_context_);
   1420 
   1421   base::hash_set<int>* ids = manager->GetResourceIds(extension_id);
   1422   if (!ids)
   1423     return NULL;
   1424 
   1425   for (base::hash_set<int>::const_iterator iter = ids->begin();
   1426        iter != ids->end();
   1427        ++iter) {
   1428     BluetoothLowEnergyNotifySession* session =
   1429         manager->Get(extension_id, *iter);
   1430     if (!session)
   1431       continue;
   1432 
   1433     if (session->GetSession()->GetCharacteristicIdentifier() ==
   1434         characteristic_id)
   1435       return session;
   1436   }
   1437 
   1438   return NULL;
   1439 }
   1440 
   1441 bool BluetoothLowEnergyEventRouter::RemoveNotifySession(
   1442     const std::string& extension_id,
   1443     const std::string& characteristic_id) {
   1444   NotifySessionResourceManager* manager =
   1445       GetNotifySessionResourceManager(browser_context_);
   1446 
   1447   base::hash_set<int>* ids = manager->GetResourceIds(extension_id);
   1448   if (!ids)
   1449     return false;
   1450 
   1451   for (base::hash_set<int>::const_iterator iter = ids->begin();
   1452        iter != ids->end();
   1453        ++iter) {
   1454     BluetoothLowEnergyNotifySession* session =
   1455         manager->Get(extension_id, *iter);
   1456     if (!session ||
   1457         session->GetSession()->GetCharacteristicIdentifier() !=
   1458             characteristic_id)
   1459       continue;
   1460 
   1461     manager->Remove(extension_id, *iter);
   1462     return true;
   1463   }
   1464 
   1465   return false;
   1466 }
   1467 
   1468 }  // namespace extensions
   1469