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