Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / browser / api / bluetooth_low_energy / bluetooth_low_energy_event_router.cc
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
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::core_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   adapter_ = NULL;
178 }
179
180 bool BluetoothLowEnergyEventRouter::IsBluetoothSupported() const {
181   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
182   return adapter_.get() ||
183          BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
184 }
185
186 bool 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
203 bool BluetoothLowEnergyEventRouter::HasAdapter() const {
204   return (adapter_.get() != NULL);
205 }
206
207 void 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
263 void 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
300 bool 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
335 BluetoothLowEnergyEventRouter::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
355 BluetoothLowEnergyEventRouter::Status
356 BluetoothLowEnergyEventRouter::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
391 BluetoothLowEnergyEventRouter::Status
392 BluetoothLowEnergyEventRouter::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
437 BluetoothLowEnergyEventRouter::Status
438 BluetoothLowEnergyEventRouter::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
469 BluetoothLowEnergyEventRouter::Status
470 BluetoothLowEnergyEventRouter::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
516 BluetoothLowEnergyEventRouter::Status
517 BluetoothLowEnergyEventRouter::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
547 void 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
586 void 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
625 void 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
691 void 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
722 void 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
760 void 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
798 void BluetoothLowEnergyEventRouter::SetAdapterForTesting(
799     device::BluetoothAdapter* adapter) {
800   adapter_ = adapter;
801   InitializeIdentifierMappings();
802 }
803
804 void 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
819 void 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
845 void 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
866 void 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
886 void 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
905 void 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
923 void 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
942 void 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
960 void 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
994 void 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
1025 void 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
1038 void 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
1089 void 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
1140 BluetoothGattService* 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
1167 BluetoothGattCharacteristic*
1168 BluetoothLowEnergyEventRouter::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
1195 BluetoothGattDescriptor* 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
1221 void 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
1228 void 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
1252 void 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
1270 void BluetoothLowEnergyEventRouter::OnError(
1271     const ErrorCallback& error_callback) {
1272   VLOG(2) << "Remote characteristic/descriptor value read/write failed.";
1273   error_callback.Run(kStatusErrorFailed);
1274 }
1275
1276 void 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
1290 void 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
1317 void 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
1331 void 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
1346 BluetoothLowEnergyConnection* 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
1371 bool 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
1396 BluetoothLowEnergyNotifySession*
1397 BluetoothLowEnergyEventRouter::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
1423 bool 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