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::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::PROPERTY_NONE
)
60 if (properties
& BluetoothGattCharacteristic::PROPERTY_BROADCAST
)
61 api_properties
->push_back(apibtle::CHARACTERISTIC_PROPERTY_BROADCAST
);
62 if (properties
& BluetoothGattCharacteristic::PROPERTY_READ
)
63 api_properties
->push_back(apibtle::CHARACTERISTIC_PROPERTY_READ
);
65 BluetoothGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE
) {
66 api_properties
->push_back(
67 apibtle::CHARACTERISTIC_PROPERTY_WRITEWITHOUTRESPONSE
);
69 if (properties
& BluetoothGattCharacteristic::PROPERTY_WRITE
)
70 api_properties
->push_back(apibtle::CHARACTERISTIC_PROPERTY_WRITE
);
71 if (properties
& BluetoothGattCharacteristic::PROPERTY_NOTIFY
)
72 api_properties
->push_back(apibtle::CHARACTERISTIC_PROPERTY_NOTIFY
);
73 if (properties
& BluetoothGattCharacteristic::PROPERTY_INDICATE
)
74 api_properties
->push_back(apibtle::CHARACTERISTIC_PROPERTY_INDICATE
);
76 BluetoothGattCharacteristic::PROPERTY_AUTHENTICATED_SIGNED_WRITES
) {
77 api_properties
->push_back(
78 apibtle::CHARACTERISTIC_PROPERTY_AUTHENTICATEDSIGNEDWRITES
);
80 if (properties
& BluetoothGattCharacteristic::PROPERTY_EXTENDED_PROPERTIES
) {
81 api_properties
->push_back(
82 apibtle::CHARACTERISTIC_PROPERTY_EXTENDEDPROPERTIES
);
84 if (properties
& BluetoothGattCharacteristic::PROPERTY_RELIABLE_WRITE
)
85 api_properties
->push_back(apibtle::CHARACTERISTIC_PROPERTY_RELIABLEWRITE
);
86 if (properties
& BluetoothGattCharacteristic::PROPERTY_WRITABLE_AUXILIARIES
) {
87 api_properties
->push_back(
88 apibtle::CHARACTERISTIC_PROPERTY_WRITABLEAUXILIARIES
);
92 void PopulateCharacteristic(const BluetoothGattCharacteristic
* characteristic
,
93 apibtle::Characteristic
* out
) {
96 out
->uuid
= characteristic
->GetUUID().canonical_value();
97 out
->is_local
= characteristic
->IsLocal();
98 out
->instance_id
.reset(new std::string(characteristic
->GetIdentifier()));
100 PopulateService(characteristic
->GetService(), &out
->service
);
101 PopulateCharacteristicProperties(characteristic
->GetProperties(),
104 const std::vector
<uint8
>& value
= characteristic
->GetValue();
108 out
->value
.reset(new std::vector
<char>(value
.begin(), value
.end()));
111 void PopulateDescriptor(const BluetoothGattDescriptor
* descriptor
,
112 apibtle::Descriptor
* out
) {
115 out
->uuid
= descriptor
->GetUUID().canonical_value();
116 out
->is_local
= descriptor
->IsLocal();
117 out
->instance_id
.reset(new std::string(descriptor
->GetIdentifier()));
119 PopulateCharacteristic(descriptor
->GetCharacteristic(), &out
->characteristic
);
121 const std::vector
<uint8
>& value
= descriptor
->GetValue();
125 out
->value
.reset(new std::vector
<char>(value
.begin(), value
.end()));
128 typedef extensions::ApiResourceManager
<extensions::BluetoothLowEnergyConnection
>
129 ConnectionResourceManager
;
130 ConnectionResourceManager
* GetConnectionResourceManager(
131 content::BrowserContext
* context
) {
132 ConnectionResourceManager
* manager
= ConnectionResourceManager::Get(context
);
134 << "There is no Bluetooth low energy connection manager. "
135 "If this assertion is failing during a test, then it is likely that "
136 "TestExtensionSystem is failing to provide an instance of "
137 "ApiResourceManager<BluetoothLowEnergyConnection>.";
141 typedef extensions::ApiResourceManager
<
142 extensions::BluetoothLowEnergyNotifySession
> NotifySessionResourceManager
;
143 NotifySessionResourceManager
* GetNotifySessionResourceManager(
144 content::BrowserContext
* context
) {
145 NotifySessionResourceManager
* manager
=
146 NotifySessionResourceManager::Get(context
);
148 << "There is no Bluetooth low energy value update session manager."
149 "If this assertion is failing during a test, then it is likely that "
150 "TestExtensionSystem is failing to provide an instance of "
151 "ApiResourceManager<BluetoothLowEnergyNotifySession>.";
155 // Translates GattErrorCodes to RouterError Codes
156 extensions::BluetoothLowEnergyEventRouter::Status
GattErrorToRouterError(
157 BluetoothGattService::GattErrorCode error_code
) {
158 extensions::BluetoothLowEnergyEventRouter::Status error_status
=
159 extensions::BluetoothLowEnergyEventRouter::kStatusErrorFailed
;
160 if (error_code
== BluetoothGattService::GATT_ERROR_IN_PROGRESS
) {
162 extensions::BluetoothLowEnergyEventRouter::kStatusErrorInProgress
;
163 } else if (error_code
== BluetoothGattService::GATT_ERROR_INVALID_LENGTH
) {
165 extensions::BluetoothLowEnergyEventRouter::kStatusErrorInvalidLength
;
166 } else if (error_code
== BluetoothGattService::GATT_ERROR_NOT_PERMITTED
) {
168 extensions::BluetoothLowEnergyEventRouter::kStatusErrorPermissionDenied
;
169 } else if (error_code
== BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED
) {
170 error_status
= extensions::BluetoothLowEnergyEventRouter::
171 kStatusErrorInsufficientAuthorization
;
172 } else if (error_code
== BluetoothGattService::GATT_ERROR_NOT_PAIRED
) {
174 extensions::BluetoothLowEnergyEventRouter::kStatusErrorHigherSecurity
;
175 } else if (error_code
== BluetoothGattService::GATT_ERROR_NOT_SUPPORTED
) {
177 extensions::BluetoothLowEnergyEventRouter::kStatusErrorGattNotSupported
;
185 namespace extensions
{
187 BluetoothLowEnergyEventRouter::BluetoothLowEnergyEventRouter(
188 content::BrowserContext
* context
)
189 : adapter_(NULL
), browser_context_(context
), weak_ptr_factory_(this) {
190 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
191 DCHECK(browser_context_
);
192 VLOG(1) << "Initializing BluetoothLowEnergyEventRouter.";
194 if (!IsBluetoothSupported()) {
195 VLOG(1) << "Bluetooth not supported on the current platform.";
200 BluetoothLowEnergyEventRouter::~BluetoothLowEnergyEventRouter() {
201 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
205 adapter_
->RemoveObserver(this);
209 bool BluetoothLowEnergyEventRouter::IsBluetoothSupported() const {
210 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
211 return adapter_
.get() ||
212 BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
215 bool BluetoothLowEnergyEventRouter::InitializeAdapterAndInvokeCallback(
216 const base::Closure
& callback
) {
217 if (!IsBluetoothSupported())
220 if (adapter_
.get()) {
225 BluetoothAdapterFactory::GetAdapter(
226 base::Bind(&BluetoothLowEnergyEventRouter::OnGetAdapter
,
227 weak_ptr_factory_
.GetWeakPtr(),
232 bool BluetoothLowEnergyEventRouter::HasAdapter() const {
233 return (adapter_
.get() != NULL
);
236 void BluetoothLowEnergyEventRouter::Connect(
238 const Extension
* extension
,
239 const std::string
& device_address
,
240 const base::Closure
& callback
,
241 const ErrorCallback
& error_callback
) {
242 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
243 if (!adapter_
.get()) {
244 VLOG(1) << "BluetoothAdapter not ready.";
245 error_callback
.Run(kStatusErrorFailed
);
249 const std::string extension_id
= extension
->id();
250 const std::string connect_id
= extension_id
+ device_address
;
252 if (connecting_devices_
.count(connect_id
) != 0) {
253 error_callback
.Run(kStatusErrorInProgress
);
257 BluetoothLowEnergyConnection
* conn
=
258 FindConnection(extension_id
, device_address
);
260 if (conn
->GetConnection()->IsConnected()) {
261 VLOG(1) << "Application already connected to device: " << device_address
;
262 error_callback
.Run(kStatusErrorAlreadyConnected
);
266 // There is a connection object but it's no longer active. Simply remove it.
267 RemoveConnection(extension_id
, device_address
);
270 BluetoothDevice
* device
= adapter_
->GetDevice(device_address
);
272 VLOG(1) << "Bluetooth device not found: " << device_address
;
273 error_callback
.Run(kStatusErrorNotFound
);
277 connecting_devices_
.insert(connect_id
);
278 device
->CreateGattConnection(
279 base::Bind(&BluetoothLowEnergyEventRouter::OnCreateGattConnection
,
280 weak_ptr_factory_
.GetWeakPtr(),
285 base::Bind(&BluetoothLowEnergyEventRouter::OnConnectError
,
286 weak_ptr_factory_
.GetWeakPtr(),
292 void BluetoothLowEnergyEventRouter::Disconnect(
293 const Extension
* extension
,
294 const std::string
& device_address
,
295 const base::Closure
& callback
,
296 const ErrorCallback
& error_callback
) {
297 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
298 if (!adapter_
.get()) {
299 VLOG(1) << "BluetoothAdapter not ready.";
300 error_callback
.Run(kStatusErrorFailed
);
304 const std::string extension_id
= extension
->id();
305 const std::string disconnect_id
= extension_id
+ device_address
;
307 if (disconnecting_devices_
.count(disconnect_id
) != 0) {
308 error_callback
.Run(kStatusErrorInProgress
);
312 BluetoothLowEnergyConnection
* conn
=
313 FindConnection(extension_id
, device_address
);
314 if (!conn
|| !conn
->GetConnection()->IsConnected()) {
315 VLOG(1) << "Application not connected to device: " << device_address
;
316 error_callback
.Run(kStatusErrorNotConnected
);
320 disconnecting_devices_
.insert(disconnect_id
);
321 conn
->GetConnection()->Disconnect(
322 base::Bind(&BluetoothLowEnergyEventRouter::OnDisconnect
,
323 weak_ptr_factory_
.GetWeakPtr(),
329 bool BluetoothLowEnergyEventRouter::GetServices(
330 const std::string
& device_address
,
331 ServiceList
* out_services
) const {
332 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
333 DCHECK(out_services
);
334 if (!adapter_
.get()) {
335 VLOG(1) << "BluetoothAdapter not ready.";
339 BluetoothDevice
* device
= adapter_
->GetDevice(device_address
);
341 VLOG(1) << "Bluetooth device not found: " << device_address
;
345 out_services
->clear();
347 const std::vector
<BluetoothGattService
*>& services
=
348 device
->GetGattServices();
349 for (std::vector
<BluetoothGattService
*>::const_iterator iter
=
351 iter
!= services
.end();
353 // Populate an API service and add it to the return value.
354 const BluetoothGattService
* service
= *iter
;
355 linked_ptr
<apibtle::Service
> api_service(new apibtle::Service());
356 PopulateService(service
, api_service
.get());
358 out_services
->push_back(api_service
);
364 BluetoothLowEnergyEventRouter::Status
BluetoothLowEnergyEventRouter::GetService(
365 const std::string
& instance_id
,
366 apibtle::Service
* out_service
) const {
367 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
369 if (!adapter_
.get()) {
370 VLOG(1) << "BluetoothAdapter not ready.";
371 return kStatusErrorFailed
;
374 BluetoothGattService
* gatt_service
= FindServiceById(instance_id
);
376 VLOG(1) << "Service not found: " << instance_id
;
377 return kStatusErrorNotFound
;
380 PopulateService(gatt_service
, out_service
);
381 return kStatusSuccess
;
384 BluetoothLowEnergyEventRouter::Status
385 BluetoothLowEnergyEventRouter::GetIncludedServices(
386 const std::string
& instance_id
,
387 ServiceList
* out_services
) const {
388 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
389 DCHECK(out_services
);
390 if (!adapter_
.get()) {
391 VLOG(1) << "BluetoothAdapter not ready.";
392 return kStatusErrorFailed
;
395 BluetoothGattService
* service
= FindServiceById(instance_id
);
397 VLOG(1) << "Service not found: " << instance_id
;
398 return kStatusErrorNotFound
;
401 out_services
->clear();
403 const std::vector
<BluetoothGattService
*>& includes
=
404 service
->GetIncludedServices();
405 for (std::vector
<BluetoothGattService
*>::const_iterator iter
=
407 iter
!= includes
.end();
409 // Populate an API service and add it to the return value.
410 const BluetoothGattService
* included
= *iter
;
411 linked_ptr
<apibtle::Service
> api_service(new apibtle::Service());
412 PopulateService(included
, api_service
.get());
414 out_services
->push_back(api_service
);
417 return kStatusSuccess
;
420 BluetoothLowEnergyEventRouter::Status
421 BluetoothLowEnergyEventRouter::GetCharacteristics(
422 const Extension
* extension
,
423 const std::string
& instance_id
,
424 CharacteristicList
* out_characteristics
) const {
425 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
427 DCHECK(out_characteristics
);
428 if (!adapter_
.get()) {
429 VLOG(1) << "BlutoothAdapter not ready.";
430 return kStatusErrorFailed
;
433 BluetoothGattService
* service
= FindServiceById(instance_id
);
435 VLOG(1) << "Service not found: " << instance_id
;
436 return kStatusErrorNotFound
;
439 BluetoothPermissionRequest
request(service
->GetUUID().value());
440 if (!BluetoothManifestData::CheckRequest(extension
, request
)) {
441 VLOG(1) << "App has no permission to access the characteristics of this "
442 << "service: " << instance_id
;
443 return kStatusErrorPermissionDenied
;
446 out_characteristics
->clear();
448 const std::vector
<BluetoothGattCharacteristic
*>& characteristics
=
449 service
->GetCharacteristics();
450 for (std::vector
<BluetoothGattCharacteristic
*>::const_iterator iter
=
451 characteristics
.begin();
452 iter
!= characteristics
.end();
454 // Populate an API characteristic and add it to the return value.
455 const BluetoothGattCharacteristic
* characteristic
= *iter
;
456 linked_ptr
<apibtle::Characteristic
> api_characteristic(
457 new apibtle::Characteristic());
458 PopulateCharacteristic(characteristic
, api_characteristic
.get());
460 out_characteristics
->push_back(api_characteristic
);
463 return kStatusSuccess
;
466 BluetoothLowEnergyEventRouter::Status
467 BluetoothLowEnergyEventRouter::GetCharacteristic(
468 const Extension
* extension
,
469 const std::string
& instance_id
,
470 apibtle::Characteristic
* out_characteristic
) const {
471 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
473 DCHECK(out_characteristic
);
474 if (!adapter_
.get()) {
475 VLOG(1) << "BluetoothAdapter not ready.";
476 return kStatusErrorFailed
;
479 BluetoothGattCharacteristic
* characteristic
=
480 FindCharacteristicById(instance_id
);
481 if (!characteristic
) {
482 VLOG(1) << "Characteristic not found: " << instance_id
;
483 return kStatusErrorNotFound
;
486 BluetoothPermissionRequest
request(
487 characteristic
->GetService()->GetUUID().value());
488 if (!BluetoothManifestData::CheckRequest(extension
, request
)) {
489 VLOG(1) << "App has no permission to access this characteristic: "
491 return kStatusErrorPermissionDenied
;
494 PopulateCharacteristic(characteristic
, out_characteristic
);
495 return kStatusSuccess
;
498 BluetoothLowEnergyEventRouter::Status
499 BluetoothLowEnergyEventRouter::GetDescriptors(
500 const Extension
* extension
,
501 const std::string
& instance_id
,
502 DescriptorList
* out_descriptors
) const {
503 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
505 DCHECK(out_descriptors
);
506 if (!adapter_
.get()) {
507 VLOG(1) << "BlutoothAdapter not ready.";
508 return kStatusErrorFailed
;
511 BluetoothGattCharacteristic
* characteristic
=
512 FindCharacteristicById(instance_id
);
513 if (!characteristic
) {
514 VLOG(1) << "Characteristic not found: " << instance_id
;
515 return kStatusErrorNotFound
;
518 BluetoothPermissionRequest
request(
519 characteristic
->GetService()->GetUUID().value());
520 if (!BluetoothManifestData::CheckRequest(extension
, request
)) {
521 VLOG(1) << "App has no permission to access the descriptors of this "
522 << "characteristic: " << instance_id
;
523 return kStatusErrorPermissionDenied
;
526 out_descriptors
->clear();
528 const std::vector
<BluetoothGattDescriptor
*>& descriptors
=
529 characteristic
->GetDescriptors();
530 for (std::vector
<BluetoothGattDescriptor
*>::const_iterator iter
=
532 iter
!= descriptors
.end();
534 // Populate an API descriptor and add it to the return value.
535 const BluetoothGattDescriptor
* descriptor
= *iter
;
536 linked_ptr
<apibtle::Descriptor
> api_descriptor(new apibtle::Descriptor());
537 PopulateDescriptor(descriptor
, api_descriptor
.get());
539 out_descriptors
->push_back(api_descriptor
);
542 return kStatusSuccess
;
545 BluetoothLowEnergyEventRouter::Status
546 BluetoothLowEnergyEventRouter::GetDescriptor(
547 const Extension
* extension
,
548 const std::string
& instance_id
,
549 api::bluetooth_low_energy::Descriptor
* out_descriptor
) const {
550 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
552 DCHECK(out_descriptor
);
553 if (!adapter_
.get()) {
554 VLOG(1) << "BluetoothAdapter not ready.";
555 return kStatusErrorFailed
;
558 BluetoothGattDescriptor
* descriptor
= FindDescriptorById(instance_id
);
560 VLOG(1) << "Descriptor not found: " << instance_id
;
561 return kStatusErrorNotFound
;
564 BluetoothPermissionRequest
request(
565 descriptor
->GetCharacteristic()->GetService()->GetUUID().value());
566 if (!BluetoothManifestData::CheckRequest(extension
, request
)) {
567 VLOG(1) << "App has no permission to access this descriptor: "
569 return kStatusErrorPermissionDenied
;
572 PopulateDescriptor(descriptor
, out_descriptor
);
573 return kStatusSuccess
;
576 void BluetoothLowEnergyEventRouter::ReadCharacteristicValue(
577 const Extension
* extension
,
578 const std::string
& instance_id
,
579 const base::Closure
& callback
,
580 const ErrorCallback
& error_callback
) {
581 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
583 if (!adapter_
.get()) {
584 VLOG(1) << "BluetoothAdapter not ready.";
585 error_callback
.Run(kStatusErrorFailed
);
589 BluetoothGattCharacteristic
* characteristic
=
590 FindCharacteristicById(instance_id
);
591 if (!characteristic
) {
592 VLOG(1) << "Characteristic not found: " << instance_id
;
593 error_callback
.Run(kStatusErrorNotFound
);
597 BluetoothPermissionRequest
request(
598 characteristic
->GetService()->GetUUID().value());
599 if (!BluetoothManifestData::CheckRequest(extension
, request
)) {
600 VLOG(1) << "App has no permission to access this characteristic: "
602 error_callback
.Run(kStatusErrorPermissionDenied
);
606 characteristic
->ReadRemoteCharacteristic(
607 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess
,
608 weak_ptr_factory_
.GetWeakPtr(),
610 base::Bind(&BluetoothLowEnergyEventRouter::OnError
,
611 weak_ptr_factory_
.GetWeakPtr(),
615 void BluetoothLowEnergyEventRouter::WriteCharacteristicValue(
616 const Extension
* extension
,
617 const std::string
& instance_id
,
618 const std::vector
<uint8
>& value
,
619 const base::Closure
& callback
,
620 const ErrorCallback
& error_callback
) {
621 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
623 if (!adapter_
.get()) {
624 VLOG(1) << "BluetoothAdapter not ready.";
625 error_callback
.Run(kStatusErrorFailed
);
629 BluetoothGattCharacteristic
* characteristic
=
630 FindCharacteristicById(instance_id
);
631 if (!characteristic
) {
632 VLOG(1) << "Characteristic not found: " << instance_id
;
633 error_callback
.Run(kStatusErrorNotFound
);
637 BluetoothPermissionRequest
request(
638 characteristic
->GetService()->GetUUID().value());
639 if (!BluetoothManifestData::CheckRequest(extension
, request
)) {
640 VLOG(1) << "App has no permission to access this characteristic: "
642 error_callback
.Run(kStatusErrorPermissionDenied
);
646 characteristic
->WriteRemoteCharacteristic(
649 base::Bind(&BluetoothLowEnergyEventRouter::OnError
,
650 weak_ptr_factory_
.GetWeakPtr(),
654 void BluetoothLowEnergyEventRouter::StartCharacteristicNotifications(
656 const Extension
* extension
,
657 const std::string
& instance_id
,
658 const base::Closure
& callback
,
659 const ErrorCallback
& error_callback
) {
660 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
661 if (!adapter_
.get()) {
662 VLOG(1) << "BluetoothAdapter not ready.";
663 error_callback
.Run(kStatusErrorFailed
);
667 const std::string extension_id
= extension
->id();
668 const std::string session_id
= extension_id
+ instance_id
;
670 if (pending_session_calls_
.count(session_id
) != 0) {
671 error_callback
.Run(kStatusErrorInProgress
);
675 BluetoothLowEnergyNotifySession
* session
=
676 FindNotifySession(extension_id
, instance_id
);
678 if (session
->GetSession()->IsActive()) {
679 VLOG(1) << "Application has already enabled notifications from "
680 << "characteristic: " << instance_id
;
681 error_callback
.Run(kStatusErrorAlreadyNotifying
);
685 RemoveNotifySession(extension_id
, instance_id
);
688 BluetoothGattCharacteristic
* characteristic
=
689 FindCharacteristicById(instance_id
);
690 if (!characteristic
) {
691 VLOG(1) << "Characteristic not found: " << instance_id
;
692 error_callback
.Run(kStatusErrorNotFound
);
696 BluetoothPermissionRequest
request(
697 characteristic
->GetService()->GetUUID().value());
698 if (!BluetoothManifestData::CheckRequest(extension
, request
)) {
699 VLOG(1) << "App has no permission to access this characteristic: "
701 error_callback
.Run(kStatusErrorPermissionDenied
);
705 pending_session_calls_
.insert(session_id
);
706 characteristic
->StartNotifySession(
707 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySession
,
708 weak_ptr_factory_
.GetWeakPtr(),
713 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySessionError
,
714 weak_ptr_factory_
.GetWeakPtr(),
720 void BluetoothLowEnergyEventRouter::StopCharacteristicNotifications(
721 const Extension
* extension
,
722 const std::string
& instance_id
,
723 const base::Closure
& callback
,
724 const ErrorCallback
& error_callback
) {
725 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
726 if (!adapter_
.get()) {
727 VLOG(1) << "BluetoothAdapter not ready.";
728 error_callback
.Run(kStatusErrorFailed
);
732 const std::string extension_id
= extension
->id();
734 BluetoothLowEnergyNotifySession
* session
=
735 FindNotifySession(extension_id
, instance_id
);
736 if (!session
|| !session
->GetSession()->IsActive()) {
737 VLOG(1) << "Application has not enabled notifications from "
738 << "characteristic: " << instance_id
;
739 error_callback
.Run(kStatusErrorNotNotifying
);
743 session
->GetSession()->Stop(
744 base::Bind(&BluetoothLowEnergyEventRouter::OnStopNotifySession
,
745 weak_ptr_factory_
.GetWeakPtr(),
751 void BluetoothLowEnergyEventRouter::ReadDescriptorValue(
752 const Extension
* extension
,
753 const std::string
& instance_id
,
754 const base::Closure
& callback
,
755 const ErrorCallback
& error_callback
) {
756 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
758 if (!adapter_
.get()) {
759 VLOG(1) << "BluetoothAdapter not ready.";
760 error_callback
.Run(kStatusErrorFailed
);
764 BluetoothGattDescriptor
* descriptor
= FindDescriptorById(instance_id
);
766 VLOG(1) << "Descriptor not found: " << instance_id
;
767 error_callback
.Run(kStatusErrorNotFound
);
771 BluetoothPermissionRequest
request(
772 descriptor
->GetCharacteristic()->GetService()->GetUUID().value());
773 if (!BluetoothManifestData::CheckRequest(extension
, request
)) {
774 VLOG(1) << "App has no permission to access this descriptor: "
776 error_callback
.Run(kStatusErrorPermissionDenied
);
780 descriptor
->ReadRemoteDescriptor(
781 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess
,
782 weak_ptr_factory_
.GetWeakPtr(),
784 base::Bind(&BluetoothLowEnergyEventRouter::OnError
,
785 weak_ptr_factory_
.GetWeakPtr(),
789 void BluetoothLowEnergyEventRouter::WriteDescriptorValue(
790 const Extension
* extension
,
791 const std::string
& instance_id
,
792 const std::vector
<uint8
>& value
,
793 const base::Closure
& callback
,
794 const ErrorCallback
& error_callback
) {
795 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
797 if (!adapter_
.get()) {
798 VLOG(1) << "BluetoothAdapter not ready.";
799 error_callback
.Run(kStatusErrorFailed
);
803 BluetoothGattDescriptor
* descriptor
= FindDescriptorById(instance_id
);
805 VLOG(1) << "Descriptor not found: " << instance_id
;
806 error_callback
.Run(kStatusErrorNotFound
);
810 BluetoothPermissionRequest
request(
811 descriptor
->GetCharacteristic()->GetService()->GetUUID().value());
812 if (!BluetoothManifestData::CheckRequest(extension
, request
)) {
813 VLOG(1) << "App has no permission to access this descriptor: "
815 error_callback
.Run(kStatusErrorPermissionDenied
);
819 descriptor
->WriteRemoteDescriptor(
822 base::Bind(&BluetoothLowEnergyEventRouter::OnError
,
823 weak_ptr_factory_
.GetWeakPtr(),
827 void BluetoothLowEnergyEventRouter::SetAdapterForTesting(
828 device::BluetoothAdapter
* adapter
) {
830 InitializeIdentifierMappings();
833 void BluetoothLowEnergyEventRouter::GattServiceAdded(
834 BluetoothAdapter
* adapter
,
835 BluetoothDevice
* device
,
836 BluetoothGattService
* service
) {
837 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
838 DCHECK_EQ(adapter
, adapter_
.get());
839 VLOG(2) << "GATT service added: " << service
->GetIdentifier();
841 DCHECK(service_id_to_device_address_
.find(service
->GetIdentifier()) ==
842 service_id_to_device_address_
.end());
844 service_id_to_device_address_
[service
->GetIdentifier()] =
845 device
->GetAddress();
848 void BluetoothLowEnergyEventRouter::GattServiceRemoved(
849 BluetoothAdapter
* adapter
,
850 BluetoothDevice
* device
,
851 BluetoothGattService
* service
) {
852 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
853 DCHECK_EQ(adapter
, adapter_
.get());
854 VLOG(2) << "GATT service removed: " << service
->GetIdentifier();
856 DCHECK(service_id_to_device_address_
.find(service
->GetIdentifier()) !=
857 service_id_to_device_address_
.end());
859 DCHECK(device
->GetAddress() ==
860 service_id_to_device_address_
[service
->GetIdentifier()]);
861 service_id_to_device_address_
.erase(service
->GetIdentifier());
864 apibtle::Service api_service
;
865 PopulateService(service
, &api_service
);
867 scoped_ptr
<base::ListValue
> args
=
868 apibtle::OnServiceRemoved::Create(api_service
);
869 scoped_ptr
<Event
> event(
870 new Event(events::BLUETOOTH_LOW_ENERGY_ON_SERVICE_REMOVED
,
871 apibtle::OnServiceRemoved::kEventName
, args
.Pass()));
872 EventRouter::Get(browser_context_
)->BroadcastEvent(event
.Pass());
875 void BluetoothLowEnergyEventRouter::GattDiscoveryCompleteForService(
876 BluetoothAdapter
* adapter
,
877 BluetoothGattService
* service
) {
878 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
879 DCHECK_EQ(adapter
, adapter_
.get());
880 VLOG(2) << "GATT service discovery complete: " << service
->GetIdentifier();
882 DCHECK(service_id_to_device_address_
.find(service
->GetIdentifier()) !=
883 service_id_to_device_address_
.end());
885 // Signal the service added event here.
886 apibtle::Service api_service
;
887 PopulateService(service
, &api_service
);
889 scoped_ptr
<base::ListValue
> args
=
890 apibtle::OnServiceAdded::Create(api_service
);
891 scoped_ptr
<Event
> event(
892 new Event(events::BLUETOOTH_LOW_ENERGY_ON_SERVICE_ADDED
,
893 apibtle::OnServiceAdded::kEventName
, args
.Pass()));
894 EventRouter::Get(browser_context_
)->BroadcastEvent(event
.Pass());
897 void BluetoothLowEnergyEventRouter::GattServiceChanged(
898 BluetoothAdapter
* adapter
,
899 BluetoothGattService
* service
) {
900 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
901 DCHECK_EQ(adapter
, adapter_
.get());
902 VLOG(2) << "GATT service changed: " << service
->GetIdentifier();
903 DCHECK(service_id_to_device_address_
.find(service
->GetIdentifier()) !=
904 service_id_to_device_address_
.end());
907 apibtle::Service api_service
;
908 PopulateService(service
, &api_service
);
910 DispatchEventToExtensionsWithPermission(
911 events::BLUETOOTH_LOW_ENERGY_ON_SERVICE_CHANGED
,
912 apibtle::OnServiceChanged::kEventName
, service
->GetUUID(),
913 "" /* characteristic_id */,
914 apibtle::OnServiceChanged::Create(api_service
));
917 void BluetoothLowEnergyEventRouter::GattCharacteristicAdded(
918 BluetoothAdapter
* adapter
,
919 BluetoothGattCharacteristic
* characteristic
) {
920 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
921 DCHECK_EQ(adapter
, adapter_
.get());
922 VLOG(2) << "GATT characteristic added: " << characteristic
->GetIdentifier();
924 BluetoothGattService
* service
= characteristic
->GetService();
927 DCHECK(chrc_id_to_service_id_
.find(characteristic
->GetIdentifier()) ==
928 chrc_id_to_service_id_
.end());
929 DCHECK(service_id_to_device_address_
.find(service
->GetIdentifier()) !=
930 service_id_to_device_address_
.end());
932 chrc_id_to_service_id_
[characteristic
->GetIdentifier()] =
933 service
->GetIdentifier();
936 void BluetoothLowEnergyEventRouter::GattCharacteristicRemoved(
937 BluetoothAdapter
* adapter
,
938 BluetoothGattCharacteristic
* characteristic
) {
939 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
940 DCHECK_EQ(adapter
, adapter_
.get());
941 VLOG(2) << "GATT characteristic removed: " << characteristic
->GetIdentifier();
943 BluetoothGattService
* service
= characteristic
->GetService();
946 DCHECK(chrc_id_to_service_id_
.find(characteristic
->GetIdentifier()) !=
947 chrc_id_to_service_id_
.end());
948 DCHECK(service
->GetIdentifier() ==
949 chrc_id_to_service_id_
[characteristic
->GetIdentifier()]);
951 chrc_id_to_service_id_
.erase(characteristic
->GetIdentifier());
954 void BluetoothLowEnergyEventRouter::GattDescriptorAdded(
955 BluetoothAdapter
* adapter
,
956 BluetoothGattDescriptor
* descriptor
) {
957 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
958 DCHECK_EQ(adapter
, adapter_
.get());
959 VLOG(2) << "GATT descriptor added: " << descriptor
->GetIdentifier();
961 BluetoothGattCharacteristic
* characteristic
= descriptor
->GetCharacteristic();
962 DCHECK(characteristic
);
964 DCHECK(desc_id_to_chrc_id_
.find(descriptor
->GetIdentifier()) ==
965 desc_id_to_chrc_id_
.end());
966 DCHECK(chrc_id_to_service_id_
.find(characteristic
->GetIdentifier()) !=
967 chrc_id_to_service_id_
.end());
969 desc_id_to_chrc_id_
[descriptor
->GetIdentifier()] =
970 characteristic
->GetIdentifier();
973 void BluetoothLowEnergyEventRouter::GattDescriptorRemoved(
974 BluetoothAdapter
* adapter
,
975 BluetoothGattDescriptor
* descriptor
) {
976 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
977 DCHECK_EQ(adapter
, adapter_
.get());
978 VLOG(2) << "GATT descriptor removed: " << descriptor
->GetIdentifier();
980 BluetoothGattCharacteristic
* characteristic
= descriptor
->GetCharacteristic();
981 DCHECK(characteristic
);
983 DCHECK(desc_id_to_chrc_id_
.find(descriptor
->GetIdentifier()) !=
984 desc_id_to_chrc_id_
.end());
985 DCHECK(characteristic
->GetIdentifier() ==
986 desc_id_to_chrc_id_
[descriptor
->GetIdentifier()]);
988 desc_id_to_chrc_id_
.erase(descriptor
->GetIdentifier());
991 void BluetoothLowEnergyEventRouter::GattCharacteristicValueChanged(
992 BluetoothAdapter
* adapter
,
993 BluetoothGattCharacteristic
* characteristic
,
994 const std::vector
<uint8
>& value
) {
995 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
996 DCHECK_EQ(adapter
, adapter_
.get());
997 VLOG(2) << "GATT characteristic value changed: "
998 << characteristic
->GetIdentifier();
1000 BluetoothGattService
* service
= characteristic
->GetService();
1003 DCHECK(service_id_to_device_address_
.find(service
->GetIdentifier()) !=
1004 service_id_to_device_address_
.end());
1005 DCHECK(chrc_id_to_service_id_
.find(characteristic
->GetIdentifier()) !=
1006 chrc_id_to_service_id_
.end());
1007 DCHECK(chrc_id_to_service_id_
[characteristic
->GetIdentifier()] ==
1008 service
->GetIdentifier());
1010 // Send the event; manually construct the arguments, instead of using
1011 // apibtle::OnCharacteristicValueChanged::Create, as it doesn't convert
1012 // lists of enums correctly.
1013 apibtle::Characteristic api_characteristic
;
1014 PopulateCharacteristic(characteristic
, &api_characteristic
);
1015 scoped_ptr
<base::ListValue
> args(new base::ListValue());
1016 args
->Append(apibtle::CharacteristicToValue(&api_characteristic
).release());
1018 DispatchEventToExtensionsWithPermission(
1019 events::BLUETOOTH_LOW_ENERGY_ON_CHARACTERISTIC_VALUE_CHANGED
,
1020 apibtle::OnCharacteristicValueChanged::kEventName
, service
->GetUUID(),
1021 characteristic
->GetIdentifier(), args
.Pass());
1024 void BluetoothLowEnergyEventRouter::GattDescriptorValueChanged(
1025 BluetoothAdapter
* adapter
,
1026 BluetoothGattDescriptor
* descriptor
,
1027 const std::vector
<uint8
>& value
) {
1028 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
1029 DCHECK_EQ(adapter
, adapter_
.get());
1030 VLOG(2) << "GATT descriptor value changed: " << descriptor
->GetIdentifier();
1032 BluetoothGattCharacteristic
* characteristic
= descriptor
->GetCharacteristic();
1033 DCHECK(characteristic
);
1035 DCHECK(desc_id_to_chrc_id_
.find(descriptor
->GetIdentifier()) !=
1036 desc_id_to_chrc_id_
.end());
1037 DCHECK(characteristic
->GetIdentifier() ==
1038 desc_id_to_chrc_id_
[descriptor
->GetIdentifier()]);
1040 // Send the event; manually construct the arguments, instead of using
1041 // apibtle::OnDescriptorValueChanged::Create, as it doesn't convert
1042 // lists of enums correctly.
1043 apibtle::Descriptor api_descriptor
;
1044 PopulateDescriptor(descriptor
, &api_descriptor
);
1045 scoped_ptr
<base::ListValue
> args(new base::ListValue());
1046 args
->Append(apibtle::DescriptorToValue(&api_descriptor
).release());
1048 DispatchEventToExtensionsWithPermission(
1049 events::BLUETOOTH_LOW_ENERGY_ON_DESCRIPTOR_VALUE_CHANGED
,
1050 apibtle::OnDescriptorValueChanged::kEventName
,
1051 characteristic
->GetService()->GetUUID(), "" /* characteristic_id */,
1055 void BluetoothLowEnergyEventRouter::OnGetAdapter(
1056 const base::Closure
& callback
,
1057 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
1060 // Initialize instance ID mappings for all discovered GATT objects and add
1062 InitializeIdentifierMappings();
1063 adapter_
->AddObserver(this);
1068 void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() {
1069 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
1070 DCHECK(service_id_to_device_address_
.empty());
1071 DCHECK(chrc_id_to_service_id_
.empty());
1074 BluetoothAdapter::DeviceList devices
= adapter_
->GetDevices();
1075 for (BluetoothAdapter::DeviceList::iterator iter
= devices
.begin();
1076 iter
!= devices
.end();
1078 BluetoothDevice
* device
= *iter
;
1081 std::vector
<BluetoothGattService
*> services
= device
->GetGattServices();
1082 for (std::vector
<BluetoothGattService
*>::iterator siter
= services
.begin();
1083 siter
!= services
.end();
1085 BluetoothGattService
* service
= *siter
;
1087 const std::string
& service_id
= service
->GetIdentifier();
1088 service_id_to_device_address_
[service_id
] = device
->GetAddress();
1091 const std::vector
<BluetoothGattCharacteristic
*>& characteristics
=
1092 service
->GetCharacteristics();
1093 for (std::vector
<BluetoothGattCharacteristic
*>::const_iterator citer
=
1094 characteristics
.begin();
1095 citer
!= characteristics
.end();
1097 BluetoothGattCharacteristic
* characteristic
= *citer
;
1099 const std::string
& chrc_id
= characteristic
->GetIdentifier();
1100 chrc_id_to_service_id_
[chrc_id
] = service_id
;
1103 const std::vector
<BluetoothGattDescriptor
*>& descriptors
=
1104 characteristic
->GetDescriptors();
1105 for (std::vector
<BluetoothGattDescriptor
*>::const_iterator diter
=
1106 descriptors
.begin();
1107 diter
!= descriptors
.end();
1109 BluetoothGattDescriptor
* descriptor
= *diter
;
1111 const std::string
& desc_id
= descriptor
->GetIdentifier();
1112 desc_id_to_chrc_id_
[desc_id
] = chrc_id
;
1119 void BluetoothLowEnergyEventRouter::DispatchEventToExtensionsWithPermission(
1120 events::HistogramValue histogram_value
,
1121 const std::string
& event_name
,
1122 const device::BluetoothUUID
& uuid
,
1123 const std::string
& characteristic_id
,
1124 scoped_ptr
<base::ListValue
> args
) {
1125 // Obtain the listeners of |event_name|. The list can contain multiple
1126 // entries for the same extension, so we keep track of the extensions that we
1127 // already sent the event to, since we want the send an event to an extension
1129 BluetoothPermissionRequest
request(uuid
.value());
1130 std::set
<std::string
> handled_extensions
;
1131 const EventListenerMap::ListenerList listeners
=
1132 EventRouter::Get(browser_context_
)->listeners().GetEventListenersByName(
1135 for (EventListenerMap::ListenerList::const_iterator iter
= listeners
.begin();
1136 iter
!= listeners
.end();
1138 const std::string extension_id
= (*iter
)->extension_id();
1139 if (handled_extensions
.find(extension_id
) != handled_extensions
.end())
1142 handled_extensions
.insert(extension_id
);
1144 const Extension
* extension
=
1145 ExtensionRegistry::Get(browser_context_
)
1146 ->GetExtensionById(extension_id
, ExtensionRegistry::EVERYTHING
);
1148 // For all API methods, the "low_energy" permission check is handled by
1149 // BluetoothLowEnergyExtensionFunction but for events we have to do the
1151 if (!BluetoothManifestData::CheckRequest(extension
, request
) ||
1152 !BluetoothManifestData::CheckLowEnergyPermitted(extension
))
1155 // If |event_name| is "onCharacteristicValueChanged", then send the
1156 // event only if the extension has requested notifications from the
1157 // related characteristic.
1158 if (event_name
== apibtle::OnCharacteristicValueChanged::kEventName
&&
1159 !characteristic_id
.empty() &&
1160 !FindNotifySession(extension_id
, characteristic_id
))
1164 scoped_ptr
<base::ListValue
> args_copy(args
->DeepCopy());
1165 scoped_ptr
<Event
> event(
1166 new Event(histogram_value
, event_name
, args_copy
.Pass()));
1167 EventRouter::Get(browser_context_
)->DispatchEventToExtension(
1168 extension_id
, event
.Pass());
1172 BluetoothGattService
* BluetoothLowEnergyEventRouter::FindServiceById(
1173 const std::string
& instance_id
) const {
1174 InstanceIdMap::const_iterator iter
=
1175 service_id_to_device_address_
.find(instance_id
);
1176 if (iter
== service_id_to_device_address_
.end()) {
1177 VLOG(1) << "GATT service identifier unknown: " << instance_id
;
1181 const std::string
& address
= iter
->second
;
1183 BluetoothDevice
* device
= adapter_
->GetDevice(address
);
1185 VLOG(1) << "Bluetooth device not found: " << address
;
1189 BluetoothGattService
* service
= device
->GetGattService(instance_id
);
1191 VLOG(1) << "GATT service with ID \"" << instance_id
1192 << "\" not found on device \"" << address
<< "\"";
1199 BluetoothGattCharacteristic
*
1200 BluetoothLowEnergyEventRouter::FindCharacteristicById(
1201 const std::string
& instance_id
) const {
1202 InstanceIdMap::const_iterator iter
= chrc_id_to_service_id_
.find(instance_id
);
1203 if (iter
== chrc_id_to_service_id_
.end()) {
1204 VLOG(1) << "GATT characteristic identifier unknown: " << instance_id
;
1208 const std::string
& service_id
= iter
->second
;
1210 BluetoothGattService
* service
= FindServiceById(service_id
);
1212 VLOG(1) << "Failed to obtain service for characteristic: " << instance_id
;
1216 BluetoothGattCharacteristic
* characteristic
=
1217 service
->GetCharacteristic(instance_id
);
1218 if (!characteristic
) {
1219 VLOG(1) << "GATT characteristic with ID \"" << instance_id
1220 << "\" not found on service \"" << service_id
<< "\"";
1224 return characteristic
;
1227 BluetoothGattDescriptor
* BluetoothLowEnergyEventRouter::FindDescriptorById(
1228 const std::string
& instance_id
) const {
1229 InstanceIdMap::const_iterator iter
= desc_id_to_chrc_id_
.find(instance_id
);
1230 if (iter
== desc_id_to_chrc_id_
.end()) {
1231 VLOG(1) << "GATT descriptor identifier unknown: " << instance_id
;
1235 const std::string
& chrc_id
= iter
->second
;
1236 BluetoothGattCharacteristic
* chrc
= FindCharacteristicById(chrc_id
);
1238 VLOG(1) << "Failed to obtain characteristic for descriptor: "
1243 BluetoothGattDescriptor
* descriptor
= chrc
->GetDescriptor(instance_id
);
1245 VLOG(1) << "GATT descriptor with ID \"" << instance_id
1246 << "\" not found on characteristic \"" << chrc_id
<< "\"";
1253 void BluetoothLowEnergyEventRouter::OnValueSuccess(
1254 const base::Closure
& callback
,
1255 const std::vector
<uint8
>& value
) {
1256 VLOG(2) << "Remote characteristic/descriptor value read successful.";
1260 void BluetoothLowEnergyEventRouter::OnCreateGattConnection(
1262 const std::string
& extension_id
,
1263 const std::string
& device_address
,
1264 const base::Closure
& callback
,
1265 scoped_ptr
<BluetoothGattConnection
> connection
) {
1266 VLOG(2) << "GATT connection created.";
1267 DCHECK(connection
.get());
1268 DCHECK(!FindConnection(extension_id
, device_address
));
1269 DCHECK_EQ(device_address
, connection
->GetDeviceAddress());
1271 const std::string connect_id
= extension_id
+ device_address
;
1272 DCHECK_NE(0U, connecting_devices_
.count(connect_id
));
1274 BluetoothLowEnergyConnection
* conn
= new BluetoothLowEnergyConnection(
1275 persistent
, extension_id
, connection
.Pass());
1276 ConnectionResourceManager
* manager
=
1277 GetConnectionResourceManager(browser_context_
);
1280 connecting_devices_
.erase(connect_id
);
1284 void BluetoothLowEnergyEventRouter::OnDisconnect(
1285 const std::string
& extension_id
,
1286 const std::string
& device_address
,
1287 const base::Closure
& callback
) {
1288 VLOG(2) << "GATT connection terminated.";
1290 const std::string disconnect_id
= extension_id
+ device_address
;
1291 DCHECK_NE(0U, disconnecting_devices_
.count(disconnect_id
));
1293 if (!RemoveConnection(extension_id
, device_address
)) {
1294 VLOG(1) << "The connection was removed before disconnect completed, id: "
1295 << extension_id
<< ", device: " << device_address
;
1298 disconnecting_devices_
.erase(disconnect_id
);
1302 void BluetoothLowEnergyEventRouter::OnError(
1303 const ErrorCallback
& error_callback
,
1304 BluetoothGattService::GattErrorCode error_code
) {
1305 VLOG(2) << "Remote characteristic/descriptor value read/write failed.";
1307 error_callback
.Run(GattErrorToRouterError(error_code
));
1310 void BluetoothLowEnergyEventRouter::OnConnectError(
1311 const std::string
& extension_id
,
1312 const std::string
& device_address
,
1313 const ErrorCallback
& error_callback
,
1314 BluetoothDevice::ConnectErrorCode error_code
) {
1315 VLOG(2) << "Failed to create GATT connection: " << error_code
;
1317 const std::string connect_id
= extension_id
+ device_address
;
1318 DCHECK_NE(0U, connecting_devices_
.count(connect_id
));
1320 connecting_devices_
.erase(connect_id
);
1321 Status error_status
= kStatusErrorFailed
;
1322 if (error_code
== BluetoothDevice::ERROR_INPROGRESS
) {
1323 error_status
= kStatusErrorInProgress
;
1324 } else if (error_code
== BluetoothDevice::ERROR_AUTH_FAILED
||
1325 error_code
== BluetoothDevice::ERROR_AUTH_REJECTED
) {
1326 error_status
= kStatusErrorAuthenticationFailed
;
1327 } else if (error_code
== BluetoothDevice::ERROR_AUTH_CANCELED
) {
1328 error_status
= kStatusErrorCanceled
;
1329 } else if (error_code
== BluetoothDevice::ERROR_AUTH_TIMEOUT
) {
1330 error_status
= kStatusErrorTimeout
;
1331 } else if (error_code
== BluetoothDevice::ERROR_UNSUPPORTED_DEVICE
) {
1332 error_status
= kStatusErrorUnsupportedDevice
;
1334 // ERROR_UNKNOWN and ERROR_FAILED defaulted to kStatusErrorFailed
1336 error_callback
.Run(error_status
);
1339 void BluetoothLowEnergyEventRouter::OnStartNotifySession(
1341 const std::string
& extension_id
,
1342 const std::string
& characteristic_id
,
1343 const base::Closure
& callback
,
1344 scoped_ptr
<device::BluetoothGattNotifySession
> session
) {
1345 VLOG(2) << "Value update session created for characteristic: "
1346 << characteristic_id
;
1347 DCHECK(session
.get());
1348 DCHECK(!FindNotifySession(extension_id
, characteristic_id
));
1349 DCHECK_EQ(characteristic_id
, session
->GetCharacteristicIdentifier());
1351 const std::string session_id
= extension_id
+ characteristic_id
;
1352 DCHECK_NE(0U, pending_session_calls_
.count(session_id
));
1354 BluetoothLowEnergyNotifySession
* resource
=
1355 new BluetoothLowEnergyNotifySession(
1356 persistent
, extension_id
, session
.Pass());
1358 NotifySessionResourceManager
* manager
=
1359 GetNotifySessionResourceManager(browser_context_
);
1360 manager
->Add(resource
);
1362 pending_session_calls_
.erase(session_id
);
1366 void BluetoothLowEnergyEventRouter::OnStartNotifySessionError(
1367 const std::string
& extension_id
,
1368 const std::string
& characteristic_id
,
1369 const ErrorCallback
& error_callback
,
1370 device::BluetoothGattService::GattErrorCode error_code
) {
1371 VLOG(2) << "Failed to create value update session for characteristic: "
1372 << characteristic_id
;
1374 const std::string session_id
= extension_id
+ characteristic_id
;
1375 DCHECK_NE(0U, pending_session_calls_
.count(session_id
));
1377 pending_session_calls_
.erase(session_id
);
1378 error_callback
.Run(GattErrorToRouterError(error_code
));
1381 void BluetoothLowEnergyEventRouter::OnStopNotifySession(
1382 const std::string
& extension_id
,
1383 const std::string
& characteristic_id
,
1384 const base::Closure
& callback
) {
1385 VLOG(2) << "Value update session terminated.";
1387 if (!RemoveNotifySession(extension_id
, characteristic_id
)) {
1388 VLOG(1) << "The value update session was removed before Stop completed, "
1389 << "id: " << extension_id
1390 << ", characteristic: " << characteristic_id
;
1396 BluetoothLowEnergyConnection
* BluetoothLowEnergyEventRouter::FindConnection(
1397 const std::string
& extension_id
,
1398 const std::string
& device_address
) {
1399 ConnectionResourceManager
* manager
=
1400 GetConnectionResourceManager(browser_context_
);
1402 base::hash_set
<int>* connection_ids
= manager
->GetResourceIds(extension_id
);
1403 if (!connection_ids
)
1406 for (base::hash_set
<int>::const_iterator iter
= connection_ids
->begin();
1407 iter
!= connection_ids
->end();
1409 extensions::BluetoothLowEnergyConnection
* conn
=
1410 manager
->Get(extension_id
, *iter
);
1414 if (conn
->GetConnection()->GetDeviceAddress() == device_address
)
1421 bool BluetoothLowEnergyEventRouter::RemoveConnection(
1422 const std::string
& extension_id
,
1423 const std::string
& device_address
) {
1424 ConnectionResourceManager
* manager
=
1425 GetConnectionResourceManager(browser_context_
);
1427 base::hash_set
<int>* connection_ids
= manager
->GetResourceIds(extension_id
);
1428 if (!connection_ids
)
1431 for (base::hash_set
<int>::const_iterator iter
= connection_ids
->begin();
1432 iter
!= connection_ids
->end();
1434 extensions::BluetoothLowEnergyConnection
* conn
=
1435 manager
->Get(extension_id
, *iter
);
1436 if (!conn
|| conn
->GetConnection()->GetDeviceAddress() != device_address
)
1439 manager
->Remove(extension_id
, *iter
);
1446 BluetoothLowEnergyNotifySession
*
1447 BluetoothLowEnergyEventRouter::FindNotifySession(
1448 const std::string
& extension_id
,
1449 const std::string
& characteristic_id
) {
1450 NotifySessionResourceManager
* manager
=
1451 GetNotifySessionResourceManager(browser_context_
);
1453 base::hash_set
<int>* ids
= manager
->GetResourceIds(extension_id
);
1457 for (base::hash_set
<int>::const_iterator iter
= ids
->begin();
1460 BluetoothLowEnergyNotifySession
* session
=
1461 manager
->Get(extension_id
, *iter
);
1465 if (session
->GetSession()->GetCharacteristicIdentifier() ==
1473 bool BluetoothLowEnergyEventRouter::RemoveNotifySession(
1474 const std::string
& extension_id
,
1475 const std::string
& characteristic_id
) {
1476 NotifySessionResourceManager
* manager
=
1477 GetNotifySessionResourceManager(browser_context_
);
1479 base::hash_set
<int>* ids
= manager
->GetResourceIds(extension_id
);
1483 for (base::hash_set
<int>::const_iterator iter
= ids
->begin();
1486 BluetoothLowEnergyNotifySession
* session
=
1487 manager
->Get(extension_id
, *iter
);
1489 session
->GetSession()->GetCharacteristicIdentifier() !=
1493 manager
->Remove(extension_id
, *iter
);
1500 } // namespace extensions