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.
5 #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.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"
22 using content::BrowserThread;
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;
32 namespace apibtle = extensions::core_api::bluetooth_low_energy;
36 void PopulateService(const BluetoothGattService* service,
37 apibtle::Service* out) {
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()));
45 if (!service->GetDevice())
48 out->device_address.reset(
49 new std::string(service->GetDevice()->GetAddress()));
52 void PopulateCharacteristicProperties(
53 BluetoothGattCharacteristic::Properties properties,
54 std::vector<apibtle::CharacteristicProperty>* api_properties) {
55 DCHECK(api_properties && api_properties->empty());
57 if (properties == BluetoothGattCharacteristic::kPropertyNone)
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);
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);
75 BluetoothGattCharacteristic::kPropertyAuthenticatedSignedWrites) {
76 api_properties->push_back(
77 apibtle::CHARACTERISTIC_PROPERTY_AUTHENTICATEDSIGNEDWRITES);
79 if (properties & BluetoothGattCharacteristic::kPropertyExtendedProperties) {
80 api_properties->push_back(
81 apibtle::CHARACTERISTIC_PROPERTY_EXTENDEDPROPERTIES);
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);
91 void PopulateCharacteristic(const BluetoothGattCharacteristic* characteristic,
92 apibtle::Characteristic* out) {
95 out->uuid = characteristic->GetUUID().canonical_value();
96 out->is_local = characteristic->IsLocal();
97 out->instance_id.reset(new std::string(characteristic->GetIdentifier()));
99 PopulateService(characteristic->GetService(), &out->service);
100 PopulateCharacteristicProperties(characteristic->GetProperties(),
103 const std::vector<uint8>& value = characteristic->GetValue();
107 out->value.reset(new std::string(value.begin(), value.end()));
110 void PopulateDescriptor(const BluetoothGattDescriptor* descriptor,
111 apibtle::Descriptor* out) {
114 out->uuid = descriptor->GetUUID().canonical_value();
115 out->is_local = descriptor->IsLocal();
116 out->instance_id.reset(new std::string(descriptor->GetIdentifier()));
118 PopulateCharacteristic(descriptor->GetCharacteristic(), &out->characteristic);
120 const std::vector<uint8>& value = descriptor->GetValue();
124 out->value.reset(new std::string(value.begin(), value.end()));
127 typedef extensions::ApiResourceManager<extensions::BluetoothLowEnergyConnection>
128 ConnectionResourceManager;
129 ConnectionResourceManager* GetConnectionResourceManager(
130 content::BrowserContext* context) {
131 ConnectionResourceManager* manager = ConnectionResourceManager::Get(context);
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>.";
140 typedef extensions::ApiResourceManager<
141 extensions::BluetoothLowEnergyNotifySession> NotifySessionResourceManager;
142 NotifySessionResourceManager* GetNotifySessionResourceManager(
143 content::BrowserContext* context) {
144 NotifySessionResourceManager* manager =
145 NotifySessionResourceManager::Get(context);
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>.";
156 namespace extensions {
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.";
165 if (!IsBluetoothSupported()) {
166 VLOG(1) << "Bluetooth not supported on the current platform.";
171 BluetoothLowEnergyEventRouter::~BluetoothLowEnergyEventRouter() {
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
176 adapter_->RemoveObserver(this);
180 bool BluetoothLowEnergyEventRouter::IsBluetoothSupported() const {
181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
182 return adapter_.get() ||
183 BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
186 bool BluetoothLowEnergyEventRouter::InitializeAdapterAndInvokeCallback(
187 const base::Closure& callback) {
188 if (!IsBluetoothSupported())
191 if (adapter_.get()) {
196 BluetoothAdapterFactory::GetAdapter(
197 base::Bind(&BluetoothLowEnergyEventRouter::OnGetAdapter,
198 weak_ptr_factory_.GetWeakPtr(),
203 bool BluetoothLowEnergyEventRouter::HasAdapter() const {
204 return (adapter_.get() != NULL);
207 void BluetoothLowEnergyEventRouter::Connect(
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);
220 const std::string extension_id = extension->id();
221 const std::string connect_id = extension_id + device_address;
223 if (connecting_devices_.count(connect_id) != 0) {
224 error_callback.Run(kStatusErrorInProgress);
228 BluetoothLowEnergyConnection* conn =
229 FindConnection(extension_id, device_address);
231 if (conn->GetConnection()->IsConnected()) {
232 VLOG(1) << "Application already connected to device: " << device_address;
233 error_callback.Run(kStatusErrorAlreadyConnected);
237 // There is a connection object but it's no longer active. Simply remove it.
238 RemoveConnection(extension_id, device_address);
241 BluetoothDevice* device = adapter_->GetDevice(device_address);
243 VLOG(1) << "Bluetooth device not found: " << device_address;
244 error_callback.Run(kStatusErrorNotFound);
248 connecting_devices_.insert(connect_id);
249 device->CreateGattConnection(
250 base::Bind(&BluetoothLowEnergyEventRouter::OnCreateGattConnection,
251 weak_ptr_factory_.GetWeakPtr(),
256 base::Bind(&BluetoothLowEnergyEventRouter::OnConnectError,
257 weak_ptr_factory_.GetWeakPtr(),
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);
275 const std::string extension_id = extension->id();
276 const std::string disconnect_id = extension_id + device_address;
278 if (disconnecting_devices_.count(disconnect_id) != 0) {
279 error_callback.Run(kStatusErrorInProgress);
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);
291 disconnecting_devices_.insert(disconnect_id);
292 conn->GetConnection()->Disconnect(
293 base::Bind(&BluetoothLowEnergyEventRouter::OnDisconnect,
294 weak_ptr_factory_.GetWeakPtr(),
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.";
310 BluetoothDevice* device = adapter_->GetDevice(device_address);
312 VLOG(1) << "Bluetooth device not found: " << device_address;
316 out_services->clear();
318 const std::vector<BluetoothGattService*>& services =
319 device->GetGattServices();
320 for (std::vector<BluetoothGattService*>::const_iterator iter =
322 iter != services.end();
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());
329 out_services->push_back(api_service);
335 BluetoothLowEnergyEventRouter::Status BluetoothLowEnergyEventRouter::GetService(
336 const std::string& instance_id,
337 apibtle::Service* out_service) const {
338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
340 if (!adapter_.get()) {
341 VLOG(1) << "BluetoothAdapter not ready.";
342 return kStatusErrorFailed;
345 BluetoothGattService* gatt_service = FindServiceById(instance_id);
347 VLOG(1) << "Service not found: " << instance_id;
348 return kStatusErrorNotFound;
351 PopulateService(gatt_service, out_service);
352 return kStatusSuccess;
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;
366 BluetoothGattService* service = FindServiceById(instance_id);
368 VLOG(1) << "Service not found: " << instance_id;
369 return kStatusErrorNotFound;
372 out_services->clear();
374 const std::vector<BluetoothGattService*>& includes =
375 service->GetIncludedServices();
376 for (std::vector<BluetoothGattService*>::const_iterator iter =
378 iter != includes.end();
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());
385 out_services->push_back(api_service);
388 return kStatusSuccess;
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));
398 DCHECK(out_characteristics);
399 if (!adapter_.get()) {
400 VLOG(1) << "BlutoothAdapter not ready.";
401 return kStatusErrorFailed;
404 BluetoothGattService* service = FindServiceById(instance_id);
406 VLOG(1) << "Service not found: " << instance_id;
407 return kStatusErrorNotFound;
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;
417 out_characteristics->clear();
419 const std::vector<BluetoothGattCharacteristic*>& characteristics =
420 service->GetCharacteristics();
421 for (std::vector<BluetoothGattCharacteristic*>::const_iterator iter =
422 characteristics.begin();
423 iter != characteristics.end();
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());
431 out_characteristics->push_back(api_characteristic);
434 return kStatusSuccess;
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));
444 DCHECK(out_characteristic);
445 if (!adapter_.get()) {
446 VLOG(1) << "BluetoothAdapter not ready.";
447 return kStatusErrorFailed;
450 BluetoothGattCharacteristic* characteristic =
451 FindCharacteristicById(instance_id);
452 if (!characteristic) {
453 VLOG(1) << "Characteristic not found: " << instance_id;
454 return kStatusErrorNotFound;
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: "
462 return kStatusErrorPermissionDenied;
465 PopulateCharacteristic(characteristic, out_characteristic);
466 return kStatusSuccess;
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));
476 DCHECK(out_descriptors);
477 if (!adapter_.get()) {
478 VLOG(1) << "BlutoothAdapter not ready.";
479 return kStatusErrorFailed;
482 BluetoothGattCharacteristic* characteristic =
483 FindCharacteristicById(instance_id);
484 if (!characteristic) {
485 VLOG(1) << "Characteristic not found: " << instance_id;
486 return kStatusErrorNotFound;
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;
497 out_descriptors->clear();
499 const std::vector<BluetoothGattDescriptor*>& descriptors =
500 characteristic->GetDescriptors();
501 for (std::vector<BluetoothGattDescriptor*>::const_iterator iter =
503 iter != descriptors.end();
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());
510 out_descriptors->push_back(api_descriptor);
513 return kStatusSuccess;
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));
523 DCHECK(out_descriptor);
524 if (!adapter_.get()) {
525 VLOG(1) << "BluetoothAdapter not ready.";
526 return kStatusErrorFailed;
529 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
531 VLOG(1) << "Descriptor not found: " << instance_id;
532 return kStatusErrorNotFound;
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: "
540 return kStatusErrorPermissionDenied;
543 PopulateDescriptor(descriptor, out_descriptor);
544 return kStatusSuccess;
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));
554 if (!adapter_.get()) {
555 VLOG(1) << "BluetoothAdapter not ready.";
556 error_callback.Run(kStatusErrorFailed);
560 BluetoothGattCharacteristic* characteristic =
561 FindCharacteristicById(instance_id);
562 if (!characteristic) {
563 VLOG(1) << "Characteristic not found: " << instance_id;
564 error_callback.Run(kStatusErrorNotFound);
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: "
573 error_callback.Run(kStatusErrorPermissionDenied);
577 characteristic->ReadRemoteCharacteristic(
578 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
579 weak_ptr_factory_.GetWeakPtr(),
581 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
582 weak_ptr_factory_.GetWeakPtr(),
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));
594 if (!adapter_.get()) {
595 VLOG(1) << "BluetoothAdapter not ready.";
596 error_callback.Run(kStatusErrorFailed);
600 BluetoothGattCharacteristic* characteristic =
601 FindCharacteristicById(instance_id);
602 if (!characteristic) {
603 VLOG(1) << "Characteristic not found: " << instance_id;
604 error_callback.Run(kStatusErrorNotFound);
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: "
613 error_callback.Run(kStatusErrorPermissionDenied);
617 characteristic->WriteRemoteCharacteristic(
620 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
621 weak_ptr_factory_.GetWeakPtr(),
625 void BluetoothLowEnergyEventRouter::StartCharacteristicNotifications(
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);
638 const std::string extension_id = extension->id();
639 const std::string session_id = extension_id + instance_id;
641 if (pending_session_calls_.count(session_id) != 0) {
642 error_callback.Run(kStatusErrorInProgress);
646 BluetoothLowEnergyNotifySession* session =
647 FindNotifySession(extension_id, instance_id);
649 if (session->GetSession()->IsActive()) {
650 VLOG(1) << "Application has already enabled notifications from "
651 << "characteristic: " << instance_id;
652 error_callback.Run(kStatusErrorAlreadyNotifying);
656 RemoveNotifySession(extension_id, instance_id);
659 BluetoothGattCharacteristic* characteristic =
660 FindCharacteristicById(instance_id);
661 if (!characteristic) {
662 VLOG(1) << "Characteristic not found: " << instance_id;
663 error_callback.Run(kStatusErrorNotFound);
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: "
672 error_callback.Run(kStatusErrorPermissionDenied);
676 pending_session_calls_.insert(session_id);
677 characteristic->StartNotifySession(
678 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySession,
679 weak_ptr_factory_.GetWeakPtr(),
684 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySessionError,
685 weak_ptr_factory_.GetWeakPtr(),
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);
703 const std::string extension_id = extension->id();
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);
714 session->GetSession()->Stop(
715 base::Bind(&BluetoothLowEnergyEventRouter::OnStopNotifySession,
716 weak_ptr_factory_.GetWeakPtr(),
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));
729 if (!adapter_.get()) {
730 VLOG(1) << "BluetoothAdapter not ready.";
731 error_callback.Run(kStatusErrorFailed);
735 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
737 VLOG(1) << "Descriptor not found: " << instance_id;
738 error_callback.Run(kStatusErrorNotFound);
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: "
747 error_callback.Run(kStatusErrorPermissionDenied);
751 descriptor->ReadRemoteDescriptor(
752 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
753 weak_ptr_factory_.GetWeakPtr(),
755 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
756 weak_ptr_factory_.GetWeakPtr(),
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));
768 if (!adapter_.get()) {
769 VLOG(1) << "BluetoothAdapter not ready.";
770 error_callback.Run(kStatusErrorFailed);
774 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
776 VLOG(1) << "Descriptor not found: " << instance_id;
777 error_callback.Run(kStatusErrorNotFound);
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: "
786 error_callback.Run(kStatusErrorPermissionDenied);
790 descriptor->WriteRemoteDescriptor(
793 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
794 weak_ptr_factory_.GetWeakPtr(),
798 void BluetoothLowEnergyEventRouter::SetAdapterForTesting(
799 device::BluetoothAdapter* adapter) {
801 InitializeIdentifierMappings();
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();
812 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) ==
813 service_id_to_device_address_.end());
815 service_id_to_device_address_[service->GetIdentifier()] =
816 device->GetAddress();
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();
827 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
828 service_id_to_device_address_.end());
830 DCHECK(device->GetAddress() ==
831 service_id_to_device_address_[service->GetIdentifier()]);
832 service_id_to_device_address_.erase(service->GetIdentifier());
835 apibtle::Service api_service;
836 PopulateService(service, &api_service);
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());
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();
852 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
853 service_id_to_device_address_.end());
855 // Signal the service added event here.
856 apibtle::Service api_service;
857 PopulateService(service, &api_service);
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());
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());
876 apibtle::Service api_service;
877 PopulateService(service, &api_service);
879 DispatchEventToExtensionsWithPermission(
880 apibtle::OnServiceChanged::kEventName,
882 "" /* characteristic_id */,
883 apibtle::OnServiceChanged::Create(api_service));
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();
893 BluetoothGattService* service = characteristic->GetService();
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());
901 chrc_id_to_service_id_[characteristic->GetIdentifier()] =
902 service->GetIdentifier();
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();
912 BluetoothGattService* service = characteristic->GetService();
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()]);
920 chrc_id_to_service_id_.erase(characteristic->GetIdentifier());
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();
930 BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic();
931 DCHECK(characteristic);
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());
938 desc_id_to_chrc_id_[descriptor->GetIdentifier()] =
939 characteristic->GetIdentifier();
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();
949 BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic();
950 DCHECK(characteristic);
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()]);
957 desc_id_to_chrc_id_.erase(descriptor->GetIdentifier());
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();
969 BluetoothGattService* service = characteristic->GetService();
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());
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());
987 DispatchEventToExtensionsWithPermission(
988 apibtle::OnCharacteristicValueChanged::kEventName,
990 characteristic->GetIdentifier(),
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();
1002 BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic();
1003 DCHECK(characteristic);
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()]);
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());
1018 DispatchEventToExtensionsWithPermission(
1019 apibtle::OnDescriptorValueChanged::kEventName,
1020 characteristic->GetService()->GetUUID(),
1021 "" /* characteristic_id */,
1025 void BluetoothLowEnergyEventRouter::OnGetAdapter(
1026 const base::Closure& callback,
1027 scoped_refptr<device::BluetoothAdapter> adapter) {
1030 // Initialize instance ID mappings for all discovered GATT objects and add
1032 InitializeIdentifierMappings();
1033 adapter_->AddObserver(this);
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());
1044 BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
1045 for (BluetoothAdapter::DeviceList::iterator iter = devices.begin();
1046 iter != devices.end();
1048 BluetoothDevice* device = *iter;
1051 std::vector<BluetoothGattService*> services = device->GetGattServices();
1052 for (std::vector<BluetoothGattService*>::iterator siter = services.begin();
1053 siter != services.end();
1055 BluetoothGattService* service = *siter;
1057 const std::string& service_id = service->GetIdentifier();
1058 service_id_to_device_address_[service_id] = device->GetAddress();
1061 const std::vector<BluetoothGattCharacteristic*>& characteristics =
1062 service->GetCharacteristics();
1063 for (std::vector<BluetoothGattCharacteristic*>::const_iterator citer =
1064 characteristics.begin();
1065 citer != characteristics.end();
1067 BluetoothGattCharacteristic* characteristic = *citer;
1069 const std::string& chrc_id = characteristic->GetIdentifier();
1070 chrc_id_to_service_id_[chrc_id] = service_id;
1073 const std::vector<BluetoothGattDescriptor*>& descriptors =
1074 characteristic->GetDescriptors();
1075 for (std::vector<BluetoothGattDescriptor*>::const_iterator diter =
1076 descriptors.begin();
1077 diter != descriptors.end();
1079 BluetoothGattDescriptor* descriptor = *diter;
1081 const std::string& desc_id = descriptor->GetIdentifier();
1082 desc_id_to_chrc_id_[desc_id] = chrc_id;
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
1098 BluetoothPermissionRequest request(uuid.value());
1099 std::set<std::string> handled_extensions;
1100 const EventListenerMap::ListenerList listeners =
1101 EventRouter::Get(browser_context_)->listeners().GetEventListenersByName(
1104 for (EventListenerMap::ListenerList::const_iterator iter = listeners.begin();
1105 iter != listeners.end();
1107 const std::string extension_id = (*iter)->extension_id();
1108 if (handled_extensions.find(extension_id) != handled_extensions.end())
1111 handled_extensions.insert(extension_id);
1113 const Extension* extension =
1114 ExtensionRegistry::Get(browser_context_)
1115 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
1117 // For all API methods, the "low_energy" permission check is handled by
1118 // BluetoothLowEnergyExtensionFunction but for events we have to do the
1120 if (!BluetoothManifestData::CheckRequest(extension, request) ||
1121 !BluetoothManifestData::CheckLowEnergyPermitted(extension))
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))
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());
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;
1149 const std::string& address = iter->second;
1151 BluetoothDevice* device = adapter_->GetDevice(address);
1153 VLOG(1) << "Bluetooth device not found: " << address;
1157 BluetoothGattService* service = device->GetGattService(instance_id);
1159 VLOG(1) << "GATT service with ID \"" << instance_id
1160 << "\" not found on device \"" << address << "\"";
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;
1176 const std::string& service_id = iter->second;
1178 BluetoothGattService* service = FindServiceById(service_id);
1180 VLOG(1) << "Failed to obtain service for characteristic: " << instance_id;
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 << "\"";
1192 return characteristic;
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;
1203 const std::string& chrc_id = iter->second;
1204 BluetoothGattCharacteristic* chrc = FindCharacteristicById(chrc_id);
1206 VLOG(1) << "Failed to obtain characteristic for descriptor: "
1211 BluetoothGattDescriptor* descriptor = chrc->GetDescriptor(instance_id);
1213 VLOG(1) << "GATT descriptor with ID \"" << instance_id
1214 << "\" not found on characteristic \"" << chrc_id << "\"";
1221 void BluetoothLowEnergyEventRouter::OnValueSuccess(
1222 const base::Closure& callback,
1223 const std::vector<uint8>& value) {
1224 VLOG(2) << "Remote characteristic/descriptor value read successful.";
1228 void BluetoothLowEnergyEventRouter::OnCreateGattConnection(
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());
1239 const std::string connect_id = extension_id + device_address;
1240 DCHECK_NE(0U, connecting_devices_.count(connect_id));
1242 BluetoothLowEnergyConnection* conn = new BluetoothLowEnergyConnection(
1243 persistent, extension_id, connection.Pass());
1244 ConnectionResourceManager* manager =
1245 GetConnectionResourceManager(browser_context_);
1248 connecting_devices_.erase(connect_id);
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.";
1258 const std::string disconnect_id = extension_id + device_address;
1259 DCHECK_NE(0U, disconnecting_devices_.count(disconnect_id));
1261 if (!RemoveConnection(extension_id, device_address)) {
1262 VLOG(1) << "The connection was removed before disconnect completed, id: "
1263 << extension_id << ", device: " << device_address;
1266 disconnecting_devices_.erase(disconnect_id);
1270 void BluetoothLowEnergyEventRouter::OnError(
1271 const ErrorCallback& error_callback) {
1272 VLOG(2) << "Remote characteristic/descriptor value read/write failed.";
1273 error_callback.Run(kStatusErrorFailed);
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;
1283 const std::string connect_id = extension_id + device_address;
1284 DCHECK_NE(0U, connecting_devices_.count(connect_id));
1286 connecting_devices_.erase(connect_id);
1287 error_callback.Run(kStatusErrorFailed);
1290 void BluetoothLowEnergyEventRouter::OnStartNotifySession(
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());
1302 const std::string session_id = extension_id + characteristic_id;
1303 DCHECK_NE(0U, pending_session_calls_.count(session_id));
1305 BluetoothLowEnergyNotifySession* resource =
1306 new BluetoothLowEnergyNotifySession(
1307 persistent, extension_id, session.Pass());
1309 NotifySessionResourceManager* manager =
1310 GetNotifySessionResourceManager(browser_context_);
1311 manager->Add(resource);
1313 pending_session_calls_.erase(session_id);
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;
1324 const std::string session_id = extension_id + characteristic_id;
1325 DCHECK_NE(0U, pending_session_calls_.count(session_id));
1327 pending_session_calls_.erase(session_id);
1328 error_callback.Run(kStatusErrorFailed);
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.";
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;
1346 BluetoothLowEnergyConnection* BluetoothLowEnergyEventRouter::FindConnection(
1347 const std::string& extension_id,
1348 const std::string& device_address) {
1349 ConnectionResourceManager* manager =
1350 GetConnectionResourceManager(browser_context_);
1352 base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
1353 if (!connection_ids)
1356 for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
1357 iter != connection_ids->end();
1359 extensions::BluetoothLowEnergyConnection* conn =
1360 manager->Get(extension_id, *iter);
1364 if (conn->GetConnection()->GetDeviceAddress() == device_address)
1371 bool BluetoothLowEnergyEventRouter::RemoveConnection(
1372 const std::string& extension_id,
1373 const std::string& device_address) {
1374 ConnectionResourceManager* manager =
1375 GetConnectionResourceManager(browser_context_);
1377 base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
1378 if (!connection_ids)
1381 for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
1382 iter != connection_ids->end();
1384 extensions::BluetoothLowEnergyConnection* conn =
1385 manager->Get(extension_id, *iter);
1386 if (!conn || conn->GetConnection()->GetDeviceAddress() != device_address)
1389 manager->Remove(extension_id, *iter);
1396 BluetoothLowEnergyNotifySession*
1397 BluetoothLowEnergyEventRouter::FindNotifySession(
1398 const std::string& extension_id,
1399 const std::string& characteristic_id) {
1400 NotifySessionResourceManager* manager =
1401 GetNotifySessionResourceManager(browser_context_);
1403 base::hash_set<int>* ids = manager->GetResourceIds(extension_id);
1407 for (base::hash_set<int>::const_iterator iter = ids->begin();
1410 BluetoothLowEnergyNotifySession* session =
1411 manager->Get(extension_id, *iter);
1415 if (session->GetSession()->GetCharacteristicIdentifier() ==
1423 bool BluetoothLowEnergyEventRouter::RemoveNotifySession(
1424 const std::string& extension_id,
1425 const std::string& characteristic_id) {
1426 NotifySessionResourceManager* manager =
1427 GetNotifySessionResourceManager(browser_context_);
1429 base::hash_set<int>* ids = manager->GetResourceIds(extension_id);
1433 for (base::hash_set<int>::const_iterator iter = ids->begin();
1436 BluetoothLowEnergyNotifySession* session =
1437 manager->Get(extension_id, *iter);
1439 session->GetSession()->GetCharacteristicIdentifier() !=
1443 manager->Remove(extension_id, *iter);
1450 } // namespace extensions