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