1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h" 6 7#include "base/bind.h" 8#include "base/logging.h" 9#include "base/values.h" 10#include "content/public/browser/browser_thread.h" 11#include "device/bluetooth/bluetooth_adapter_factory.h" 12#include "device/bluetooth/bluetooth_gatt_characteristic.h" 13#include "device/bluetooth/bluetooth_gatt_connection.h" 14#include "device/bluetooth/bluetooth_gatt_descriptor.h" 15#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.h" 16#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h" 17#include "extensions/browser/api/bluetooth_low_energy/utils.h" 18#include "extensions/browser/event_router.h" 19#include "extensions/browser/extension_registry.h" 20#include "extensions/common/api/bluetooth/bluetooth_manifest_data.h" 21 22using content::BrowserThread; 23 24using device::BluetoothAdapter; 25using device::BluetoothAdapterFactory; 26using device::BluetoothDevice; 27using device::BluetoothGattCharacteristic; 28using device::BluetoothGattConnection; 29using device::BluetoothGattDescriptor; 30using device::BluetoothGattService; 31 32namespace apibtle = extensions::core_api::bluetooth_low_energy; 33 34namespace { 35 36void PopulateService(const BluetoothGattService* service, 37 apibtle::Service* out) { 38 DCHECK(out); 39 40 out->uuid = service->GetUUID().canonical_value(); 41 out->is_primary = service->IsPrimary(); 42 out->is_local = service->IsLocal(); 43 out->instance_id.reset(new std::string(service->GetIdentifier())); 44 45 if (!service->GetDevice()) 46 return; 47 48 out->device_address.reset( 49 new std::string(service->GetDevice()->GetAddress())); 50} 51 52void PopulateCharacteristicProperties( 53 BluetoothGattCharacteristic::Properties properties, 54 std::vector<apibtle::CharacteristicProperty>* api_properties) { 55 DCHECK(api_properties && api_properties->empty()); 56 57 if (properties == BluetoothGattCharacteristic::kPropertyNone) 58 return; 59 60 if (properties & BluetoothGattCharacteristic::kPropertyBroadcast) 61 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_BROADCAST); 62 if (properties & BluetoothGattCharacteristic::kPropertyRead) 63 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_READ); 64 if (properties & BluetoothGattCharacteristic::kPropertyWriteWithoutResponse) { 65 api_properties->push_back( 66 apibtle::CHARACTERISTIC_PROPERTY_WRITEWITHOUTRESPONSE); 67 } 68 if (properties & BluetoothGattCharacteristic::kPropertyWrite) 69 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_WRITE); 70 if (properties & BluetoothGattCharacteristic::kPropertyNotify) 71 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_NOTIFY); 72 if (properties & BluetoothGattCharacteristic::kPropertyIndicate) 73 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_INDICATE); 74 if (properties & 75 BluetoothGattCharacteristic::kPropertyAuthenticatedSignedWrites) { 76 api_properties->push_back( 77 apibtle::CHARACTERISTIC_PROPERTY_AUTHENTICATEDSIGNEDWRITES); 78 } 79 if (properties & BluetoothGattCharacteristic::kPropertyExtendedProperties) { 80 api_properties->push_back( 81 apibtle::CHARACTERISTIC_PROPERTY_EXTENDEDPROPERTIES); 82 } 83 if (properties & BluetoothGattCharacteristic::kPropertyReliableWrite) 84 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_RELIABLEWRITE); 85 if (properties & BluetoothGattCharacteristic::kPropertyWritableAuxiliaries) { 86 api_properties->push_back( 87 apibtle::CHARACTERISTIC_PROPERTY_WRITABLEAUXILIARIES); 88 } 89} 90 91void PopulateCharacteristic(const BluetoothGattCharacteristic* characteristic, 92 apibtle::Characteristic* out) { 93 DCHECK(out); 94 95 out->uuid = characteristic->GetUUID().canonical_value(); 96 out->is_local = characteristic->IsLocal(); 97 out->instance_id.reset(new std::string(characteristic->GetIdentifier())); 98 99 PopulateService(characteristic->GetService(), &out->service); 100 PopulateCharacteristicProperties(characteristic->GetProperties(), 101 &out->properties); 102 103 const std::vector<uint8>& value = characteristic->GetValue(); 104 if (value.empty()) 105 return; 106 107 out->value.reset(new std::string(value.begin(), value.end())); 108} 109 110void PopulateDescriptor(const BluetoothGattDescriptor* descriptor, 111 apibtle::Descriptor* out) { 112 DCHECK(out); 113 114 out->uuid = descriptor->GetUUID().canonical_value(); 115 out->is_local = descriptor->IsLocal(); 116 out->instance_id.reset(new std::string(descriptor->GetIdentifier())); 117 118 PopulateCharacteristic(descriptor->GetCharacteristic(), &out->characteristic); 119 120 const std::vector<uint8>& value = descriptor->GetValue(); 121 if (value.empty()) 122 return; 123 124 out->value.reset(new std::string(value.begin(), value.end())); 125} 126 127typedef extensions::ApiResourceManager<extensions::BluetoothLowEnergyConnection> 128 ConnectionResourceManager; 129ConnectionResourceManager* GetConnectionResourceManager( 130 content::BrowserContext* context) { 131 ConnectionResourceManager* manager = ConnectionResourceManager::Get(context); 132 DCHECK(manager) 133 << "There is no Bluetooth low energy connection manager. " 134 "If this assertion is failing during a test, then it is likely that " 135 "TestExtensionSystem is failing to provide an instance of " 136 "ApiResourceManager<BluetoothLowEnergyConnection>."; 137 return manager; 138} 139 140typedef extensions::ApiResourceManager< 141 extensions::BluetoothLowEnergyNotifySession> NotifySessionResourceManager; 142NotifySessionResourceManager* GetNotifySessionResourceManager( 143 content::BrowserContext* context) { 144 NotifySessionResourceManager* manager = 145 NotifySessionResourceManager::Get(context); 146 DCHECK(manager) 147 << "There is no Bluetooth low energy value update session manager." 148 "If this assertion is failing during a test, then it is likely that " 149 "TestExtensionSystem is failing to provide an instance of " 150 "ApiResourceManager<BluetoothLowEnergyNotifySession>."; 151 return manager; 152} 153 154} // namespace 155 156namespace extensions { 157 158BluetoothLowEnergyEventRouter::BluetoothLowEnergyEventRouter( 159 content::BrowserContext* context) 160 : adapter_(NULL), browser_context_(context), weak_ptr_factory_(this) { 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 162 DCHECK(browser_context_); 163 VLOG(1) << "Initializing BluetoothLowEnergyEventRouter."; 164 165 if (!IsBluetoothSupported()) { 166 VLOG(1) << "Bluetooth not supported on the current platform."; 167 return; 168 } 169} 170 171BluetoothLowEnergyEventRouter::~BluetoothLowEnergyEventRouter() { 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 173 if (!adapter_.get()) 174 return; 175 176 adapter_->RemoveObserver(this); 177 adapter_ = NULL; 178} 179 180bool BluetoothLowEnergyEventRouter::IsBluetoothSupported() const { 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 182 return adapter_.get() || 183 BluetoothAdapterFactory::IsBluetoothAdapterAvailable(); 184} 185 186bool BluetoothLowEnergyEventRouter::InitializeAdapterAndInvokeCallback( 187 const base::Closure& callback) { 188 if (!IsBluetoothSupported()) 189 return false; 190 191 if (adapter_.get()) { 192 callback.Run(); 193 return true; 194 } 195 196 BluetoothAdapterFactory::GetAdapter( 197 base::Bind(&BluetoothLowEnergyEventRouter::OnGetAdapter, 198 weak_ptr_factory_.GetWeakPtr(), 199 callback)); 200 return true; 201} 202 203bool BluetoothLowEnergyEventRouter::HasAdapter() const { 204 return (adapter_.get() != NULL); 205} 206 207void BluetoothLowEnergyEventRouter::Connect( 208 bool persistent, 209 const Extension* extension, 210 const std::string& device_address, 211 const base::Closure& callback, 212 const ErrorCallback& error_callback) { 213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 214 if (!adapter_.get()) { 215 VLOG(1) << "BluetoothAdapter not ready."; 216 error_callback.Run(kStatusErrorFailed); 217 return; 218 } 219 220 const std::string extension_id = extension->id(); 221 const std::string connect_id = extension_id + device_address; 222 223 if (connecting_devices_.count(connect_id) != 0) { 224 error_callback.Run(kStatusErrorInProgress); 225 return; 226 } 227 228 BluetoothLowEnergyConnection* conn = 229 FindConnection(extension_id, device_address); 230 if (conn) { 231 if (conn->GetConnection()->IsConnected()) { 232 VLOG(1) << "Application already connected to device: " << device_address; 233 error_callback.Run(kStatusErrorAlreadyConnected); 234 return; 235 } 236 237 // There is a connection object but it's no longer active. Simply remove it. 238 RemoveConnection(extension_id, device_address); 239 } 240 241 BluetoothDevice* device = adapter_->GetDevice(device_address); 242 if (!device) { 243 VLOG(1) << "Bluetooth device not found: " << device_address; 244 error_callback.Run(kStatusErrorNotFound); 245 return; 246 } 247 248 connecting_devices_.insert(connect_id); 249 device->CreateGattConnection( 250 base::Bind(&BluetoothLowEnergyEventRouter::OnCreateGattConnection, 251 weak_ptr_factory_.GetWeakPtr(), 252 persistent, 253 extension_id, 254 device_address, 255 callback), 256 base::Bind(&BluetoothLowEnergyEventRouter::OnConnectError, 257 weak_ptr_factory_.GetWeakPtr(), 258 extension_id, 259 device_address, 260 error_callback)); 261} 262 263void BluetoothLowEnergyEventRouter::Disconnect( 264 const Extension* extension, 265 const std::string& device_address, 266 const base::Closure& callback, 267 const ErrorCallback& error_callback) { 268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 269 if (!adapter_.get()) { 270 VLOG(1) << "BluetoothAdapter not ready."; 271 error_callback.Run(kStatusErrorFailed); 272 return; 273 } 274 275 const std::string extension_id = extension->id(); 276 const std::string disconnect_id = extension_id + device_address; 277 278 if (disconnecting_devices_.count(disconnect_id) != 0) { 279 error_callback.Run(kStatusErrorInProgress); 280 return; 281 } 282 283 BluetoothLowEnergyConnection* conn = 284 FindConnection(extension_id, device_address); 285 if (!conn || !conn->GetConnection()->IsConnected()) { 286 VLOG(1) << "Application not connected to device: " << device_address; 287 error_callback.Run(kStatusErrorNotConnected); 288 return; 289 } 290 291 disconnecting_devices_.insert(disconnect_id); 292 conn->GetConnection()->Disconnect( 293 base::Bind(&BluetoothLowEnergyEventRouter::OnDisconnect, 294 weak_ptr_factory_.GetWeakPtr(), 295 extension_id, 296 device_address, 297 callback)); 298} 299 300bool BluetoothLowEnergyEventRouter::GetServices( 301 const std::string& device_address, 302 ServiceList* out_services) const { 303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 304 DCHECK(out_services); 305 if (!adapter_.get()) { 306 VLOG(1) << "BluetoothAdapter not ready."; 307 return false; 308 } 309 310 BluetoothDevice* device = adapter_->GetDevice(device_address); 311 if (!device) { 312 VLOG(1) << "Bluetooth device not found: " << device_address; 313 return false; 314 } 315 316 out_services->clear(); 317 318 const std::vector<BluetoothGattService*>& services = 319 device->GetGattServices(); 320 for (std::vector<BluetoothGattService*>::const_iterator iter = 321 services.begin(); 322 iter != services.end(); 323 ++iter) { 324 // Populate an API service and add it to the return value. 325 const BluetoothGattService* service = *iter; 326 linked_ptr<apibtle::Service> api_service(new apibtle::Service()); 327 PopulateService(service, api_service.get()); 328 329 out_services->push_back(api_service); 330 } 331 332 return true; 333} 334 335BluetoothLowEnergyEventRouter::Status BluetoothLowEnergyEventRouter::GetService( 336 const std::string& instance_id, 337 apibtle::Service* out_service) const { 338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 339 DCHECK(out_service); 340 if (!adapter_.get()) { 341 VLOG(1) << "BluetoothAdapter not ready."; 342 return kStatusErrorFailed; 343 } 344 345 BluetoothGattService* gatt_service = FindServiceById(instance_id); 346 if (!gatt_service) { 347 VLOG(1) << "Service not found: " << instance_id; 348 return kStatusErrorNotFound; 349 } 350 351 PopulateService(gatt_service, out_service); 352 return kStatusSuccess; 353} 354 355BluetoothLowEnergyEventRouter::Status 356BluetoothLowEnergyEventRouter::GetIncludedServices( 357 const std::string& instance_id, 358 ServiceList* out_services) const { 359 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 360 DCHECK(out_services); 361 if (!adapter_.get()) { 362 VLOG(1) << "BluetoothAdapter not ready."; 363 return kStatusErrorFailed; 364 } 365 366 BluetoothGattService* service = FindServiceById(instance_id); 367 if (!service) { 368 VLOG(1) << "Service not found: " << instance_id; 369 return kStatusErrorNotFound; 370 } 371 372 out_services->clear(); 373 374 const std::vector<BluetoothGattService*>& includes = 375 service->GetIncludedServices(); 376 for (std::vector<BluetoothGattService*>::const_iterator iter = 377 includes.begin(); 378 iter != includes.end(); 379 ++iter) { 380 // Populate an API service and add it to the return value. 381 const BluetoothGattService* included = *iter; 382 linked_ptr<apibtle::Service> api_service(new apibtle::Service()); 383 PopulateService(included, api_service.get()); 384 385 out_services->push_back(api_service); 386 } 387 388 return kStatusSuccess; 389} 390 391BluetoothLowEnergyEventRouter::Status 392BluetoothLowEnergyEventRouter::GetCharacteristics( 393 const Extension* extension, 394 const std::string& instance_id, 395 CharacteristicList* out_characteristics) const { 396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 397 DCHECK(extension); 398 DCHECK(out_characteristics); 399 if (!adapter_.get()) { 400 VLOG(1) << "BlutoothAdapter not ready."; 401 return kStatusErrorFailed; 402 } 403 404 BluetoothGattService* service = FindServiceById(instance_id); 405 if (!service) { 406 VLOG(1) << "Service not found: " << instance_id; 407 return kStatusErrorNotFound; 408 } 409 410 BluetoothPermissionRequest request(service->GetUUID().value()); 411 if (!BluetoothManifestData::CheckRequest(extension, request)) { 412 VLOG(1) << "App has no permission to access the characteristics of this " 413 << "service: " << instance_id; 414 return kStatusErrorPermissionDenied; 415 } 416 417 out_characteristics->clear(); 418 419 const std::vector<BluetoothGattCharacteristic*>& characteristics = 420 service->GetCharacteristics(); 421 for (std::vector<BluetoothGattCharacteristic*>::const_iterator iter = 422 characteristics.begin(); 423 iter != characteristics.end(); 424 ++iter) { 425 // Populate an API characteristic and add it to the return value. 426 const BluetoothGattCharacteristic* characteristic = *iter; 427 linked_ptr<apibtle::Characteristic> api_characteristic( 428 new apibtle::Characteristic()); 429 PopulateCharacteristic(characteristic, api_characteristic.get()); 430 431 out_characteristics->push_back(api_characteristic); 432 } 433 434 return kStatusSuccess; 435} 436 437BluetoothLowEnergyEventRouter::Status 438BluetoothLowEnergyEventRouter::GetCharacteristic( 439 const Extension* extension, 440 const std::string& instance_id, 441 apibtle::Characteristic* out_characteristic) const { 442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 443 DCHECK(extension); 444 DCHECK(out_characteristic); 445 if (!adapter_.get()) { 446 VLOG(1) << "BluetoothAdapter not ready."; 447 return kStatusErrorFailed; 448 } 449 450 BluetoothGattCharacteristic* characteristic = 451 FindCharacteristicById(instance_id); 452 if (!characteristic) { 453 VLOG(1) << "Characteristic not found: " << instance_id; 454 return kStatusErrorNotFound; 455 } 456 457 BluetoothPermissionRequest request( 458 characteristic->GetService()->GetUUID().value()); 459 if (!BluetoothManifestData::CheckRequest(extension, request)) { 460 VLOG(1) << "App has no permission to access this characteristic: " 461 << instance_id; 462 return kStatusErrorPermissionDenied; 463 } 464 465 PopulateCharacteristic(characteristic, out_characteristic); 466 return kStatusSuccess; 467} 468 469BluetoothLowEnergyEventRouter::Status 470BluetoothLowEnergyEventRouter::GetDescriptors( 471 const Extension* extension, 472 const std::string& instance_id, 473 DescriptorList* out_descriptors) const { 474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 475 DCHECK(extension); 476 DCHECK(out_descriptors); 477 if (!adapter_.get()) { 478 VLOG(1) << "BlutoothAdapter not ready."; 479 return kStatusErrorFailed; 480 } 481 482 BluetoothGattCharacteristic* characteristic = 483 FindCharacteristicById(instance_id); 484 if (!characteristic) { 485 VLOG(1) << "Characteristic not found: " << instance_id; 486 return kStatusErrorNotFound; 487 } 488 489 BluetoothPermissionRequest request( 490 characteristic->GetService()->GetUUID().value()); 491 if (!BluetoothManifestData::CheckRequest(extension, request)) { 492 VLOG(1) << "App has no permission to access the descriptors of this " 493 << "characteristic: " << instance_id; 494 return kStatusErrorPermissionDenied; 495 } 496 497 out_descriptors->clear(); 498 499 const std::vector<BluetoothGattDescriptor*>& descriptors = 500 characteristic->GetDescriptors(); 501 for (std::vector<BluetoothGattDescriptor*>::const_iterator iter = 502 descriptors.begin(); 503 iter != descriptors.end(); 504 ++iter) { 505 // Populate an API descriptor and add it to the return value. 506 const BluetoothGattDescriptor* descriptor = *iter; 507 linked_ptr<apibtle::Descriptor> api_descriptor(new apibtle::Descriptor()); 508 PopulateDescriptor(descriptor, api_descriptor.get()); 509 510 out_descriptors->push_back(api_descriptor); 511 } 512 513 return kStatusSuccess; 514} 515 516BluetoothLowEnergyEventRouter::Status 517BluetoothLowEnergyEventRouter::GetDescriptor( 518 const Extension* extension, 519 const std::string& instance_id, 520 core_api::bluetooth_low_energy::Descriptor* out_descriptor) const { 521 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 522 DCHECK(extension); 523 DCHECK(out_descriptor); 524 if (!adapter_.get()) { 525 VLOG(1) << "BluetoothAdapter not ready."; 526 return kStatusErrorFailed; 527 } 528 529 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id); 530 if (!descriptor) { 531 VLOG(1) << "Descriptor not found: " << instance_id; 532 return kStatusErrorNotFound; 533 } 534 535 BluetoothPermissionRequest request( 536 descriptor->GetCharacteristic()->GetService()->GetUUID().value()); 537 if (!BluetoothManifestData::CheckRequest(extension, request)) { 538 VLOG(1) << "App has no permission to access this descriptor: " 539 << instance_id; 540 return kStatusErrorPermissionDenied; 541 } 542 543 PopulateDescriptor(descriptor, out_descriptor); 544 return kStatusSuccess; 545} 546 547void BluetoothLowEnergyEventRouter::ReadCharacteristicValue( 548 const Extension* extension, 549 const std::string& instance_id, 550 const base::Closure& callback, 551 const ErrorCallback& error_callback) { 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 553 DCHECK(extension); 554 if (!adapter_.get()) { 555 VLOG(1) << "BluetoothAdapter not ready."; 556 error_callback.Run(kStatusErrorFailed); 557 return; 558 } 559 560 BluetoothGattCharacteristic* characteristic = 561 FindCharacteristicById(instance_id); 562 if (!characteristic) { 563 VLOG(1) << "Characteristic not found: " << instance_id; 564 error_callback.Run(kStatusErrorNotFound); 565 return; 566 } 567 568 BluetoothPermissionRequest request( 569 characteristic->GetService()->GetUUID().value()); 570 if (!BluetoothManifestData::CheckRequest(extension, request)) { 571 VLOG(1) << "App has no permission to access this characteristic: " 572 << instance_id; 573 error_callback.Run(kStatusErrorPermissionDenied); 574 return; 575 } 576 577 characteristic->ReadRemoteCharacteristic( 578 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess, 579 weak_ptr_factory_.GetWeakPtr(), 580 callback), 581 base::Bind(&BluetoothLowEnergyEventRouter::OnError, 582 weak_ptr_factory_.GetWeakPtr(), 583 error_callback)); 584} 585 586void BluetoothLowEnergyEventRouter::WriteCharacteristicValue( 587 const Extension* extension, 588 const std::string& instance_id, 589 const std::vector<uint8>& value, 590 const base::Closure& callback, 591 const ErrorCallback& error_callback) { 592 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 593 DCHECK(extension); 594 if (!adapter_.get()) { 595 VLOG(1) << "BluetoothAdapter not ready."; 596 error_callback.Run(kStatusErrorFailed); 597 return; 598 } 599 600 BluetoothGattCharacteristic* characteristic = 601 FindCharacteristicById(instance_id); 602 if (!characteristic) { 603 VLOG(1) << "Characteristic not found: " << instance_id; 604 error_callback.Run(kStatusErrorNotFound); 605 return; 606 } 607 608 BluetoothPermissionRequest request( 609 characteristic->GetService()->GetUUID().value()); 610 if (!BluetoothManifestData::CheckRequest(extension, request)) { 611 VLOG(1) << "App has no permission to access this characteristic: " 612 << instance_id; 613 error_callback.Run(kStatusErrorPermissionDenied); 614 return; 615 } 616 617 characteristic->WriteRemoteCharacteristic( 618 value, 619 callback, 620 base::Bind(&BluetoothLowEnergyEventRouter::OnError, 621 weak_ptr_factory_.GetWeakPtr(), 622 error_callback)); 623} 624 625void BluetoothLowEnergyEventRouter::StartCharacteristicNotifications( 626 bool persistent, 627 const Extension* extension, 628 const std::string& instance_id, 629 const base::Closure& callback, 630 const ErrorCallback& error_callback) { 631 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 632 if (!adapter_.get()) { 633 VLOG(1) << "BluetoothAdapter not ready."; 634 error_callback.Run(kStatusErrorFailed); 635 return; 636 } 637 638 const std::string extension_id = extension->id(); 639 const std::string session_id = extension_id + instance_id; 640 641 if (pending_session_calls_.count(session_id) != 0) { 642 error_callback.Run(kStatusErrorInProgress); 643 return; 644 } 645 646 BluetoothLowEnergyNotifySession* session = 647 FindNotifySession(extension_id, instance_id); 648 if (session) { 649 if (session->GetSession()->IsActive()) { 650 VLOG(1) << "Application has already enabled notifications from " 651 << "characteristic: " << instance_id; 652 error_callback.Run(kStatusErrorAlreadyNotifying); 653 return; 654 } 655 656 RemoveNotifySession(extension_id, instance_id); 657 } 658 659 BluetoothGattCharacteristic* characteristic = 660 FindCharacteristicById(instance_id); 661 if (!characteristic) { 662 VLOG(1) << "Characteristic not found: " << instance_id; 663 error_callback.Run(kStatusErrorNotFound); 664 return; 665 } 666 667 BluetoothPermissionRequest request( 668 characteristic->GetService()->GetUUID().value()); 669 if (!BluetoothManifestData::CheckRequest(extension, request)) { 670 VLOG(1) << "App has no permission to access this characteristic: " 671 << instance_id; 672 error_callback.Run(kStatusErrorPermissionDenied); 673 return; 674 } 675 676 pending_session_calls_.insert(session_id); 677 characteristic->StartNotifySession( 678 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySession, 679 weak_ptr_factory_.GetWeakPtr(), 680 persistent, 681 extension_id, 682 instance_id, 683 callback), 684 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySessionError, 685 weak_ptr_factory_.GetWeakPtr(), 686 extension_id, 687 instance_id, 688 error_callback)); 689} 690 691void BluetoothLowEnergyEventRouter::StopCharacteristicNotifications( 692 const Extension* extension, 693 const std::string& instance_id, 694 const base::Closure& callback, 695 const ErrorCallback& error_callback) { 696 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 697 if (!adapter_.get()) { 698 VLOG(1) << "BluetoothAdapter not ready."; 699 error_callback.Run(kStatusErrorFailed); 700 return; 701 } 702 703 const std::string extension_id = extension->id(); 704 705 BluetoothLowEnergyNotifySession* session = 706 FindNotifySession(extension_id, instance_id); 707 if (!session || !session->GetSession()->IsActive()) { 708 VLOG(1) << "Application has not enabled notifications from " 709 << "characteristic: " << instance_id; 710 error_callback.Run(kStatusErrorNotNotifying); 711 return; 712 } 713 714 session->GetSession()->Stop( 715 base::Bind(&BluetoothLowEnergyEventRouter::OnStopNotifySession, 716 weak_ptr_factory_.GetWeakPtr(), 717 extension_id, 718 instance_id, 719 callback)); 720} 721 722void BluetoothLowEnergyEventRouter::ReadDescriptorValue( 723 const Extension* extension, 724 const std::string& instance_id, 725 const base::Closure& callback, 726 const ErrorCallback& error_callback) { 727 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 728 DCHECK(extension); 729 if (!adapter_.get()) { 730 VLOG(1) << "BluetoothAdapter not ready."; 731 error_callback.Run(kStatusErrorFailed); 732 return; 733 } 734 735 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id); 736 if (!descriptor) { 737 VLOG(1) << "Descriptor not found: " << instance_id; 738 error_callback.Run(kStatusErrorNotFound); 739 return; 740 } 741 742 BluetoothPermissionRequest request( 743 descriptor->GetCharacteristic()->GetService()->GetUUID().value()); 744 if (!BluetoothManifestData::CheckRequest(extension, request)) { 745 VLOG(1) << "App has no permission to access this descriptor: " 746 << instance_id; 747 error_callback.Run(kStatusErrorPermissionDenied); 748 return; 749 } 750 751 descriptor->ReadRemoteDescriptor( 752 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess, 753 weak_ptr_factory_.GetWeakPtr(), 754 callback), 755 base::Bind(&BluetoothLowEnergyEventRouter::OnError, 756 weak_ptr_factory_.GetWeakPtr(), 757 error_callback)); 758} 759 760void BluetoothLowEnergyEventRouter::WriteDescriptorValue( 761 const Extension* extension, 762 const std::string& instance_id, 763 const std::vector<uint8>& value, 764 const base::Closure& callback, 765 const ErrorCallback& error_callback) { 766 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 767 DCHECK(extension); 768 if (!adapter_.get()) { 769 VLOG(1) << "BluetoothAdapter not ready."; 770 error_callback.Run(kStatusErrorFailed); 771 return; 772 } 773 774 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id); 775 if (!descriptor) { 776 VLOG(1) << "Descriptor not found: " << instance_id; 777 error_callback.Run(kStatusErrorNotFound); 778 return; 779 } 780 781 BluetoothPermissionRequest request( 782 descriptor->GetCharacteristic()->GetService()->GetUUID().value()); 783 if (!BluetoothManifestData::CheckRequest(extension, request)) { 784 VLOG(1) << "App has no permission to access this descriptor: " 785 << instance_id; 786 error_callback.Run(kStatusErrorPermissionDenied); 787 return; 788 } 789 790 descriptor->WriteRemoteDescriptor( 791 value, 792 callback, 793 base::Bind(&BluetoothLowEnergyEventRouter::OnError, 794 weak_ptr_factory_.GetWeakPtr(), 795 error_callback)); 796} 797 798void BluetoothLowEnergyEventRouter::SetAdapterForTesting( 799 device::BluetoothAdapter* adapter) { 800 adapter_ = adapter; 801 InitializeIdentifierMappings(); 802} 803 804void BluetoothLowEnergyEventRouter::GattServiceAdded( 805 BluetoothAdapter* adapter, 806 BluetoothDevice* device, 807 BluetoothGattService* service) { 808 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 809 DCHECK_EQ(adapter, adapter_.get()); 810 VLOG(2) << "GATT service added: " << service->GetIdentifier(); 811 812 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) == 813 service_id_to_device_address_.end()); 814 815 service_id_to_device_address_[service->GetIdentifier()] = 816 device->GetAddress(); 817} 818 819void BluetoothLowEnergyEventRouter::GattServiceRemoved( 820 BluetoothAdapter* adapter, 821 BluetoothDevice* device, 822 BluetoothGattService* service) { 823 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 824 DCHECK_EQ(adapter, adapter_.get()); 825 VLOG(2) << "GATT service removed: " << service->GetIdentifier(); 826 827 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 828 service_id_to_device_address_.end()); 829 830 DCHECK(device->GetAddress() == 831 service_id_to_device_address_[service->GetIdentifier()]); 832 service_id_to_device_address_.erase(service->GetIdentifier()); 833 834 // Signal API event. 835 apibtle::Service api_service; 836 PopulateService(service, &api_service); 837 838 scoped_ptr<base::ListValue> args = 839 apibtle::OnServiceRemoved::Create(api_service); 840 scoped_ptr<Event> event( 841 new Event(apibtle::OnServiceRemoved::kEventName, args.Pass())); 842 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); 843} 844 845void BluetoothLowEnergyEventRouter::GattDiscoveryCompleteForService( 846 BluetoothAdapter* adapter, 847 BluetoothGattService* service) { 848 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 849 DCHECK_EQ(adapter, adapter_.get()); 850 VLOG(2) << "GATT service discovery complete: " << service->GetIdentifier(); 851 852 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 853 service_id_to_device_address_.end()); 854 855 // Signal the service added event here. 856 apibtle::Service api_service; 857 PopulateService(service, &api_service); 858 859 scoped_ptr<base::ListValue> args = 860 apibtle::OnServiceAdded::Create(api_service); 861 scoped_ptr<Event> event( 862 new Event(apibtle::OnServiceAdded::kEventName, args.Pass())); 863 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); 864} 865 866void BluetoothLowEnergyEventRouter::GattServiceChanged( 867 BluetoothAdapter* adapter, 868 BluetoothGattService* service) { 869 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 870 DCHECK_EQ(adapter, adapter_.get()); 871 VLOG(2) << "GATT service changed: " << service->GetIdentifier(); 872 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 873 service_id_to_device_address_.end()); 874 875 // Signal API event. 876 apibtle::Service api_service; 877 PopulateService(service, &api_service); 878 879 DispatchEventToExtensionsWithPermission( 880 apibtle::OnServiceChanged::kEventName, 881 service->GetUUID(), 882 "" /* characteristic_id */, 883 apibtle::OnServiceChanged::Create(api_service)); 884} 885 886void BluetoothLowEnergyEventRouter::GattCharacteristicAdded( 887 BluetoothAdapter* adapter, 888 BluetoothGattCharacteristic* characteristic) { 889 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 890 DCHECK_EQ(adapter, adapter_.get()); 891 VLOG(2) << "GATT characteristic added: " << characteristic->GetIdentifier(); 892 893 BluetoothGattService* service = characteristic->GetService(); 894 DCHECK(service); 895 896 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) == 897 chrc_id_to_service_id_.end()); 898 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 899 service_id_to_device_address_.end()); 900 901 chrc_id_to_service_id_[characteristic->GetIdentifier()] = 902 service->GetIdentifier(); 903} 904 905void BluetoothLowEnergyEventRouter::GattCharacteristicRemoved( 906 BluetoothAdapter* adapter, 907 BluetoothGattCharacteristic* characteristic) { 908 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 909 DCHECK_EQ(adapter, adapter_.get()); 910 VLOG(2) << "GATT characteristic removed: " << characteristic->GetIdentifier(); 911 912 BluetoothGattService* service = characteristic->GetService(); 913 DCHECK(service); 914 915 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) != 916 chrc_id_to_service_id_.end()); 917 DCHECK(service->GetIdentifier() == 918 chrc_id_to_service_id_[characteristic->GetIdentifier()]); 919 920 chrc_id_to_service_id_.erase(characteristic->GetIdentifier()); 921} 922 923void BluetoothLowEnergyEventRouter::GattDescriptorAdded( 924 BluetoothAdapter* adapter, 925 BluetoothGattDescriptor* descriptor) { 926 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 927 DCHECK_EQ(adapter, adapter_.get()); 928 VLOG(2) << "GATT descriptor added: " << descriptor->GetIdentifier(); 929 930 BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic(); 931 DCHECK(characteristic); 932 933 DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) == 934 desc_id_to_chrc_id_.end()); 935 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) != 936 chrc_id_to_service_id_.end()); 937 938 desc_id_to_chrc_id_[descriptor->GetIdentifier()] = 939 characteristic->GetIdentifier(); 940} 941 942void BluetoothLowEnergyEventRouter::GattDescriptorRemoved( 943 BluetoothAdapter* adapter, 944 BluetoothGattDescriptor* descriptor) { 945 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 946 DCHECK_EQ(adapter, adapter_.get()); 947 VLOG(2) << "GATT descriptor removed: " << descriptor->GetIdentifier(); 948 949 BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic(); 950 DCHECK(characteristic); 951 952 DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) != 953 desc_id_to_chrc_id_.end()); 954 DCHECK(characteristic->GetIdentifier() == 955 desc_id_to_chrc_id_[descriptor->GetIdentifier()]); 956 957 desc_id_to_chrc_id_.erase(descriptor->GetIdentifier()); 958} 959 960void BluetoothLowEnergyEventRouter::GattCharacteristicValueChanged( 961 BluetoothAdapter* adapter, 962 BluetoothGattCharacteristic* characteristic, 963 const std::vector<uint8>& value) { 964 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 965 DCHECK_EQ(adapter, adapter_.get()); 966 VLOG(2) << "GATT characteristic value changed: " 967 << characteristic->GetIdentifier(); 968 969 BluetoothGattService* service = characteristic->GetService(); 970 DCHECK(service); 971 972 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 973 service_id_to_device_address_.end()); 974 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) != 975 chrc_id_to_service_id_.end()); 976 DCHECK(chrc_id_to_service_id_[characteristic->GetIdentifier()] == 977 service->GetIdentifier()); 978 979 // Send the event; manually construct the arguments, instead of using 980 // apibtle::OnCharacteristicValueChanged::Create, as it doesn't convert 981 // lists of enums correctly. 982 apibtle::Characteristic api_characteristic; 983 PopulateCharacteristic(characteristic, &api_characteristic); 984 scoped_ptr<base::ListValue> args(new base::ListValue()); 985 args->Append(apibtle::CharacteristicToValue(&api_characteristic).release()); 986 987 DispatchEventToExtensionsWithPermission( 988 apibtle::OnCharacteristicValueChanged::kEventName, 989 service->GetUUID(), 990 characteristic->GetIdentifier(), 991 args.Pass()); 992} 993 994void BluetoothLowEnergyEventRouter::GattDescriptorValueChanged( 995 BluetoothAdapter* adapter, 996 BluetoothGattDescriptor* descriptor, 997 const std::vector<uint8>& value) { 998 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 999 DCHECK_EQ(adapter, adapter_.get()); 1000 VLOG(2) << "GATT descriptor value changed: " << descriptor->GetIdentifier(); 1001 1002 BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic(); 1003 DCHECK(characteristic); 1004 1005 DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) != 1006 desc_id_to_chrc_id_.end()); 1007 DCHECK(characteristic->GetIdentifier() == 1008 desc_id_to_chrc_id_[descriptor->GetIdentifier()]); 1009 1010 // Send the event; manually construct the arguments, instead of using 1011 // apibtle::OnDescriptorValueChanged::Create, as it doesn't convert 1012 // lists of enums correctly. 1013 apibtle::Descriptor api_descriptor; 1014 PopulateDescriptor(descriptor, &api_descriptor); 1015 scoped_ptr<base::ListValue> args(new base::ListValue()); 1016 args->Append(apibtle::DescriptorToValue(&api_descriptor).release()); 1017 1018 DispatchEventToExtensionsWithPermission( 1019 apibtle::OnDescriptorValueChanged::kEventName, 1020 characteristic->GetService()->GetUUID(), 1021 "" /* characteristic_id */, 1022 args.Pass()); 1023} 1024 1025void BluetoothLowEnergyEventRouter::OnGetAdapter( 1026 const base::Closure& callback, 1027 scoped_refptr<device::BluetoothAdapter> adapter) { 1028 adapter_ = adapter; 1029 1030 // Initialize instance ID mappings for all discovered GATT objects and add 1031 // observers. 1032 InitializeIdentifierMappings(); 1033 adapter_->AddObserver(this); 1034 1035 callback.Run(); 1036} 1037 1038void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() { 1039 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1040 DCHECK(service_id_to_device_address_.empty()); 1041 DCHECK(chrc_id_to_service_id_.empty()); 1042 1043 // Devices 1044 BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); 1045 for (BluetoothAdapter::DeviceList::iterator iter = devices.begin(); 1046 iter != devices.end(); 1047 ++iter) { 1048 BluetoothDevice* device = *iter; 1049 1050 // Services 1051 std::vector<BluetoothGattService*> services = device->GetGattServices(); 1052 for (std::vector<BluetoothGattService*>::iterator siter = services.begin(); 1053 siter != services.end(); 1054 ++siter) { 1055 BluetoothGattService* service = *siter; 1056 1057 const std::string& service_id = service->GetIdentifier(); 1058 service_id_to_device_address_[service_id] = device->GetAddress(); 1059 1060 // Characteristics 1061 const std::vector<BluetoothGattCharacteristic*>& characteristics = 1062 service->GetCharacteristics(); 1063 for (std::vector<BluetoothGattCharacteristic*>::const_iterator citer = 1064 characteristics.begin(); 1065 citer != characteristics.end(); 1066 ++citer) { 1067 BluetoothGattCharacteristic* characteristic = *citer; 1068 1069 const std::string& chrc_id = characteristic->GetIdentifier(); 1070 chrc_id_to_service_id_[chrc_id] = service_id; 1071 1072 // Descriptors 1073 const std::vector<BluetoothGattDescriptor*>& descriptors = 1074 characteristic->GetDescriptors(); 1075 for (std::vector<BluetoothGattDescriptor*>::const_iterator diter = 1076 descriptors.begin(); 1077 diter != descriptors.end(); 1078 ++diter) { 1079 BluetoothGattDescriptor* descriptor = *diter; 1080 1081 const std::string& desc_id = descriptor->GetIdentifier(); 1082 desc_id_to_chrc_id_[desc_id] = chrc_id; 1083 } 1084 } 1085 } 1086 } 1087} 1088 1089void BluetoothLowEnergyEventRouter::DispatchEventToExtensionsWithPermission( 1090 const std::string& event_name, 1091 const device::BluetoothUUID& uuid, 1092 const std::string& characteristic_id, 1093 scoped_ptr<base::ListValue> args) { 1094 // Obtain the listeners of |event_name|. The list can contain multiple 1095 // entries for the same extension, so we keep track of the extensions that we 1096 // already sent the event to, since we want the send an event to an extension 1097 // only once. 1098 BluetoothPermissionRequest request(uuid.value()); 1099 std::set<std::string> handled_extensions; 1100 const EventListenerMap::ListenerList listeners = 1101 EventRouter::Get(browser_context_)->listeners().GetEventListenersByName( 1102 event_name); 1103 1104 for (EventListenerMap::ListenerList::const_iterator iter = listeners.begin(); 1105 iter != listeners.end(); 1106 ++iter) { 1107 const std::string extension_id = (*iter)->extension_id(); 1108 if (handled_extensions.find(extension_id) != handled_extensions.end()) 1109 continue; 1110 1111 handled_extensions.insert(extension_id); 1112 1113 const Extension* extension = 1114 ExtensionRegistry::Get(browser_context_) 1115 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); 1116 1117 // For all API methods, the "low_energy" permission check is handled by 1118 // BluetoothLowEnergyExtensionFunction but for events we have to do the 1119 // check here. 1120 if (!BluetoothManifestData::CheckRequest(extension, request) || 1121 !BluetoothManifestData::CheckLowEnergyPermitted(extension)) 1122 continue; 1123 1124 // If |event_name| is "onCharacteristicValueChanged", then send the 1125 // event only if the extension has requested notifications from the 1126 // related characteristic. 1127 if (event_name == apibtle::OnCharacteristicValueChanged::kEventName && 1128 !characteristic_id.empty() && 1129 !FindNotifySession(extension_id, characteristic_id)) 1130 continue; 1131 1132 // Send the event. 1133 scoped_ptr<base::ListValue> args_copy(args->DeepCopy()); 1134 scoped_ptr<Event> event(new Event(event_name, args_copy.Pass())); 1135 EventRouter::Get(browser_context_)->DispatchEventToExtension( 1136 extension_id, event.Pass()); 1137 } 1138} 1139 1140BluetoothGattService* BluetoothLowEnergyEventRouter::FindServiceById( 1141 const std::string& instance_id) const { 1142 InstanceIdMap::const_iterator iter = 1143 service_id_to_device_address_.find(instance_id); 1144 if (iter == service_id_to_device_address_.end()) { 1145 VLOG(1) << "GATT service identifier unknown: " << instance_id; 1146 return NULL; 1147 } 1148 1149 const std::string& address = iter->second; 1150 1151 BluetoothDevice* device = adapter_->GetDevice(address); 1152 if (!device) { 1153 VLOG(1) << "Bluetooth device not found: " << address; 1154 return NULL; 1155 } 1156 1157 BluetoothGattService* service = device->GetGattService(instance_id); 1158 if (!service) { 1159 VLOG(1) << "GATT service with ID \"" << instance_id 1160 << "\" not found on device \"" << address << "\""; 1161 return NULL; 1162 } 1163 1164 return service; 1165} 1166 1167BluetoothGattCharacteristic* 1168BluetoothLowEnergyEventRouter::FindCharacteristicById( 1169 const std::string& instance_id) const { 1170 InstanceIdMap::const_iterator iter = chrc_id_to_service_id_.find(instance_id); 1171 if (iter == chrc_id_to_service_id_.end()) { 1172 VLOG(1) << "GATT characteristic identifier unknown: " << instance_id; 1173 return NULL; 1174 } 1175 1176 const std::string& service_id = iter->second; 1177 1178 BluetoothGattService* service = FindServiceById(service_id); 1179 if (!service) { 1180 VLOG(1) << "Failed to obtain service for characteristic: " << instance_id; 1181 return NULL; 1182 } 1183 1184 BluetoothGattCharacteristic* characteristic = 1185 service->GetCharacteristic(instance_id); 1186 if (!characteristic) { 1187 VLOG(1) << "GATT characteristic with ID \"" << instance_id 1188 << "\" not found on service \"" << service_id << "\""; 1189 return NULL; 1190 } 1191 1192 return characteristic; 1193} 1194 1195BluetoothGattDescriptor* BluetoothLowEnergyEventRouter::FindDescriptorById( 1196 const std::string& instance_id) const { 1197 InstanceIdMap::const_iterator iter = desc_id_to_chrc_id_.find(instance_id); 1198 if (iter == desc_id_to_chrc_id_.end()) { 1199 VLOG(1) << "GATT descriptor identifier unknown: " << instance_id; 1200 return NULL; 1201 } 1202 1203 const std::string& chrc_id = iter->second; 1204 BluetoothGattCharacteristic* chrc = FindCharacteristicById(chrc_id); 1205 if (!chrc) { 1206 VLOG(1) << "Failed to obtain characteristic for descriptor: " 1207 << instance_id; 1208 return NULL; 1209 } 1210 1211 BluetoothGattDescriptor* descriptor = chrc->GetDescriptor(instance_id); 1212 if (!descriptor) { 1213 VLOG(1) << "GATT descriptor with ID \"" << instance_id 1214 << "\" not found on characteristic \"" << chrc_id << "\""; 1215 return NULL; 1216 } 1217 1218 return descriptor; 1219} 1220 1221void BluetoothLowEnergyEventRouter::OnValueSuccess( 1222 const base::Closure& callback, 1223 const std::vector<uint8>& value) { 1224 VLOG(2) << "Remote characteristic/descriptor value read successful."; 1225 callback.Run(); 1226} 1227 1228void BluetoothLowEnergyEventRouter::OnCreateGattConnection( 1229 bool persistent, 1230 const std::string& extension_id, 1231 const std::string& device_address, 1232 const base::Closure& callback, 1233 scoped_ptr<BluetoothGattConnection> connection) { 1234 VLOG(2) << "GATT connection created."; 1235 DCHECK(connection.get()); 1236 DCHECK(!FindConnection(extension_id, device_address)); 1237 DCHECK_EQ(device_address, connection->GetDeviceAddress()); 1238 1239 const std::string connect_id = extension_id + device_address; 1240 DCHECK_NE(0U, connecting_devices_.count(connect_id)); 1241 1242 BluetoothLowEnergyConnection* conn = new BluetoothLowEnergyConnection( 1243 persistent, extension_id, connection.Pass()); 1244 ConnectionResourceManager* manager = 1245 GetConnectionResourceManager(browser_context_); 1246 manager->Add(conn); 1247 1248 connecting_devices_.erase(connect_id); 1249 callback.Run(); 1250} 1251 1252void BluetoothLowEnergyEventRouter::OnDisconnect( 1253 const std::string& extension_id, 1254 const std::string& device_address, 1255 const base::Closure& callback) { 1256 VLOG(2) << "GATT connection terminated."; 1257 1258 const std::string disconnect_id = extension_id + device_address; 1259 DCHECK_NE(0U, disconnecting_devices_.count(disconnect_id)); 1260 1261 if (!RemoveConnection(extension_id, device_address)) { 1262 VLOG(1) << "The connection was removed before disconnect completed, id: " 1263 << extension_id << ", device: " << device_address; 1264 } 1265 1266 disconnecting_devices_.erase(disconnect_id); 1267 callback.Run(); 1268} 1269 1270void BluetoothLowEnergyEventRouter::OnError( 1271 const ErrorCallback& error_callback) { 1272 VLOG(2) << "Remote characteristic/descriptor value read/write failed."; 1273 error_callback.Run(kStatusErrorFailed); 1274} 1275 1276void BluetoothLowEnergyEventRouter::OnConnectError( 1277 const std::string& extension_id, 1278 const std::string& device_address, 1279 const ErrorCallback& error_callback, 1280 BluetoothDevice::ConnectErrorCode error_code) { 1281 VLOG(2) << "Failed to create GATT connection: " << error_code; 1282 1283 const std::string connect_id = extension_id + device_address; 1284 DCHECK_NE(0U, connecting_devices_.count(connect_id)); 1285 1286 connecting_devices_.erase(connect_id); 1287 error_callback.Run(kStatusErrorFailed); 1288} 1289 1290void BluetoothLowEnergyEventRouter::OnStartNotifySession( 1291 bool persistent, 1292 const std::string& extension_id, 1293 const std::string& characteristic_id, 1294 const base::Closure& callback, 1295 scoped_ptr<device::BluetoothGattNotifySession> session) { 1296 VLOG(2) << "Value update session created for characteristic: " 1297 << characteristic_id; 1298 DCHECK(session.get()); 1299 DCHECK(!FindNotifySession(extension_id, characteristic_id)); 1300 DCHECK_EQ(characteristic_id, session->GetCharacteristicIdentifier()); 1301 1302 const std::string session_id = extension_id + characteristic_id; 1303 DCHECK_NE(0U, pending_session_calls_.count(session_id)); 1304 1305 BluetoothLowEnergyNotifySession* resource = 1306 new BluetoothLowEnergyNotifySession( 1307 persistent, extension_id, session.Pass()); 1308 1309 NotifySessionResourceManager* manager = 1310 GetNotifySessionResourceManager(browser_context_); 1311 manager->Add(resource); 1312 1313 pending_session_calls_.erase(session_id); 1314 callback.Run(); 1315} 1316 1317void BluetoothLowEnergyEventRouter::OnStartNotifySessionError( 1318 const std::string& extension_id, 1319 const std::string& characteristic_id, 1320 const ErrorCallback& error_callback) { 1321 VLOG(2) << "Failed to create value update session for characteristic: " 1322 << characteristic_id; 1323 1324 const std::string session_id = extension_id + characteristic_id; 1325 DCHECK_NE(0U, pending_session_calls_.count(session_id)); 1326 1327 pending_session_calls_.erase(session_id); 1328 error_callback.Run(kStatusErrorFailed); 1329} 1330 1331void BluetoothLowEnergyEventRouter::OnStopNotifySession( 1332 const std::string& extension_id, 1333 const std::string& characteristic_id, 1334 const base::Closure& callback) { 1335 VLOG(2) << "Value update session terminated."; 1336 1337 if (!RemoveNotifySession(extension_id, characteristic_id)) { 1338 VLOG(1) << "The value update session was removed before Stop completed, " 1339 << "id: " << extension_id 1340 << ", characteristic: " << characteristic_id; 1341 } 1342 1343 callback.Run(); 1344} 1345 1346BluetoothLowEnergyConnection* BluetoothLowEnergyEventRouter::FindConnection( 1347 const std::string& extension_id, 1348 const std::string& device_address) { 1349 ConnectionResourceManager* manager = 1350 GetConnectionResourceManager(browser_context_); 1351 1352 base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id); 1353 if (!connection_ids) 1354 return NULL; 1355 1356 for (base::hash_set<int>::const_iterator iter = connection_ids->begin(); 1357 iter != connection_ids->end(); 1358 ++iter) { 1359 extensions::BluetoothLowEnergyConnection* conn = 1360 manager->Get(extension_id, *iter); 1361 if (!conn) 1362 continue; 1363 1364 if (conn->GetConnection()->GetDeviceAddress() == device_address) 1365 return conn; 1366 } 1367 1368 return NULL; 1369} 1370 1371bool BluetoothLowEnergyEventRouter::RemoveConnection( 1372 const std::string& extension_id, 1373 const std::string& device_address) { 1374 ConnectionResourceManager* manager = 1375 GetConnectionResourceManager(browser_context_); 1376 1377 base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id); 1378 if (!connection_ids) 1379 return false; 1380 1381 for (base::hash_set<int>::const_iterator iter = connection_ids->begin(); 1382 iter != connection_ids->end(); 1383 ++iter) { 1384 extensions::BluetoothLowEnergyConnection* conn = 1385 manager->Get(extension_id, *iter); 1386 if (!conn || conn->GetConnection()->GetDeviceAddress() != device_address) 1387 continue; 1388 1389 manager->Remove(extension_id, *iter); 1390 return true; 1391 } 1392 1393 return false; 1394} 1395 1396BluetoothLowEnergyNotifySession* 1397BluetoothLowEnergyEventRouter::FindNotifySession( 1398 const std::string& extension_id, 1399 const std::string& characteristic_id) { 1400 NotifySessionResourceManager* manager = 1401 GetNotifySessionResourceManager(browser_context_); 1402 1403 base::hash_set<int>* ids = manager->GetResourceIds(extension_id); 1404 if (!ids) 1405 return NULL; 1406 1407 for (base::hash_set<int>::const_iterator iter = ids->begin(); 1408 iter != ids->end(); 1409 ++iter) { 1410 BluetoothLowEnergyNotifySession* session = 1411 manager->Get(extension_id, *iter); 1412 if (!session) 1413 continue; 1414 1415 if (session->GetSession()->GetCharacteristicIdentifier() == 1416 characteristic_id) 1417 return session; 1418 } 1419 1420 return NULL; 1421} 1422 1423bool BluetoothLowEnergyEventRouter::RemoveNotifySession( 1424 const std::string& extension_id, 1425 const std::string& characteristic_id) { 1426 NotifySessionResourceManager* manager = 1427 GetNotifySessionResourceManager(browser_context_); 1428 1429 base::hash_set<int>* ids = manager->GetResourceIds(extension_id); 1430 if (!ids) 1431 return false; 1432 1433 for (base::hash_set<int>::const_iterator iter = ids->begin(); 1434 iter != ids->end(); 1435 ++iter) { 1436 BluetoothLowEnergyNotifySession* session = 1437 manager->Get(extension_id, *iter); 1438 if (!session || 1439 session->GetSession()->GetCharacteristicIdentifier() != 1440 characteristic_id) 1441 continue; 1442 1443 manager->Remove(extension_id, *iter); 1444 return true; 1445 } 1446 1447 return false; 1448} 1449 1450} // namespace extensions 1451