Add ICU message format support
[chromium-blink-merge.git] / extensions / browser / api / bluetooth_low_energy / bluetooth_low_energy_event_router.cc
blob51f8143d4047a5148e2eafcd16362ad2d9794336
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"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/values.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "device/bluetooth/bluetooth_adapter_factory.h"
12 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
13 #include "device/bluetooth/bluetooth_gatt_connection.h"
14 #include "device/bluetooth/bluetooth_gatt_descriptor.h"
15 #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.h"
16 #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h"
17 #include "extensions/browser/api/bluetooth_low_energy/utils.h"
18 #include "extensions/browser/event_router.h"
19 #include "extensions/browser/extension_registry.h"
20 #include "extensions/common/api/bluetooth/bluetooth_manifest_data.h"
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;
34 namespace {
36 void PopulateService(const BluetoothGattService* service,
37 apibtle::Service* out) {
38 DCHECK(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())
46 return;
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)
58 return;
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);
64 if (properties &
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);
75 if (properties &
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) {
94 DCHECK(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(),
102 &out->properties);
104 const std::vector<uint8>& value = characteristic->GetValue();
105 if (value.empty())
106 return;
108 out->value.reset(new std::vector<char>(value.begin(), value.end()));
111 void PopulateDescriptor(const BluetoothGattDescriptor* descriptor,
112 apibtle::Descriptor* out) {
113 DCHECK(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();
122 if (value.empty())
123 return;
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);
133 DCHECK(manager)
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>.";
138 return manager;
141 typedef extensions::ApiResourceManager<
142 extensions::BluetoothLowEnergyNotifySession> NotifySessionResourceManager;
143 NotifySessionResourceManager* GetNotifySessionResourceManager(
144 content::BrowserContext* context) {
145 NotifySessionResourceManager* manager =
146 NotifySessionResourceManager::Get(context);
147 DCHECK(manager)
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>.";
152 return manager;
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) {
161 error_status =
162 extensions::BluetoothLowEnergyEventRouter::kStatusErrorInProgress;
163 } else if (error_code == BluetoothGattService::GATT_ERROR_INVALID_LENGTH) {
164 error_status =
165 extensions::BluetoothLowEnergyEventRouter::kStatusErrorInvalidLength;
166 } else if (error_code == BluetoothGattService::GATT_ERROR_NOT_PERMITTED) {
167 error_status =
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) {
173 error_status =
174 extensions::BluetoothLowEnergyEventRouter::kStatusErrorHigherSecurity;
175 } else if (error_code == BluetoothGattService::GATT_ERROR_NOT_SUPPORTED) {
176 error_status =
177 extensions::BluetoothLowEnergyEventRouter::kStatusErrorGattNotSupported;
180 return error_status;
183 } // namespace
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.";
196 return;
200 BluetoothLowEnergyEventRouter::~BluetoothLowEnergyEventRouter() {
201 DCHECK_CURRENTLY_ON(BrowserThread::UI);
202 if (!adapter_.get())
203 return;
205 adapter_->RemoveObserver(this);
206 adapter_ = NULL;
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())
218 return false;
220 if (adapter_.get()) {
221 callback.Run();
222 return true;
225 BluetoothAdapterFactory::GetAdapter(
226 base::Bind(&BluetoothLowEnergyEventRouter::OnGetAdapter,
227 weak_ptr_factory_.GetWeakPtr(),
228 callback));
229 return true;
232 bool BluetoothLowEnergyEventRouter::HasAdapter() const {
233 return (adapter_.get() != NULL);
236 void BluetoothLowEnergyEventRouter::Connect(
237 bool persistent,
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);
246 return;
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);
254 return;
257 BluetoothLowEnergyConnection* conn =
258 FindConnection(extension_id, device_address);
259 if (conn) {
260 if (conn->GetConnection()->IsConnected()) {
261 VLOG(1) << "Application already connected to device: " << device_address;
262 error_callback.Run(kStatusErrorAlreadyConnected);
263 return;
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);
271 if (!device) {
272 VLOG(1) << "Bluetooth device not found: " << device_address;
273 error_callback.Run(kStatusErrorNotFound);
274 return;
277 connecting_devices_.insert(connect_id);
278 device->CreateGattConnection(
279 base::Bind(&BluetoothLowEnergyEventRouter::OnCreateGattConnection,
280 weak_ptr_factory_.GetWeakPtr(),
281 persistent,
282 extension_id,
283 device_address,
284 callback),
285 base::Bind(&BluetoothLowEnergyEventRouter::OnConnectError,
286 weak_ptr_factory_.GetWeakPtr(),
287 extension_id,
288 device_address,
289 error_callback));
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);
301 return;
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);
309 return;
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);
317 return;
320 disconnecting_devices_.insert(disconnect_id);
321 conn->GetConnection()->Disconnect(
322 base::Bind(&BluetoothLowEnergyEventRouter::OnDisconnect,
323 weak_ptr_factory_.GetWeakPtr(),
324 extension_id,
325 device_address,
326 callback));
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.";
336 return false;
339 BluetoothDevice* device = adapter_->GetDevice(device_address);
340 if (!device) {
341 VLOG(1) << "Bluetooth device not found: " << device_address;
342 return false;
345 out_services->clear();
347 const std::vector<BluetoothGattService*>& services =
348 device->GetGattServices();
349 for (std::vector<BluetoothGattService*>::const_iterator iter =
350 services.begin();
351 iter != services.end();
352 ++iter) {
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);
361 return true;
364 BluetoothLowEnergyEventRouter::Status BluetoothLowEnergyEventRouter::GetService(
365 const std::string& instance_id,
366 apibtle::Service* out_service) const {
367 DCHECK_CURRENTLY_ON(BrowserThread::UI);
368 DCHECK(out_service);
369 if (!adapter_.get()) {
370 VLOG(1) << "BluetoothAdapter not ready.";
371 return kStatusErrorFailed;
374 BluetoothGattService* gatt_service = FindServiceById(instance_id);
375 if (!gatt_service) {
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);
396 if (!service) {
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 =
406 includes.begin();
407 iter != includes.end();
408 ++iter) {
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);
426 DCHECK(extension);
427 DCHECK(out_characteristics);
428 if (!adapter_.get()) {
429 VLOG(1) << "BlutoothAdapter not ready.";
430 return kStatusErrorFailed;
433 BluetoothGattService* service = FindServiceById(instance_id);
434 if (!service) {
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();
453 ++iter) {
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);
472 DCHECK(extension);
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: "
490 << instance_id;
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);
504 DCHECK(extension);
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 =
531 descriptors.begin();
532 iter != descriptors.end();
533 ++iter) {
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);
551 DCHECK(extension);
552 DCHECK(out_descriptor);
553 if (!adapter_.get()) {
554 VLOG(1) << "BluetoothAdapter not ready.";
555 return kStatusErrorFailed;
558 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
559 if (!descriptor) {
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: "
568 << instance_id;
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);
582 DCHECK(extension);
583 if (!adapter_.get()) {
584 VLOG(1) << "BluetoothAdapter not ready.";
585 error_callback.Run(kStatusErrorFailed);
586 return;
589 BluetoothGattCharacteristic* characteristic =
590 FindCharacteristicById(instance_id);
591 if (!characteristic) {
592 VLOG(1) << "Characteristic not found: " << instance_id;
593 error_callback.Run(kStatusErrorNotFound);
594 return;
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: "
601 << instance_id;
602 error_callback.Run(kStatusErrorPermissionDenied);
603 return;
606 characteristic->ReadRemoteCharacteristic(
607 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
608 weak_ptr_factory_.GetWeakPtr(),
609 callback),
610 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
611 weak_ptr_factory_.GetWeakPtr(),
612 error_callback));
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);
622 DCHECK(extension);
623 if (!adapter_.get()) {
624 VLOG(1) << "BluetoothAdapter not ready.";
625 error_callback.Run(kStatusErrorFailed);
626 return;
629 BluetoothGattCharacteristic* characteristic =
630 FindCharacteristicById(instance_id);
631 if (!characteristic) {
632 VLOG(1) << "Characteristic not found: " << instance_id;
633 error_callback.Run(kStatusErrorNotFound);
634 return;
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: "
641 << instance_id;
642 error_callback.Run(kStatusErrorPermissionDenied);
643 return;
646 characteristic->WriteRemoteCharacteristic(
647 value,
648 callback,
649 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
650 weak_ptr_factory_.GetWeakPtr(),
651 error_callback));
654 void BluetoothLowEnergyEventRouter::StartCharacteristicNotifications(
655 bool persistent,
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);
664 return;
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);
672 return;
675 BluetoothLowEnergyNotifySession* session =
676 FindNotifySession(extension_id, instance_id);
677 if (session) {
678 if (session->GetSession()->IsActive()) {
679 VLOG(1) << "Application has already enabled notifications from "
680 << "characteristic: " << instance_id;
681 error_callback.Run(kStatusErrorAlreadyNotifying);
682 return;
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);
693 return;
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: "
700 << instance_id;
701 error_callback.Run(kStatusErrorPermissionDenied);
702 return;
705 pending_session_calls_.insert(session_id);
706 characteristic->StartNotifySession(
707 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySession,
708 weak_ptr_factory_.GetWeakPtr(),
709 persistent,
710 extension_id,
711 instance_id,
712 callback),
713 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySessionError,
714 weak_ptr_factory_.GetWeakPtr(),
715 extension_id,
716 instance_id,
717 error_callback));
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);
729 return;
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);
740 return;
743 session->GetSession()->Stop(
744 base::Bind(&BluetoothLowEnergyEventRouter::OnStopNotifySession,
745 weak_ptr_factory_.GetWeakPtr(),
746 extension_id,
747 instance_id,
748 callback));
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);
757 DCHECK(extension);
758 if (!adapter_.get()) {
759 VLOG(1) << "BluetoothAdapter not ready.";
760 error_callback.Run(kStatusErrorFailed);
761 return;
764 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
765 if (!descriptor) {
766 VLOG(1) << "Descriptor not found: " << instance_id;
767 error_callback.Run(kStatusErrorNotFound);
768 return;
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: "
775 << instance_id;
776 error_callback.Run(kStatusErrorPermissionDenied);
777 return;
780 descriptor->ReadRemoteDescriptor(
781 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
782 weak_ptr_factory_.GetWeakPtr(),
783 callback),
784 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
785 weak_ptr_factory_.GetWeakPtr(),
786 error_callback));
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);
796 DCHECK(extension);
797 if (!adapter_.get()) {
798 VLOG(1) << "BluetoothAdapter not ready.";
799 error_callback.Run(kStatusErrorFailed);
800 return;
803 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
804 if (!descriptor) {
805 VLOG(1) << "Descriptor not found: " << instance_id;
806 error_callback.Run(kStatusErrorNotFound);
807 return;
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: "
814 << instance_id;
815 error_callback.Run(kStatusErrorPermissionDenied);
816 return;
819 descriptor->WriteRemoteDescriptor(
820 value,
821 callback,
822 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
823 weak_ptr_factory_.GetWeakPtr(),
824 error_callback));
827 void BluetoothLowEnergyEventRouter::SetAdapterForTesting(
828 device::BluetoothAdapter* adapter) {
829 adapter_ = 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());
863 // Signal API event.
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());
906 // Signal API event.
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();
925 DCHECK(service);
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();
944 DCHECK(service);
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();
1001 DCHECK(service);
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 */,
1052 args.Pass());
1055 void BluetoothLowEnergyEventRouter::OnGetAdapter(
1056 const base::Closure& callback,
1057 scoped_refptr<device::BluetoothAdapter> adapter) {
1058 adapter_ = adapter;
1060 // Initialize instance ID mappings for all discovered GATT objects and add
1061 // observers.
1062 InitializeIdentifierMappings();
1063 adapter_->AddObserver(this);
1065 callback.Run();
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());
1073 // Devices
1074 BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
1075 for (BluetoothAdapter::DeviceList::iterator iter = devices.begin();
1076 iter != devices.end();
1077 ++iter) {
1078 BluetoothDevice* device = *iter;
1080 // Services
1081 std::vector<BluetoothGattService*> services = device->GetGattServices();
1082 for (std::vector<BluetoothGattService*>::iterator siter = services.begin();
1083 siter != services.end();
1084 ++siter) {
1085 BluetoothGattService* service = *siter;
1087 const std::string& service_id = service->GetIdentifier();
1088 service_id_to_device_address_[service_id] = device->GetAddress();
1090 // Characteristics
1091 const std::vector<BluetoothGattCharacteristic*>& characteristics =
1092 service->GetCharacteristics();
1093 for (std::vector<BluetoothGattCharacteristic*>::const_iterator citer =
1094 characteristics.begin();
1095 citer != characteristics.end();
1096 ++citer) {
1097 BluetoothGattCharacteristic* characteristic = *citer;
1099 const std::string& chrc_id = characteristic->GetIdentifier();
1100 chrc_id_to_service_id_[chrc_id] = service_id;
1102 // Descriptors
1103 const std::vector<BluetoothGattDescriptor*>& descriptors =
1104 characteristic->GetDescriptors();
1105 for (std::vector<BluetoothGattDescriptor*>::const_iterator diter =
1106 descriptors.begin();
1107 diter != descriptors.end();
1108 ++diter) {
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
1128 // only once.
1129 BluetoothPermissionRequest request(uuid.value());
1130 std::set<std::string> handled_extensions;
1131 const EventListenerMap::ListenerList listeners =
1132 EventRouter::Get(browser_context_)->listeners().GetEventListenersByName(
1133 event_name);
1135 for (EventListenerMap::ListenerList::const_iterator iter = listeners.begin();
1136 iter != listeners.end();
1137 ++iter) {
1138 const std::string extension_id = (*iter)->extension_id();
1139 if (handled_extensions.find(extension_id) != handled_extensions.end())
1140 continue;
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
1150 // check here.
1151 if (!BluetoothManifestData::CheckRequest(extension, request) ||
1152 !BluetoothManifestData::CheckLowEnergyPermitted(extension))
1153 continue;
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))
1161 continue;
1163 // Send the event.
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;
1178 return NULL;
1181 const std::string& address = iter->second;
1183 BluetoothDevice* device = adapter_->GetDevice(address);
1184 if (!device) {
1185 VLOG(1) << "Bluetooth device not found: " << address;
1186 return NULL;
1189 BluetoothGattService* service = device->GetGattService(instance_id);
1190 if (!service) {
1191 VLOG(1) << "GATT service with ID \"" << instance_id
1192 << "\" not found on device \"" << address << "\"";
1193 return NULL;
1196 return service;
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;
1205 return NULL;
1208 const std::string& service_id = iter->second;
1210 BluetoothGattService* service = FindServiceById(service_id);
1211 if (!service) {
1212 VLOG(1) << "Failed to obtain service for characteristic: " << instance_id;
1213 return NULL;
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 << "\"";
1221 return NULL;
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;
1232 return NULL;
1235 const std::string& chrc_id = iter->second;
1236 BluetoothGattCharacteristic* chrc = FindCharacteristicById(chrc_id);
1237 if (!chrc) {
1238 VLOG(1) << "Failed to obtain characteristic for descriptor: "
1239 << instance_id;
1240 return NULL;
1243 BluetoothGattDescriptor* descriptor = chrc->GetDescriptor(instance_id);
1244 if (!descriptor) {
1245 VLOG(1) << "GATT descriptor with ID \"" << instance_id
1246 << "\" not found on characteristic \"" << chrc_id << "\"";
1247 return NULL;
1250 return descriptor;
1253 void BluetoothLowEnergyEventRouter::OnValueSuccess(
1254 const base::Closure& callback,
1255 const std::vector<uint8>& value) {
1256 VLOG(2) << "Remote characteristic/descriptor value read successful.";
1257 callback.Run();
1260 void BluetoothLowEnergyEventRouter::OnCreateGattConnection(
1261 bool persistent,
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_);
1278 manager->Add(conn);
1280 connecting_devices_.erase(connect_id);
1281 callback.Run();
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);
1299 callback.Run();
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(
1340 bool persistent,
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);
1363 callback.Run();
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;
1393 callback.Run();
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)
1404 return NULL;
1406 for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
1407 iter != connection_ids->end();
1408 ++iter) {
1409 extensions::BluetoothLowEnergyConnection* conn =
1410 manager->Get(extension_id, *iter);
1411 if (!conn)
1412 continue;
1414 if (conn->GetConnection()->GetDeviceAddress() == device_address)
1415 return conn;
1418 return NULL;
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)
1429 return false;
1431 for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
1432 iter != connection_ids->end();
1433 ++iter) {
1434 extensions::BluetoothLowEnergyConnection* conn =
1435 manager->Get(extension_id, *iter);
1436 if (!conn || conn->GetConnection()->GetDeviceAddress() != device_address)
1437 continue;
1439 manager->Remove(extension_id, *iter);
1440 return true;
1443 return false;
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);
1454 if (!ids)
1455 return NULL;
1457 for (base::hash_set<int>::const_iterator iter = ids->begin();
1458 iter != ids->end();
1459 ++iter) {
1460 BluetoothLowEnergyNotifySession* session =
1461 manager->Get(extension_id, *iter);
1462 if (!session)
1463 continue;
1465 if (session->GetSession()->GetCharacteristicIdentifier() ==
1466 characteristic_id)
1467 return session;
1470 return NULL;
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);
1480 if (!ids)
1481 return false;
1483 for (base::hash_set<int>::const_iterator iter = ids->begin();
1484 iter != ids->end();
1485 ++iter) {
1486 BluetoothLowEnergyNotifySession* session =
1487 manager->Get(extension_id, *iter);
1488 if (!session ||
1489 session->GetSession()->GetCharacteristicIdentifier() !=
1490 characteristic_id)
1491 continue;
1493 manager->Remove(extension_id, *iter);
1494 return true;
1497 return false;
1500 } // namespace extensions