Fix search results being clipped in app list.
[chromium-blink-merge.git] / extensions / browser / api / bluetooth_low_energy / bluetooth_low_energy_event_router.cc
blobe1f59fb2cd44e8e271acb94cf95b65aa3d2c8c33
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::core_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 core_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(apibtle::OnServiceRemoved::kEventName, args.Pass()));
871 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
874 void BluetoothLowEnergyEventRouter::GattDiscoveryCompleteForService(
875 BluetoothAdapter* adapter,
876 BluetoothGattService* service) {
877 DCHECK_CURRENTLY_ON(BrowserThread::UI);
878 DCHECK_EQ(adapter, adapter_.get());
879 VLOG(2) << "GATT service discovery complete: " << service->GetIdentifier();
881 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
882 service_id_to_device_address_.end());
884 // Signal the service added event here.
885 apibtle::Service api_service;
886 PopulateService(service, &api_service);
888 scoped_ptr<base::ListValue> args =
889 apibtle::OnServiceAdded::Create(api_service);
890 scoped_ptr<Event> event(
891 new Event(apibtle::OnServiceAdded::kEventName, args.Pass()));
892 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
895 void BluetoothLowEnergyEventRouter::GattServiceChanged(
896 BluetoothAdapter* adapter,
897 BluetoothGattService* service) {
898 DCHECK_CURRENTLY_ON(BrowserThread::UI);
899 DCHECK_EQ(adapter, adapter_.get());
900 VLOG(2) << "GATT service changed: " << service->GetIdentifier();
901 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
902 service_id_to_device_address_.end());
904 // Signal API event.
905 apibtle::Service api_service;
906 PopulateService(service, &api_service);
908 DispatchEventToExtensionsWithPermission(
909 apibtle::OnServiceChanged::kEventName,
910 service->GetUUID(),
911 "" /* characteristic_id */,
912 apibtle::OnServiceChanged::Create(api_service));
915 void BluetoothLowEnergyEventRouter::GattCharacteristicAdded(
916 BluetoothAdapter* adapter,
917 BluetoothGattCharacteristic* characteristic) {
918 DCHECK_CURRENTLY_ON(BrowserThread::UI);
919 DCHECK_EQ(adapter, adapter_.get());
920 VLOG(2) << "GATT characteristic added: " << characteristic->GetIdentifier();
922 BluetoothGattService* service = characteristic->GetService();
923 DCHECK(service);
925 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) ==
926 chrc_id_to_service_id_.end());
927 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
928 service_id_to_device_address_.end());
930 chrc_id_to_service_id_[characteristic->GetIdentifier()] =
931 service->GetIdentifier();
934 void BluetoothLowEnergyEventRouter::GattCharacteristicRemoved(
935 BluetoothAdapter* adapter,
936 BluetoothGattCharacteristic* characteristic) {
937 DCHECK_CURRENTLY_ON(BrowserThread::UI);
938 DCHECK_EQ(adapter, adapter_.get());
939 VLOG(2) << "GATT characteristic removed: " << characteristic->GetIdentifier();
941 BluetoothGattService* service = characteristic->GetService();
942 DCHECK(service);
944 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
945 chrc_id_to_service_id_.end());
946 DCHECK(service->GetIdentifier() ==
947 chrc_id_to_service_id_[characteristic->GetIdentifier()]);
949 chrc_id_to_service_id_.erase(characteristic->GetIdentifier());
952 void BluetoothLowEnergyEventRouter::GattDescriptorAdded(
953 BluetoothAdapter* adapter,
954 BluetoothGattDescriptor* descriptor) {
955 DCHECK_CURRENTLY_ON(BrowserThread::UI);
956 DCHECK_EQ(adapter, adapter_.get());
957 VLOG(2) << "GATT descriptor added: " << descriptor->GetIdentifier();
959 BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic();
960 DCHECK(characteristic);
962 DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) ==
963 desc_id_to_chrc_id_.end());
964 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
965 chrc_id_to_service_id_.end());
967 desc_id_to_chrc_id_[descriptor->GetIdentifier()] =
968 characteristic->GetIdentifier();
971 void BluetoothLowEnergyEventRouter::GattDescriptorRemoved(
972 BluetoothAdapter* adapter,
973 BluetoothGattDescriptor* descriptor) {
974 DCHECK_CURRENTLY_ON(BrowserThread::UI);
975 DCHECK_EQ(adapter, adapter_.get());
976 VLOG(2) << "GATT descriptor removed: " << descriptor->GetIdentifier();
978 BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic();
979 DCHECK(characteristic);
981 DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) !=
982 desc_id_to_chrc_id_.end());
983 DCHECK(characteristic->GetIdentifier() ==
984 desc_id_to_chrc_id_[descriptor->GetIdentifier()]);
986 desc_id_to_chrc_id_.erase(descriptor->GetIdentifier());
989 void BluetoothLowEnergyEventRouter::GattCharacteristicValueChanged(
990 BluetoothAdapter* adapter,
991 BluetoothGattCharacteristic* characteristic,
992 const std::vector<uint8>& value) {
993 DCHECK_CURRENTLY_ON(BrowserThread::UI);
994 DCHECK_EQ(adapter, adapter_.get());
995 VLOG(2) << "GATT characteristic value changed: "
996 << characteristic->GetIdentifier();
998 BluetoothGattService* service = characteristic->GetService();
999 DCHECK(service);
1001 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
1002 service_id_to_device_address_.end());
1003 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
1004 chrc_id_to_service_id_.end());
1005 DCHECK(chrc_id_to_service_id_[characteristic->GetIdentifier()] ==
1006 service->GetIdentifier());
1008 // Send the event; manually construct the arguments, instead of using
1009 // apibtle::OnCharacteristicValueChanged::Create, as it doesn't convert
1010 // lists of enums correctly.
1011 apibtle::Characteristic api_characteristic;
1012 PopulateCharacteristic(characteristic, &api_characteristic);
1013 scoped_ptr<base::ListValue> args(new base::ListValue());
1014 args->Append(apibtle::CharacteristicToValue(&api_characteristic).release());
1016 DispatchEventToExtensionsWithPermission(
1017 apibtle::OnCharacteristicValueChanged::kEventName,
1018 service->GetUUID(),
1019 characteristic->GetIdentifier(),
1020 args.Pass());
1023 void BluetoothLowEnergyEventRouter::GattDescriptorValueChanged(
1024 BluetoothAdapter* adapter,
1025 BluetoothGattDescriptor* descriptor,
1026 const std::vector<uint8>& value) {
1027 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1028 DCHECK_EQ(adapter, adapter_.get());
1029 VLOG(2) << "GATT descriptor value changed: " << descriptor->GetIdentifier();
1031 BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic();
1032 DCHECK(characteristic);
1034 DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) !=
1035 desc_id_to_chrc_id_.end());
1036 DCHECK(characteristic->GetIdentifier() ==
1037 desc_id_to_chrc_id_[descriptor->GetIdentifier()]);
1039 // Send the event; manually construct the arguments, instead of using
1040 // apibtle::OnDescriptorValueChanged::Create, as it doesn't convert
1041 // lists of enums correctly.
1042 apibtle::Descriptor api_descriptor;
1043 PopulateDescriptor(descriptor, &api_descriptor);
1044 scoped_ptr<base::ListValue> args(new base::ListValue());
1045 args->Append(apibtle::DescriptorToValue(&api_descriptor).release());
1047 DispatchEventToExtensionsWithPermission(
1048 apibtle::OnDescriptorValueChanged::kEventName,
1049 characteristic->GetService()->GetUUID(),
1050 "" /* characteristic_id */,
1051 args.Pass());
1054 void BluetoothLowEnergyEventRouter::OnGetAdapter(
1055 const base::Closure& callback,
1056 scoped_refptr<device::BluetoothAdapter> adapter) {
1057 adapter_ = adapter;
1059 // Initialize instance ID mappings for all discovered GATT objects and add
1060 // observers.
1061 InitializeIdentifierMappings();
1062 adapter_->AddObserver(this);
1064 callback.Run();
1067 void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() {
1068 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1069 DCHECK(service_id_to_device_address_.empty());
1070 DCHECK(chrc_id_to_service_id_.empty());
1072 // Devices
1073 BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
1074 for (BluetoothAdapter::DeviceList::iterator iter = devices.begin();
1075 iter != devices.end();
1076 ++iter) {
1077 BluetoothDevice* device = *iter;
1079 // Services
1080 std::vector<BluetoothGattService*> services = device->GetGattServices();
1081 for (std::vector<BluetoothGattService*>::iterator siter = services.begin();
1082 siter != services.end();
1083 ++siter) {
1084 BluetoothGattService* service = *siter;
1086 const std::string& service_id = service->GetIdentifier();
1087 service_id_to_device_address_[service_id] = device->GetAddress();
1089 // Characteristics
1090 const std::vector<BluetoothGattCharacteristic*>& characteristics =
1091 service->GetCharacteristics();
1092 for (std::vector<BluetoothGattCharacteristic*>::const_iterator citer =
1093 characteristics.begin();
1094 citer != characteristics.end();
1095 ++citer) {
1096 BluetoothGattCharacteristic* characteristic = *citer;
1098 const std::string& chrc_id = characteristic->GetIdentifier();
1099 chrc_id_to_service_id_[chrc_id] = service_id;
1101 // Descriptors
1102 const std::vector<BluetoothGattDescriptor*>& descriptors =
1103 characteristic->GetDescriptors();
1104 for (std::vector<BluetoothGattDescriptor*>::const_iterator diter =
1105 descriptors.begin();
1106 diter != descriptors.end();
1107 ++diter) {
1108 BluetoothGattDescriptor* descriptor = *diter;
1110 const std::string& desc_id = descriptor->GetIdentifier();
1111 desc_id_to_chrc_id_[desc_id] = chrc_id;
1118 void BluetoothLowEnergyEventRouter::DispatchEventToExtensionsWithPermission(
1119 const std::string& event_name,
1120 const device::BluetoothUUID& uuid,
1121 const std::string& characteristic_id,
1122 scoped_ptr<base::ListValue> args) {
1123 // Obtain the listeners of |event_name|. The list can contain multiple
1124 // entries for the same extension, so we keep track of the extensions that we
1125 // already sent the event to, since we want the send an event to an extension
1126 // only once.
1127 BluetoothPermissionRequest request(uuid.value());
1128 std::set<std::string> handled_extensions;
1129 const EventListenerMap::ListenerList listeners =
1130 EventRouter::Get(browser_context_)->listeners().GetEventListenersByName(
1131 event_name);
1133 for (EventListenerMap::ListenerList::const_iterator iter = listeners.begin();
1134 iter != listeners.end();
1135 ++iter) {
1136 const std::string extension_id = (*iter)->extension_id();
1137 if (handled_extensions.find(extension_id) != handled_extensions.end())
1138 continue;
1140 handled_extensions.insert(extension_id);
1142 const Extension* extension =
1143 ExtensionRegistry::Get(browser_context_)
1144 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
1146 // For all API methods, the "low_energy" permission check is handled by
1147 // BluetoothLowEnergyExtensionFunction but for events we have to do the
1148 // check here.
1149 if (!BluetoothManifestData::CheckRequest(extension, request) ||
1150 !BluetoothManifestData::CheckLowEnergyPermitted(extension))
1151 continue;
1153 // If |event_name| is "onCharacteristicValueChanged", then send the
1154 // event only if the extension has requested notifications from the
1155 // related characteristic.
1156 if (event_name == apibtle::OnCharacteristicValueChanged::kEventName &&
1157 !characteristic_id.empty() &&
1158 !FindNotifySession(extension_id, characteristic_id))
1159 continue;
1161 // Send the event.
1162 scoped_ptr<base::ListValue> args_copy(args->DeepCopy());
1163 scoped_ptr<Event> event(new Event(event_name, args_copy.Pass()));
1164 EventRouter::Get(browser_context_)->DispatchEventToExtension(
1165 extension_id, event.Pass());
1169 BluetoothGattService* BluetoothLowEnergyEventRouter::FindServiceById(
1170 const std::string& instance_id) const {
1171 InstanceIdMap::const_iterator iter =
1172 service_id_to_device_address_.find(instance_id);
1173 if (iter == service_id_to_device_address_.end()) {
1174 VLOG(1) << "GATT service identifier unknown: " << instance_id;
1175 return NULL;
1178 const std::string& address = iter->second;
1180 BluetoothDevice* device = adapter_->GetDevice(address);
1181 if (!device) {
1182 VLOG(1) << "Bluetooth device not found: " << address;
1183 return NULL;
1186 BluetoothGattService* service = device->GetGattService(instance_id);
1187 if (!service) {
1188 VLOG(1) << "GATT service with ID \"" << instance_id
1189 << "\" not found on device \"" << address << "\"";
1190 return NULL;
1193 return service;
1196 BluetoothGattCharacteristic*
1197 BluetoothLowEnergyEventRouter::FindCharacteristicById(
1198 const std::string& instance_id) const {
1199 InstanceIdMap::const_iterator iter = chrc_id_to_service_id_.find(instance_id);
1200 if (iter == chrc_id_to_service_id_.end()) {
1201 VLOG(1) << "GATT characteristic identifier unknown: " << instance_id;
1202 return NULL;
1205 const std::string& service_id = iter->second;
1207 BluetoothGattService* service = FindServiceById(service_id);
1208 if (!service) {
1209 VLOG(1) << "Failed to obtain service for characteristic: " << instance_id;
1210 return NULL;
1213 BluetoothGattCharacteristic* characteristic =
1214 service->GetCharacteristic(instance_id);
1215 if (!characteristic) {
1216 VLOG(1) << "GATT characteristic with ID \"" << instance_id
1217 << "\" not found on service \"" << service_id << "\"";
1218 return NULL;
1221 return characteristic;
1224 BluetoothGattDescriptor* BluetoothLowEnergyEventRouter::FindDescriptorById(
1225 const std::string& instance_id) const {
1226 InstanceIdMap::const_iterator iter = desc_id_to_chrc_id_.find(instance_id);
1227 if (iter == desc_id_to_chrc_id_.end()) {
1228 VLOG(1) << "GATT descriptor identifier unknown: " << instance_id;
1229 return NULL;
1232 const std::string& chrc_id = iter->second;
1233 BluetoothGattCharacteristic* chrc = FindCharacteristicById(chrc_id);
1234 if (!chrc) {
1235 VLOG(1) << "Failed to obtain characteristic for descriptor: "
1236 << instance_id;
1237 return NULL;
1240 BluetoothGattDescriptor* descriptor = chrc->GetDescriptor(instance_id);
1241 if (!descriptor) {
1242 VLOG(1) << "GATT descriptor with ID \"" << instance_id
1243 << "\" not found on characteristic \"" << chrc_id << "\"";
1244 return NULL;
1247 return descriptor;
1250 void BluetoothLowEnergyEventRouter::OnValueSuccess(
1251 const base::Closure& callback,
1252 const std::vector<uint8>& value) {
1253 VLOG(2) << "Remote characteristic/descriptor value read successful.";
1254 callback.Run();
1257 void BluetoothLowEnergyEventRouter::OnCreateGattConnection(
1258 bool persistent,
1259 const std::string& extension_id,
1260 const std::string& device_address,
1261 const base::Closure& callback,
1262 scoped_ptr<BluetoothGattConnection> connection) {
1263 VLOG(2) << "GATT connection created.";
1264 DCHECK(connection.get());
1265 DCHECK(!FindConnection(extension_id, device_address));
1266 DCHECK_EQ(device_address, connection->GetDeviceAddress());
1268 const std::string connect_id = extension_id + device_address;
1269 DCHECK_NE(0U, connecting_devices_.count(connect_id));
1271 BluetoothLowEnergyConnection* conn = new BluetoothLowEnergyConnection(
1272 persistent, extension_id, connection.Pass());
1273 ConnectionResourceManager* manager =
1274 GetConnectionResourceManager(browser_context_);
1275 manager->Add(conn);
1277 connecting_devices_.erase(connect_id);
1278 callback.Run();
1281 void BluetoothLowEnergyEventRouter::OnDisconnect(
1282 const std::string& extension_id,
1283 const std::string& device_address,
1284 const base::Closure& callback) {
1285 VLOG(2) << "GATT connection terminated.";
1287 const std::string disconnect_id = extension_id + device_address;
1288 DCHECK_NE(0U, disconnecting_devices_.count(disconnect_id));
1290 if (!RemoveConnection(extension_id, device_address)) {
1291 VLOG(1) << "The connection was removed before disconnect completed, id: "
1292 << extension_id << ", device: " << device_address;
1295 disconnecting_devices_.erase(disconnect_id);
1296 callback.Run();
1299 void BluetoothLowEnergyEventRouter::OnError(
1300 const ErrorCallback& error_callback,
1301 BluetoothGattService::GattErrorCode error_code) {
1302 VLOG(2) << "Remote characteristic/descriptor value read/write failed.";
1304 error_callback.Run(GattErrorToRouterError(error_code));
1307 void BluetoothLowEnergyEventRouter::OnConnectError(
1308 const std::string& extension_id,
1309 const std::string& device_address,
1310 const ErrorCallback& error_callback,
1311 BluetoothDevice::ConnectErrorCode error_code) {
1312 VLOG(2) << "Failed to create GATT connection: " << error_code;
1314 const std::string connect_id = extension_id + device_address;
1315 DCHECK_NE(0U, connecting_devices_.count(connect_id));
1317 connecting_devices_.erase(connect_id);
1318 Status error_status = kStatusErrorFailed;
1319 if (error_code == BluetoothDevice::ERROR_INPROGRESS) {
1320 error_status = kStatusErrorInProgress;
1321 } else if (error_code == BluetoothDevice::ERROR_AUTH_FAILED ||
1322 error_code == BluetoothDevice::ERROR_AUTH_REJECTED) {
1323 error_status = kStatusErrorAuthenticationFailed;
1324 } else if (error_code == BluetoothDevice::ERROR_AUTH_CANCELED) {
1325 error_status = kStatusErrorCanceled;
1326 } else if (error_code == BluetoothDevice::ERROR_AUTH_TIMEOUT) {
1327 error_status = kStatusErrorTimeout;
1328 } else if (error_code == BluetoothDevice::ERROR_UNSUPPORTED_DEVICE) {
1329 error_status = kStatusErrorUnsupportedDevice;
1331 // ERROR_UNKNOWN and ERROR_FAILED defaulted to kStatusErrorFailed
1333 error_callback.Run(error_status);
1336 void BluetoothLowEnergyEventRouter::OnStartNotifySession(
1337 bool persistent,
1338 const std::string& extension_id,
1339 const std::string& characteristic_id,
1340 const base::Closure& callback,
1341 scoped_ptr<device::BluetoothGattNotifySession> session) {
1342 VLOG(2) << "Value update session created for characteristic: "
1343 << characteristic_id;
1344 DCHECK(session.get());
1345 DCHECK(!FindNotifySession(extension_id, characteristic_id));
1346 DCHECK_EQ(characteristic_id, session->GetCharacteristicIdentifier());
1348 const std::string session_id = extension_id + characteristic_id;
1349 DCHECK_NE(0U, pending_session_calls_.count(session_id));
1351 BluetoothLowEnergyNotifySession* resource =
1352 new BluetoothLowEnergyNotifySession(
1353 persistent, extension_id, session.Pass());
1355 NotifySessionResourceManager* manager =
1356 GetNotifySessionResourceManager(browser_context_);
1357 manager->Add(resource);
1359 pending_session_calls_.erase(session_id);
1360 callback.Run();
1363 void BluetoothLowEnergyEventRouter::OnStartNotifySessionError(
1364 const std::string& extension_id,
1365 const std::string& characteristic_id,
1366 const ErrorCallback& error_callback,
1367 device::BluetoothGattService::GattErrorCode error_code) {
1368 VLOG(2) << "Failed to create value update session for characteristic: "
1369 << characteristic_id;
1371 const std::string session_id = extension_id + characteristic_id;
1372 DCHECK_NE(0U, pending_session_calls_.count(session_id));
1374 pending_session_calls_.erase(session_id);
1375 error_callback.Run(GattErrorToRouterError(error_code));
1378 void BluetoothLowEnergyEventRouter::OnStopNotifySession(
1379 const std::string& extension_id,
1380 const std::string& characteristic_id,
1381 const base::Closure& callback) {
1382 VLOG(2) << "Value update session terminated.";
1384 if (!RemoveNotifySession(extension_id, characteristic_id)) {
1385 VLOG(1) << "The value update session was removed before Stop completed, "
1386 << "id: " << extension_id
1387 << ", characteristic: " << characteristic_id;
1390 callback.Run();
1393 BluetoothLowEnergyConnection* BluetoothLowEnergyEventRouter::FindConnection(
1394 const std::string& extension_id,
1395 const std::string& device_address) {
1396 ConnectionResourceManager* manager =
1397 GetConnectionResourceManager(browser_context_);
1399 base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
1400 if (!connection_ids)
1401 return NULL;
1403 for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
1404 iter != connection_ids->end();
1405 ++iter) {
1406 extensions::BluetoothLowEnergyConnection* conn =
1407 manager->Get(extension_id, *iter);
1408 if (!conn)
1409 continue;
1411 if (conn->GetConnection()->GetDeviceAddress() == device_address)
1412 return conn;
1415 return NULL;
1418 bool BluetoothLowEnergyEventRouter::RemoveConnection(
1419 const std::string& extension_id,
1420 const std::string& device_address) {
1421 ConnectionResourceManager* manager =
1422 GetConnectionResourceManager(browser_context_);
1424 base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
1425 if (!connection_ids)
1426 return false;
1428 for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
1429 iter != connection_ids->end();
1430 ++iter) {
1431 extensions::BluetoothLowEnergyConnection* conn =
1432 manager->Get(extension_id, *iter);
1433 if (!conn || conn->GetConnection()->GetDeviceAddress() != device_address)
1434 continue;
1436 manager->Remove(extension_id, *iter);
1437 return true;
1440 return false;
1443 BluetoothLowEnergyNotifySession*
1444 BluetoothLowEnergyEventRouter::FindNotifySession(
1445 const std::string& extension_id,
1446 const std::string& characteristic_id) {
1447 NotifySessionResourceManager* manager =
1448 GetNotifySessionResourceManager(browser_context_);
1450 base::hash_set<int>* ids = manager->GetResourceIds(extension_id);
1451 if (!ids)
1452 return NULL;
1454 for (base::hash_set<int>::const_iterator iter = ids->begin();
1455 iter != ids->end();
1456 ++iter) {
1457 BluetoothLowEnergyNotifySession* session =
1458 manager->Get(extension_id, *iter);
1459 if (!session)
1460 continue;
1462 if (session->GetSession()->GetCharacteristicIdentifier() ==
1463 characteristic_id)
1464 return session;
1467 return NULL;
1470 bool BluetoothLowEnergyEventRouter::RemoveNotifySession(
1471 const std::string& extension_id,
1472 const std::string& characteristic_id) {
1473 NotifySessionResourceManager* manager =
1474 GetNotifySessionResourceManager(browser_context_);
1476 base::hash_set<int>* ids = manager->GetResourceIds(extension_id);
1477 if (!ids)
1478 return false;
1480 for (base::hash_set<int>::const_iterator iter = ids->begin();
1481 iter != ids->end();
1482 ++iter) {
1483 BluetoothLowEnergyNotifySession* session =
1484 manager->Get(extension_id, *iter);
1485 if (!session ||
1486 session->GetSession()->GetCharacteristicIdentifier() !=
1487 characteristic_id)
1488 continue;
1490 manager->Remove(extension_id, *iter);
1491 return true;
1494 return false;
1497 } // namespace extensions