15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved. 25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be 35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file. 45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h" 65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/bind.h" 85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/logging.h" 95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/values.h" 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/public/browser/browser_thread.h" 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "device/bluetooth/bluetooth_adapter_factory.h" 12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "device/bluetooth/bluetooth_gatt_characteristic.h" 136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "device/bluetooth/bluetooth_gatt_connection.h" 14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "device/bluetooth/bluetooth_gatt_descriptor.h" 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_connection.h" 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h" 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/api/bluetooth_low_energy/utils.h" 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/browser/event_router.h" 19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "extensions/browser/extension_registry.h" 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/api/bluetooth/bluetooth_manifest_data.h" 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing content::BrowserThread; 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing device::BluetoothAdapter; 255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing device::BluetoothAdapterFactory; 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing device::BluetoothDevice; 275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing device::BluetoothGattCharacteristic; 286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)using device::BluetoothGattConnection; 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using device::BluetoothGattDescriptor; 305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing device::BluetoothGattService; 315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace apibtle = extensions::core_api::bluetooth_low_energy; 335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace { 355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid PopulateService(const BluetoothGattService* service, 375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu apibtle::Service* out) { 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(out); 395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu out->uuid = service->GetUUID().canonical_value(); 415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu out->is_primary = service->IsPrimary(); 425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu out->is_local = service->IsLocal(); 435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu out->instance_id.reset(new std::string(service->GetIdentifier())); 445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!service->GetDevice()) 465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu out->device_address.reset( 495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu new std::string(service->GetDevice()->GetAddress())); 505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void PopulateCharacteristicProperties( 53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothGattCharacteristic::Properties properties, 54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) std::vector<apibtle::CharacteristicProperty>* api_properties) { 55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(api_properties && api_properties->empty()); 565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties == BluetoothGattCharacteristic::kPropertyNone) 58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties & BluetoothGattCharacteristic::kPropertyBroadcast) 61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_BROADCAST); 62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties & BluetoothGattCharacteristic::kPropertyRead) 63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_READ); 64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties & BluetoothGattCharacteristic::kPropertyWriteWithoutResponse) { 65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back( 66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) apibtle::CHARACTERISTIC_PROPERTY_WRITEWITHOUTRESPONSE); 67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties & BluetoothGattCharacteristic::kPropertyWrite) 69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_WRITE); 70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties & BluetoothGattCharacteristic::kPropertyNotify) 71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_NOTIFY); 72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties & BluetoothGattCharacteristic::kPropertyIndicate) 73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_INDICATE); 74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties & 75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothGattCharacteristic::kPropertyAuthenticatedSignedWrites) { 76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back( 77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) apibtle::CHARACTERISTIC_PROPERTY_AUTHENTICATEDSIGNEDWRITES); 78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties & BluetoothGattCharacteristic::kPropertyExtendedProperties) { 80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back( 81010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) apibtle::CHARACTERISTIC_PROPERTY_EXTENDEDPROPERTIES); 82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (properties & BluetoothGattCharacteristic::kPropertyReliableWrite) 84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_RELIABLEWRITE); 85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (properties & BluetoothGattCharacteristic::kPropertyWritableAuxiliaries) { 86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) api_properties->push_back( 87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) apibtle::CHARACTERISTIC_PROPERTY_WRITABLEAUXILIARIES); 88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void PopulateCharacteristic(const BluetoothGattCharacteristic* characteristic, 92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) apibtle::Characteristic* out) { 93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(out); 94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) out->uuid = characteristic->GetUUID().canonical_value(); 96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) out->is_local = characteristic->IsLocal(); 97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) out->instance_id.reset(new std::string(characteristic->GetIdentifier())); 98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) PopulateService(characteristic->GetService(), &out->service); 100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) PopulateCharacteristicProperties(characteristic->GetProperties(), 101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) &out->properties); 102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::vector<uint8>& value = characteristic->GetValue(); 104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (value.empty()) 105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) out->value.reset(new std::string(value.begin(), value.end())); 1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PopulateDescriptor(const BluetoothGattDescriptor* descriptor, 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) apibtle::Descriptor* out) { 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(out); 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out->uuid = descriptor->GetUUID().canonical_value(); 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out->is_local = descriptor->IsLocal(); 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out->instance_id.reset(new std::string(descriptor->GetIdentifier())); 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PopulateCharacteristic(descriptor->GetCharacteristic(), &out->characteristic); 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::vector<uint8>& value = descriptor->GetValue(); 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (value.empty()) 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out->value.reset(new std::string(value.begin(), value.end())); 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)typedef extensions::ApiResourceManager<extensions::BluetoothLowEnergyConnection> 1286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ConnectionResourceManager; 1296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)ConnectionResourceManager* GetConnectionResourceManager( 1306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::BrowserContext* context) { 1316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ConnectionResourceManager* manager = ConnectionResourceManager::Get(context); 1326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK(manager) 1336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) << "There is no Bluetooth low energy connection manager. " 1346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) "If this assertion is failing during a test, then it is likely that " 1356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) "TestExtensionSystem is failing to provide an instance of " 1366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) "ApiResourceManager<BluetoothLowEnergyConnection>."; 1376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return manager; 1386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 1396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef extensions::ApiResourceManager< 141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extensions::BluetoothLowEnergyNotifySession> NotifySessionResourceManager; 142116680a4aac90f2aa7413d9095a592090648e557Ben MurdochNotifySessionResourceManager* GetNotifySessionResourceManager( 143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::BrowserContext* context) { 144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch NotifySessionResourceManager* manager = 145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch NotifySessionResourceManager::Get(context); 146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(manager) 147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << "There is no Bluetooth low energy value update session manager." 148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch "If this assertion is failing during a test, then it is likely that " 149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch "TestExtensionSystem is failing to provide an instance of " 150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch "ApiResourceManager<BluetoothLowEnergyNotifySession>."; 151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return manager; 152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 154010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} // namespace 155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 156010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace extensions { 157010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothLowEnergyEventRouter::BluetoothLowEnergyEventRouter( 1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu content::BrowserContext* context) 1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu : adapter_(NULL), browser_context_(context), weak_ptr_factory_(this) { 1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(browser_context_); 1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(1) << "Initializing BluetoothLowEnergyEventRouter."; 1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!IsBluetoothSupported()) { 1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(1) << "Bluetooth not supported on the current platform."; 1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothLowEnergyEventRouter::~BluetoothLowEnergyEventRouter() { 1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!adapter_.get()) 1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu adapter_->RemoveObserver(this); 1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu adapter_ = NULL; 1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool BluetoothLowEnergyEventRouter::IsBluetoothSupported() const { 1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return adapter_.get() || 1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothAdapterFactory::IsBluetoothAdapterAvailable(); 1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool BluetoothLowEnergyEventRouter::InitializeAdapterAndInvokeCallback( 1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const base::Closure& callback) { 1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!IsBluetoothSupported()) 1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (adapter_.get()) { 1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu callback.Run(); 1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return true; 1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothAdapterFactory::GetAdapter( 1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&BluetoothLowEnergyEventRouter::OnGetAdapter, 1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu weak_ptr_factory_.GetWeakPtr(), 1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu callback)); 2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return true; 2015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 2025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool BluetoothLowEnergyEventRouter::HasAdapter() const { 2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return (adapter_.get() != NULL); 2055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 2065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothLowEnergyEventRouter::Connect( 2086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) bool persistent, 2096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const Extension* extension, 2106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& device_address, 2116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const base::Closure& callback, 2126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const ErrorCallback& error_callback) { 2136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 2156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) VLOG(1) << "BluetoothAdapter not ready."; 2166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorFailed); 2176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 2196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string extension_id = extension->id(); 221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string connect_id = extension_id + device_address; 222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (connecting_devices_.count(connect_id) != 0) { 2246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorInProgress); 2256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 2276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) BluetoothLowEnergyConnection* conn = 2296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) FindConnection(extension_id, device_address); 2306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (conn) { 2316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (conn->GetConnection()->IsConnected()) { 2326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) VLOG(1) << "Application already connected to device: " << device_address; 2336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorAlreadyConnected); 2346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 2366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // There is a connection object but it's no longer active. Simply remove it. 2386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) RemoveConnection(extension_id, device_address); 2396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 2406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) BluetoothDevice* device = adapter_->GetDevice(device_address); 2426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!device) { 2436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) VLOG(1) << "Bluetooth device not found: " << device_address; 2446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorNotFound); 2456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 2476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch connecting_devices_.insert(connect_id); 2496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) device->CreateGattConnection( 2506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::Bind(&BluetoothLowEnergyEventRouter::OnCreateGattConnection, 2516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 2526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) persistent, 2536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_id, 2546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) device_address, 2556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) callback), 2566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::Bind(&BluetoothLowEnergyEventRouter::OnConnectError, 2576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extension_id, 2596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) device_address, 2606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback)); 2616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 2626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothLowEnergyEventRouter::Disconnect( 2646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const Extension* extension, 2656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& device_address, 2666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const base::Closure& callback, 2676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const ErrorCallback& error_callback) { 2686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 2706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) VLOG(1) << "BluetoothAdapter not ready."; 2716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorFailed); 2726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 2746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string extension_id = extension->id(); 276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string disconnect_id = extension_id + device_address; 277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (disconnecting_devices_.count(disconnect_id) != 0) { 2796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorInProgress); 2806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 2826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 2836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) BluetoothLowEnergyConnection* conn = 2846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) FindConnection(extension_id, device_address); 2856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!conn || !conn->GetConnection()->IsConnected()) { 2866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) VLOG(1) << "Application not connected to device: " << device_address; 2876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorNotConnected); 2886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 2896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 2906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch disconnecting_devices_.insert(disconnect_id); 2926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) conn->GetConnection()->Disconnect( 2936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::Bind(&BluetoothLowEnergyEventRouter::OnDisconnect, 2946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 2956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_id, 2966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) device_address, 2976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) callback)); 2986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 2996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 3005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool BluetoothLowEnergyEventRouter::GetServices( 3015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::string& device_address, 3025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ServiceList* out_services) const { 3035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(out_services); 3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 3065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(1) << "BluetoothAdapter not ready."; 3075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 3085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothDevice* device = adapter_->GetDevice(device_address); 3115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!device) { 3125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(1) << "Bluetooth device not found: " << device_address; 3135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 3145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu out_services->clear(); 3175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::vector<BluetoothGattService*>& services = 3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu device->GetGattServices(); 3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (std::vector<BluetoothGattService*>::const_iterator iter = 3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu services.begin(); 3225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu iter != services.end(); 3235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ++iter) { 3245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Populate an API service and add it to the return value. 3255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const BluetoothGattService* service = *iter; 3265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu linked_ptr<apibtle::Service> api_service(new apibtle::Service()); 3275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu PopulateService(service, api_service.get()); 3285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu out_services->push_back(api_service); 3305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return true; 3335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 3345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::Status BluetoothLowEnergyEventRouter::GetService( 3365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::string& instance_id, 337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) apibtle::Service* out_service) const { 3385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(out_service); 3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 3415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(1) << "BluetoothAdapter not ready."; 342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorFailed; 3435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothGattService* gatt_service = FindServiceById(instance_id); 3465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!gatt_service) { 3475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(1) << "Service not found: " << instance_id; 348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorNotFound; 3495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PopulateService(gatt_service, out_service); 352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusSuccess; 3535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 3545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::Status 356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::GetIncludedServices( 3575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::string& instance_id, 3585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ServiceList* out_services) const { 3595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(out_services); 3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 3625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(1) << "BluetoothAdapter not ready."; 363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorFailed; 3645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothGattService* service = FindServiceById(instance_id); 3675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!service) { 3685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(1) << "Service not found: " << instance_id; 369f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorNotFound; 3705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu out_services->clear(); 3735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::vector<BluetoothGattService*>& includes = 3755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu service->GetIncludedServices(); 3765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (std::vector<BluetoothGattService*>::const_iterator iter = 3775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu includes.begin(); 3785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu iter != includes.end(); 3795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ++iter) { 3805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Populate an API service and add it to the return value. 3815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const BluetoothGattService* included = *iter; 3825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu linked_ptr<apibtle::Service> api_service(new apibtle::Service()); 3835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu PopulateService(included, api_service.get()); 3845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu out_services->push_back(api_service); 3865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 388f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusSuccess; 3895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 3905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::Status 392f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::GetCharacteristics( 393f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const Extension* extension, 394010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& instance_id, 395010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) CharacteristicList* out_characteristics) const { 396010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 397f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(extension); 398010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(out_characteristics); 3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 400010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "BlutoothAdapter not ready."; 401f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorFailed; 402010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 403010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 404010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothGattService* service = FindServiceById(instance_id); 405010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!service) { 406010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "Service not found: " << instance_id; 407f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorNotFound; 408f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 409f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 410f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BluetoothPermissionRequest request(service->GetUUID().value()); 411f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!BluetoothManifestData::CheckRequest(extension, request)) { 412f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "App has no permission to access the characteristics of this " 413f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << "service: " << instance_id; 414f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorPermissionDenied; 415010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 416010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 417010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) out_characteristics->clear(); 418010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 419010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::vector<BluetoothGattCharacteristic*>& characteristics = 420010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service->GetCharacteristics(); 421010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) for (std::vector<BluetoothGattCharacteristic*>::const_iterator iter = 422010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) characteristics.begin(); 423010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) iter != characteristics.end(); 424010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) ++iter) { 425010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Populate an API characteristic and add it to the return value. 426010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const BluetoothGattCharacteristic* characteristic = *iter; 427010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) linked_ptr<apibtle::Characteristic> api_characteristic( 428010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) new apibtle::Characteristic()); 429010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) PopulateCharacteristic(characteristic, api_characteristic.get()); 430010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 431010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) out_characteristics->push_back(api_characteristic); 432010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 433010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 434f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusSuccess; 435010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 436010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 437f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::Status 438f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::GetCharacteristic( 439f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const Extension* extension, 440010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& instance_id, 441010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) apibtle::Characteristic* out_characteristic) const { 442010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 443f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(extension); 444cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(out_characteristic); 4451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 446010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "BluetoothAdapter not ready."; 447f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorFailed; 448010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 449010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 450010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothGattCharacteristic* characteristic = 451010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) FindCharacteristicById(instance_id); 452010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!characteristic) { 453010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "Characteristic not found: " << instance_id; 454f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorNotFound; 455f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 456f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 457f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BluetoothPermissionRequest request( 458f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) characteristic->GetService()->GetUUID().value()); 459f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!BluetoothManifestData::CheckRequest(extension, request)) { 460f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "App has no permission to access this characteristic: " 461f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << instance_id; 462f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorPermissionDenied; 463010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 464010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 465010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) PopulateCharacteristic(characteristic, out_characteristic); 466f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusSuccess; 467010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 468010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 469f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::Status 470f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::GetDescriptors( 471f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const Extension* extension, 472cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& instance_id, 473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DescriptorList* out_descriptors) const { 474cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 475f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(extension); 476cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(out_descriptors); 4771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 478cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "BlutoothAdapter not ready."; 479f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorFailed; 480cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 481cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 482cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattCharacteristic* characteristic = 483cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FindCharacteristicById(instance_id); 484cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!characteristic) { 485cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Characteristic not found: " << instance_id; 486f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorNotFound; 487f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 488f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 489f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BluetoothPermissionRequest request( 490f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) characteristic->GetService()->GetUUID().value()); 491f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!BluetoothManifestData::CheckRequest(extension, request)) { 492f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "App has no permission to access the descriptors of this " 493f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << "characteristic: " << instance_id; 494f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorPermissionDenied; 495cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 496cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 497cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out_descriptors->clear(); 498cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 499cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::vector<BluetoothGattDescriptor*>& descriptors = 500cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) characteristic->GetDescriptors(); 501cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (std::vector<BluetoothGattDescriptor*>::const_iterator iter = 502cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) descriptors.begin(); 503cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) iter != descriptors.end(); 504cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ++iter) { 505cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Populate an API descriptor and add it to the return value. 506cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const BluetoothGattDescriptor* descriptor = *iter; 507cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) linked_ptr<apibtle::Descriptor> api_descriptor(new apibtle::Descriptor()); 508cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PopulateDescriptor(descriptor, api_descriptor.get()); 509cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 510cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out_descriptors->push_back(api_descriptor); 511cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 512cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 513f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusSuccess; 514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 515cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 516f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::Status 517f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)BluetoothLowEnergyEventRouter::GetDescriptor( 518f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const Extension* extension, 519cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& instance_id, 5201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci core_api::bluetooth_low_energy::Descriptor* out_descriptor) const { 521cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 522f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(extension); 523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(out_descriptor); 5241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 525cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "BluetoothAdapter not ready."; 526f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorFailed; 527cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 529cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id); 530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!descriptor) { 531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Descriptor not found: " << instance_id; 532f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorNotFound; 533f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 534f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 535f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BluetoothPermissionRequest request( 536f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) descriptor->GetCharacteristic()->GetService()->GetUUID().value()); 537f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!BluetoothManifestData::CheckRequest(extension, request)) { 538f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "App has no permission to access this descriptor: " 539f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << instance_id; 540f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusErrorPermissionDenied; 541cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 542cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 543cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PopulateDescriptor(descriptor, out_descriptor); 544f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return kStatusSuccess; 545cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 546cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 5476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothLowEnergyEventRouter::ReadCharacteristicValue( 548f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const Extension* extension, 549010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& instance_id, 550010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const base::Closure& callback, 551f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ErrorCallback& error_callback) { 552010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 553f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(extension); 5541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 555010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "BluetoothAdapter not ready."; 5566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorFailed); 5576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 558010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 559010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 560010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothGattCharacteristic* characteristic = 561010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) FindCharacteristicById(instance_id); 562010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!characteristic) { 563010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "Characteristic not found: " << instance_id; 5646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorNotFound); 5656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 566f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 567f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 568f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BluetoothPermissionRequest request( 569f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) characteristic->GetService()->GetUUID().value()); 570f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!BluetoothManifestData::CheckRequest(extension, request)) { 571f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "App has no permission to access this characteristic: " 572f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << instance_id; 5736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorPermissionDenied); 5746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 575010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 576010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 577010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) characteristic->ReadRemoteCharacteristic( 578f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess, 579010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 580010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) callback), 581f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&BluetoothLowEnergyEventRouter::OnError, 582f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 583f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) error_callback)); 584010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 585010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 5866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothLowEnergyEventRouter::WriteCharacteristicValue( 587f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const Extension* extension, 588cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& instance_id, 589cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::vector<uint8>& value, 590cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::Closure& callback, 591f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ErrorCallback& error_callback) { 592cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 593f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(extension); 5941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 595cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "BluetoothAdapter not ready."; 5966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorFailed); 5976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 598cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 599cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 600cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattCharacteristic* characteristic = 601cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FindCharacteristicById(instance_id); 602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!characteristic) { 603cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Characteristic not found: " << instance_id; 6046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorNotFound); 6056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 606cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 607cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 608f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BluetoothPermissionRequest request( 609f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) characteristic->GetService()->GetUUID().value()); 610f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!BluetoothManifestData::CheckRequest(extension, request)) { 611f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "App has no permission to access this characteristic: " 612f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << instance_id; 6136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorPermissionDenied); 6146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 615f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 616f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 617f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) characteristic->WriteRemoteCharacteristic( 618f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) value, 619f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) callback, 620f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&BluetoothLowEnergyEventRouter::OnError, 621f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 622f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) error_callback)); 623cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 624cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 625116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid BluetoothLowEnergyEventRouter::StartCharacteristicNotifications( 626116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool persistent, 627116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const Extension* extension, 628116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& instance_id, 629116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const base::Closure& callback, 630116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const ErrorCallback& error_callback) { 631116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 6321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 633116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "BluetoothAdapter not ready."; 634116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch error_callback.Run(kStatusErrorFailed); 635116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 636116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 637116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 638116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string extension_id = extension->id(); 639116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string session_id = extension_id + instance_id; 640116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 641116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (pending_session_calls_.count(session_id) != 0) { 642116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch error_callback.Run(kStatusErrorInProgress); 643116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 644116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 645116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 646116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BluetoothLowEnergyNotifySession* session = 647116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch FindNotifySession(extension_id, instance_id); 648116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (session) { 649116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (session->GetSession()->IsActive()) { 650116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Application has already enabled notifications from " 651116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << "characteristic: " << instance_id; 652116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch error_callback.Run(kStatusErrorAlreadyNotifying); 653116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 654116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 655116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 656116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch RemoveNotifySession(extension_id, instance_id); 657116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 658116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 659116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BluetoothGattCharacteristic* characteristic = 660116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch FindCharacteristicById(instance_id); 661116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!characteristic) { 662116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Characteristic not found: " << instance_id; 663116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch error_callback.Run(kStatusErrorNotFound); 664116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 665116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 666116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 667116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BluetoothPermissionRequest request( 668116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch characteristic->GetService()->GetUUID().value()); 669116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!BluetoothManifestData::CheckRequest(extension, request)) { 670116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "App has no permission to access this characteristic: " 671116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << instance_id; 672116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch error_callback.Run(kStatusErrorPermissionDenied); 673116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 674116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 675116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 676116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch pending_session_calls_.insert(session_id); 677116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch characteristic->StartNotifySession( 678116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySession, 679116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch weak_ptr_factory_.GetWeakPtr(), 680116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch persistent, 681116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extension_id, 682116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch instance_id, 683116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch callback), 684116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySessionError, 685116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch weak_ptr_factory_.GetWeakPtr(), 686116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extension_id, 687116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch instance_id, 688116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch error_callback)); 689116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 690116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 691116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid BluetoothLowEnergyEventRouter::StopCharacteristicNotifications( 692116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const Extension* extension, 693116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& instance_id, 694116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const base::Closure& callback, 695116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const ErrorCallback& error_callback) { 696116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 6971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 698116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "BluetoothAdapter not ready."; 699116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch error_callback.Run(kStatusErrorFailed); 700116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 701116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 702116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 703116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string extension_id = extension->id(); 704116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 705116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BluetoothLowEnergyNotifySession* session = 706116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch FindNotifySession(extension_id, instance_id); 707116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!session || !session->GetSession()->IsActive()) { 708116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Application has not enabled notifications from " 709116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << "characteristic: " << instance_id; 710116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch error_callback.Run(kStatusErrorNotNotifying); 711116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 712116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 713116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 714116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch session->GetSession()->Stop( 715116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(&BluetoothLowEnergyEventRouter::OnStopNotifySession, 716116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch weak_ptr_factory_.GetWeakPtr(), 717116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extension_id, 718116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch instance_id, 719116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch callback)); 720116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 721116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 7226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothLowEnergyEventRouter::ReadDescriptorValue( 723f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const Extension* extension, 724cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& instance_id, 725cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::Closure& callback, 726f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ErrorCallback& error_callback) { 727cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 728f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(extension); 7291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 730cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "BluetoothAdapter not ready."; 7316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorFailed); 7326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 733cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 734cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 735cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id); 736cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!descriptor) { 737cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Descriptor not found: " << instance_id; 7386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorNotFound); 7396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 740f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 741f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 742f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BluetoothPermissionRequest request( 743f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) descriptor->GetCharacteristic()->GetService()->GetUUID().value()); 744f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!BluetoothManifestData::CheckRequest(extension, request)) { 745f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "App has no permission to access this descriptor: " 746f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << instance_id; 7476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorPermissionDenied); 7486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 749cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 750cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 751cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) descriptor->ReadRemoteDescriptor( 752f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess, 753cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 754cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback), 755f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&BluetoothLowEnergyEventRouter::OnError, 756f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 757f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) error_callback)); 758cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 759cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 7606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothLowEnergyEventRouter::WriteDescriptorValue( 761f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const Extension* extension, 762cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& instance_id, 763cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::vector<uint8>& value, 764cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::Closure& callback, 765f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ErrorCallback& error_callback) { 766cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 767f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(extension); 7681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!adapter_.get()) { 769cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "BluetoothAdapter not ready."; 7706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorFailed); 7716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 772cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 773cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 774cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id); 775cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!descriptor) { 776cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Descriptor not found: " << instance_id; 7776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorNotFound); 7786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 779cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 780cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 781f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BluetoothPermissionRequest request( 782f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) descriptor->GetCharacteristic()->GetService()->GetUUID().value()); 783f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!BluetoothManifestData::CheckRequest(extension, request)) { 784f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "App has no permission to access this descriptor: " 785f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << instance_id; 7866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorPermissionDenied); 7876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 788f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 789f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 790f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) descriptor->WriteRemoteDescriptor( 791f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) value, 792f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) callback, 793f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&BluetoothLowEnergyEventRouter::OnError, 794f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 795f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) error_callback)); 796cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 797cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 7985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothLowEnergyEventRouter::SetAdapterForTesting( 7995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu device::BluetoothAdapter* adapter) { 8005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu adapter_ = adapter; 8015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu InitializeIdentifierMappings(); 8025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 8035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 8045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothLowEnergyEventRouter::GattServiceAdded( 8055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 8065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothDevice* device, 8075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothGattService* service) { 8085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 8091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 8105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(2) << "GATT service added: " << service->GetIdentifier(); 8115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 812010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) == 813010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service_id_to_device_address_.end()); 8145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 8155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) service_id_to_device_address_[service->GetIdentifier()] = 8165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device->GetAddress(); 8175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 8185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 8195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothLowEnergyEventRouter::GattServiceRemoved( 8205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 8215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothDevice* device, 8225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothGattService* service) { 8235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 8241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 8255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(2) << "GATT service removed: " << service->GetIdentifier(); 8265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 827010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 828010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service_id_to_device_address_.end()); 8295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 8305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(device->GetAddress() == 831010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service_id_to_device_address_[service->GetIdentifier()]); 832010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service_id_to_device_address_.erase(service->GetIdentifier()); 8335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 8345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Signal API event. 8355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu apibtle::Service api_service; 8365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu PopulateService(service, &api_service); 8375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 8385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu scoped_ptr<base::ListValue> args = 8395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu apibtle::OnServiceRemoved::Create(api_service); 8405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu scoped_ptr<Event> event( 8415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu new Event(apibtle::OnServiceRemoved::kEventName, args.Pass())); 8425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); 8435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 8445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 8455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothLowEnergyEventRouter::GattDiscoveryCompleteForService( 8465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 8475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothGattService* service) { 8485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 8491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 8505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VLOG(2) << "GATT service discovery complete: " << service->GetIdentifier(); 8515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 8525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 8535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) service_id_to_device_address_.end()); 8545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 8555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Signal the service added event here. 8565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) apibtle::Service api_service; 8575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PopulateService(service, &api_service); 8585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 8595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_ptr<base::ListValue> args = 8605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) apibtle::OnServiceAdded::Create(api_service); 8615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_ptr<Event> event( 8625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) new Event(apibtle::OnServiceAdded::kEventName, args.Pass())); 8635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); 8645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 8655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 8665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothLowEnergyEventRouter::GattServiceChanged( 8675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 8685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothGattService* service) { 8695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 8701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 8715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(2) << "GATT service changed: " << service->GetIdentifier(); 872010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 873010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service_id_to_device_address_.end()); 8745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 8755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Signal API event. 8765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu apibtle::Service api_service; 8775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu PopulateService(service, &api_service); 8785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 879f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DispatchEventToExtensionsWithPermission( 880f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) apibtle::OnServiceChanged::kEventName, 881f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) service->GetUUID(), 882116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch "" /* characteristic_id */, 883f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) apibtle::OnServiceChanged::Create(api_service)); 8845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 8855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 8865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothLowEnergyEventRouter::GattCharacteristicAdded( 8875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 8885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothGattCharacteristic* characteristic) { 889010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 8901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 891010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(2) << "GATT characteristic added: " << characteristic->GetIdentifier(); 892010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 8935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothGattService* service = characteristic->GetService(); 8945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(service); 8955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 896010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) == 897010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chrc_id_to_service_id_.end()); 898cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 899cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) service_id_to_device_address_.end()); 900010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 901010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chrc_id_to_service_id_[characteristic->GetIdentifier()] = 902010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service->GetIdentifier(); 9035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 9045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 9055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothLowEnergyEventRouter::GattCharacteristicRemoved( 9065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 9075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothGattCharacteristic* characteristic) { 908010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 9091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 910010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(2) << "GATT characteristic removed: " << characteristic->GetIdentifier(); 911010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 9125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothGattService* service = characteristic->GetService(); 9135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(service); 9145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 915010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) != 916010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chrc_id_to_service_id_.end()); 917010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(service->GetIdentifier() == 918010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chrc_id_to_service_id_[characteristic->GetIdentifier()]); 919010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 920010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chrc_id_to_service_id_.erase(characteristic->GetIdentifier()); 9215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 9225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 923cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothLowEnergyEventRouter::GattDescriptorAdded( 9245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 925cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattDescriptor* descriptor) { 926cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 9271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 928cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(2) << "GATT descriptor added: " << descriptor->GetIdentifier(); 929cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 9305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic(); 9315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(characteristic); 9325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 933cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) == 934cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) desc_id_to_chrc_id_.end()); 935cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) != 936cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) chrc_id_to_service_id_.end()); 937cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 938cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) desc_id_to_chrc_id_[descriptor->GetIdentifier()] = 939cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) characteristic->GetIdentifier(); 940cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 941cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 942cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothLowEnergyEventRouter::GattDescriptorRemoved( 9435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 944cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattDescriptor* descriptor) { 945cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 9461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 947cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(2) << "GATT descriptor removed: " << descriptor->GetIdentifier(); 948cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 9495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic(); 9505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(characteristic); 9515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 952cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) != 953cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) desc_id_to_chrc_id_.end()); 954cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(characteristic->GetIdentifier() == 955cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) desc_id_to_chrc_id_[descriptor->GetIdentifier()]); 956cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 957cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) desc_id_to_chrc_id_.erase(descriptor->GetIdentifier()); 958cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 959cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 9605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothLowEnergyEventRouter::GattCharacteristicValueChanged( 9615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 9625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothGattCharacteristic* characteristic, 9635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::vector<uint8>& value) { 964010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 9651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 966cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(2) << "GATT characteristic value changed: " 967cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) << characteristic->GetIdentifier(); 968010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 9695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothGattService* service = characteristic->GetService(); 9705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(service); 9715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 972010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) != 973010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service_id_to_device_address_.end()); 974010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) != 975010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chrc_id_to_service_id_.end()); 976010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(chrc_id_to_service_id_[characteristic->GetIdentifier()] == 977010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service->GetIdentifier()); 978010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 979f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Send the event; manually construct the arguments, instead of using 980f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // apibtle::OnCharacteristicValueChanged::Create, as it doesn't convert 981f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // lists of enums correctly. 982010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) apibtle::Characteristic api_characteristic; 983010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) PopulateCharacteristic(characteristic, &api_characteristic); 984010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) scoped_ptr<base::ListValue> args(new base::ListValue()); 985010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) args->Append(apibtle::CharacteristicToValue(&api_characteristic).release()); 986f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 987f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DispatchEventToExtensionsWithPermission( 988f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) apibtle::OnCharacteristicValueChanged::kEventName, 989f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) service->GetUUID(), 990116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch characteristic->GetIdentifier(), 991f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) args.Pass()); 9925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 9935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 994cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothLowEnergyEventRouter::GattDescriptorValueChanged( 9955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothAdapter* adapter, 996cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattDescriptor* descriptor, 997cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::vector<uint8>& value) { 998cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 9991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(adapter, adapter_.get()); 1000cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(2) << "GATT descriptor value changed: " << descriptor->GetIdentifier(); 1001cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 10025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) BluetoothGattCharacteristic* characteristic = descriptor->GetCharacteristic(); 10035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(characteristic); 10045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1005cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) != 1006cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) desc_id_to_chrc_id_.end()); 1007cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(characteristic->GetIdentifier() == 1008cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) desc_id_to_chrc_id_[descriptor->GetIdentifier()]); 1009cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1010f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Send the event; manually construct the arguments, instead of using 1011f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // apibtle::OnDescriptorValueChanged::Create, as it doesn't convert 1012f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // lists of enums correctly. 1013cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) apibtle::Descriptor api_descriptor; 1014cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PopulateDescriptor(descriptor, &api_descriptor); 1015cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<base::ListValue> args(new base::ListValue()); 1016cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) args->Append(apibtle::DescriptorToValue(&api_descriptor).release()); 1017f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1018f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DispatchEventToExtensionsWithPermission( 1019f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) apibtle::OnDescriptorValueChanged::kEventName, 1020f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) characteristic->GetService()->GetUUID(), 1021116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch "" /* characteristic_id */, 1022f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) args.Pass()); 1023cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 1024cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 10255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothLowEnergyEventRouter::OnGetAdapter( 10265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const base::Closure& callback, 10275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu scoped_refptr<device::BluetoothAdapter> adapter) { 10285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu adapter_ = adapter; 10295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 10305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Initialize instance ID mappings for all discovered GATT objects and add 10315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // observers. 10325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu InitializeIdentifierMappings(); 10335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu adapter_->AddObserver(this); 10345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 10355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu callback.Run(); 10365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 10375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 10385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() { 1039010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1040010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(service_id_to_device_address_.empty()); 1041010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(chrc_id_to_service_id_.empty()); 1042010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1043010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Devices 10445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); 10455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (BluetoothAdapter::DeviceList::iterator iter = devices.begin(); 10465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu iter != devices.end(); 10475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ++iter) { 10485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothDevice* device = *iter; 10495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1050010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Services 10515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu std::vector<BluetoothGattService*> services = device->GetGattServices(); 10525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (std::vector<BluetoothGattService*>::iterator siter = services.begin(); 10535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu siter != services.end(); 10545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ++siter) { 10555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BluetoothGattService* service = *siter; 10565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1057010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& service_id = service->GetIdentifier(); 1058010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service_id_to_device_address_[service_id] = device->GetAddress(); 10595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1060010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Characteristics 1061cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::vector<BluetoothGattCharacteristic*>& characteristics = 1062010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service->GetCharacteristics(); 1063cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (std::vector<BluetoothGattCharacteristic*>::const_iterator citer = 1064010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) characteristics.begin(); 1065010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) citer != characteristics.end(); 1066010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) ++citer) { 1067010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothGattCharacteristic* characteristic = *citer; 1068010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1069010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& chrc_id = characteristic->GetIdentifier(); 1070010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chrc_id_to_service_id_[chrc_id] = service_id; 1071010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1072cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Descriptors 1073cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::vector<BluetoothGattDescriptor*>& descriptors = 1074cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) characteristic->GetDescriptors(); 1075cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (std::vector<BluetoothGattDescriptor*>::const_iterator diter = 1076cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) descriptors.begin(); 1077cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) diter != descriptors.end(); 1078cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ++diter) { 1079cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattDescriptor* descriptor = *diter; 1080cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1081cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& desc_id = descriptor->GetIdentifier(); 1082cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) desc_id_to_chrc_id_[desc_id] = chrc_id; 1083cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1084010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 10855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 10865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 10875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 10885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1089f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void BluetoothLowEnergyEventRouter::DispatchEventToExtensionsWithPermission( 1090116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& event_name, 1091116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const device::BluetoothUUID& uuid, 1092116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& characteristic_id, 1093116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<base::ListValue> args) { 1094f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Obtain the listeners of |event_name|. The list can contain multiple 1095f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // entries for the same extension, so we keep track of the extensions that we 1096f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // already sent the event to, since we want the send an event to an extension 1097f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // only once. 1098f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) BluetoothPermissionRequest request(uuid.value()); 1099f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::set<std::string> handled_extensions; 1100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const EventListenerMap::ListenerList listeners = 1101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) EventRouter::Get(browser_context_)->listeners().GetEventListenersByName( 1102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event_name); 1103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (EventListenerMap::ListenerList::const_iterator iter = listeners.begin(); 1105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) iter != listeners.end(); 1106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ++iter) { 1107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string extension_id = (*iter)->extension_id(); 1108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (handled_extensions.find(extension_id) != handled_extensions.end()) 1109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 1110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) handled_extensions.insert(extension_id); 1112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const Extension* extension = 1114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ExtensionRegistry::Get(browser_context_) 1115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); 1116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // For all API methods, the "low_energy" permission check is handled by 1118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // BluetoothLowEnergyExtensionFunction but for events we have to do the 1119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // check here. 1120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!BluetoothManifestData::CheckRequest(extension, request) || 1121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) !BluetoothManifestData::CheckLowEnergyPermitted(extension)) 1122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 1123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // If |event_name| is "onCharacteristicValueChanged", then send the 1125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // event only if the extension has requested notifications from the 1126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // related characteristic. 1127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (event_name == apibtle::OnCharacteristicValueChanged::kEventName && 1128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch !characteristic_id.empty() && 1129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch !FindNotifySession(extension_id, characteristic_id)) 1130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch continue; 1131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Send the event. 1133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<base::ListValue> args_copy(args->DeepCopy()); 1134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<Event> event(new Event(event_name, args_copy.Pass())); 1135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) EventRouter::Get(browser_context_)->DispatchEventToExtension( 1136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) extension_id, event.Pass()); 1137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 1139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 11405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuBluetoothGattService* BluetoothLowEnergyEventRouter::FindServiceById( 11415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const std::string& instance_id) const { 1142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) InstanceIdMap::const_iterator iter = 1143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service_id_to_device_address_.find(instance_id); 1144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (iter == service_id_to_device_address_.end()) { 11455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VLOG(1) << "GATT service identifier unknown: " << instance_id; 11465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return NULL; 11475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 11485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& address = iter->second; 11505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1151010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothDevice* device = adapter_->GetDevice(address); 11525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!device) { 1153010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "Bluetooth device not found: " << address; 11545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return NULL; 11555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 11565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1157010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothGattService* service = device->GetGattService(instance_id); 11585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!service) { 1159010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "GATT service with ID \"" << instance_id 1160010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) << "\" not found on device \"" << address << "\""; 11615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return NULL; 11625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 11635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 11645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return service; 11655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 11665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1167010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)BluetoothGattCharacteristic* 1168010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)BluetoothLowEnergyEventRouter::FindCharacteristicById( 1169010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& instance_id) const { 1170010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) InstanceIdMap::const_iterator iter = chrc_id_to_service_id_.find(instance_id); 1171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (iter == chrc_id_to_service_id_.end()) { 1172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "GATT characteristic identifier unknown: " << instance_id; 1173010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return NULL; 1174010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 1175010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1176010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& service_id = iter->second; 1177010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1178010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothGattService* service = FindServiceById(service_id); 1179010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!service) { 1180010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "Failed to obtain service for characteristic: " << instance_id; 1181010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return NULL; 1182010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 1183010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1184010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BluetoothGattCharacteristic* characteristic = 1185010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) service->GetCharacteristic(instance_id); 1186010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!characteristic) { 1187010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "GATT characteristic with ID \"" << instance_id 1188010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) << "\" not found on service \"" << service_id << "\""; 1189010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return NULL; 1190010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 1191010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1192010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return characteristic; 1193010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 1194010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)BluetoothGattDescriptor* BluetoothLowEnergyEventRouter::FindDescriptorById( 1196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& instance_id) const { 1197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) InstanceIdMap::const_iterator iter = desc_id_to_chrc_id_.find(instance_id); 1198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (iter == desc_id_to_chrc_id_.end()) { 1199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "GATT descriptor identifier unknown: " << instance_id; 1200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return NULL; 1201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& chrc_id = iter->second; 1204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattCharacteristic* chrc = FindCharacteristicById(chrc_id); 1205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!chrc) { 1206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Failed to obtain characteristic for descriptor: " 1207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) << instance_id; 1208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return NULL; 1209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) BluetoothGattDescriptor* descriptor = chrc->GetDescriptor(instance_id); 1212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!descriptor) { 1213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "GATT descriptor with ID \"" << instance_id 1214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) << "\" not found on characteristic \"" << chrc_id << "\""; 1215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return NULL; 1216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return descriptor; 1219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 1220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void BluetoothLowEnergyEventRouter::OnValueSuccess( 1222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const base::Closure& callback, 1223010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::vector<uint8>& value) { 1224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(2) << "Remote characteristic/descriptor value read successful."; 1225010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) callback.Run(); 1226010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 1227010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 12286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothLowEnergyEventRouter::OnCreateGattConnection( 12296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) bool persistent, 12306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& extension_id, 12316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& device_address, 12326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const base::Closure& callback, 12336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) scoped_ptr<BluetoothGattConnection> connection) { 12346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) VLOG(2) << "GATT connection created."; 12356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK(connection.get()); 12366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK(!FindConnection(extension_id, device_address)); 12376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) DCHECK_EQ(device_address, connection->GetDeviceAddress()); 1238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string connect_id = extension_id + device_address; 1240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_NE(0U, connecting_devices_.count(connect_id)); 12416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 12426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) BluetoothLowEnergyConnection* conn = new BluetoothLowEnergyConnection( 12436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) persistent, extension_id, connection.Pass()); 12446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ConnectionResourceManager* manager = 12456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) GetConnectionResourceManager(browser_context_); 12466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) manager->Add(conn); 12476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch connecting_devices_.erase(connect_id); 12496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) callback.Run(); 12506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 12516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 12526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothLowEnergyEventRouter::OnDisconnect( 12536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& extension_id, 12546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& device_address, 12556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const base::Closure& callback) { 12566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) VLOG(2) << "GATT connection terminated."; 1257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string disconnect_id = extension_id + device_address; 1259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_NE(0U, disconnecting_devices_.count(disconnect_id)); 1260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 12616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!RemoveConnection(extension_id, device_address)) { 12626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) VLOG(1) << "The connection was removed before disconnect completed, id: " 12636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) << extension_id << ", device: " << device_address; 12646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 12656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch disconnecting_devices_.erase(disconnect_id); 12676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) callback.Run(); 12686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 12696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void BluetoothLowEnergyEventRouter::OnError( 1271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const ErrorCallback& error_callback) { 1272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(2) << "Remote characteristic/descriptor value read/write failed."; 1273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) error_callback.Run(kStatusErrorFailed); 1274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 1275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 12766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BluetoothLowEnergyEventRouter::OnConnectError( 1277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& extension_id, 12786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& device_address, 12796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const ErrorCallback& error_callback, 12806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) BluetoothDevice::ConnectErrorCode error_code) { 12816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) VLOG(2) << "Failed to create GATT connection: " << error_code; 12826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string connect_id = extension_id + device_address; 1284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_NE(0U, connecting_devices_.count(connect_id)); 1285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch connecting_devices_.erase(connect_id); 1287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch error_callback.Run(kStatusErrorFailed); 1288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 1289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1290116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid BluetoothLowEnergyEventRouter::OnStartNotifySession( 1291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool persistent, 1292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& extension_id, 1293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& characteristic_id, 1294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const base::Closure& callback, 1295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<device::BluetoothGattNotifySession> session) { 1296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(2) << "Value update session created for characteristic: " 1297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << characteristic_id; 1298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(session.get()); 1299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK(!FindNotifySession(extension_id, characteristic_id)); 1300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_EQ(characteristic_id, session->GetCharacteristicIdentifier()); 1301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string session_id = extension_id + characteristic_id; 1303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_NE(0U, pending_session_calls_.count(session_id)); 1304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BluetoothLowEnergyNotifySession* resource = 1306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch new BluetoothLowEnergyNotifySession( 1307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch persistent, extension_id, session.Pass()); 1308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch NotifySessionResourceManager* manager = 1310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch GetNotifySessionResourceManager(browser_context_); 1311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch manager->Add(resource); 1312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch pending_session_calls_.erase(session_id); 1314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch callback.Run(); 1315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 1316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1317116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid BluetoothLowEnergyEventRouter::OnStartNotifySessionError( 1318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& extension_id, 1319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& characteristic_id, 1320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const ErrorCallback& error_callback) { 1321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(2) << "Failed to create value update session for characteristic: " 1322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << characteristic_id; 1323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string session_id = extension_id + characteristic_id; 1325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_NE(0U, pending_session_calls_.count(session_id)); 1326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch pending_session_calls_.erase(session_id); 13286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) error_callback.Run(kStatusErrorFailed); 13296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 13306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1331116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid BluetoothLowEnergyEventRouter::OnStopNotifySession( 1332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& extension_id, 1333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& characteristic_id, 1334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const base::Closure& callback) { 1335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(2) << "Value update session terminated."; 1336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1337116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!RemoveNotifySession(extension_id, characteristic_id)) { 1338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "The value update session was removed before Stop completed, " 1339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << "id: " << extension_id 1340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << ", characteristic: " << characteristic_id; 1341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 1342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch callback.Run(); 1344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 1345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 13466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)BluetoothLowEnergyConnection* BluetoothLowEnergyEventRouter::FindConnection( 13476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& extension_id, 13486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& device_address) { 13496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ConnectionResourceManager* manager = 13506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) GetConnectionResourceManager(browser_context_); 13516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 13526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id); 13536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!connection_ids) 13546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return NULL; 13556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 13566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) for (base::hash_set<int>::const_iterator iter = connection_ids->begin(); 13576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) iter != connection_ids->end(); 13586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ++iter) { 13596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extensions::BluetoothLowEnergyConnection* conn = 13606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) manager->Get(extension_id, *iter); 13616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!conn) 13626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) continue; 13636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 13646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (conn->GetConnection()->GetDeviceAddress() == device_address) 13656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return conn; 13666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 13676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 13686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return NULL; 13696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 13706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 13716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)bool BluetoothLowEnergyEventRouter::RemoveConnection( 13726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& extension_id, 13736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const std::string& device_address) { 13746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ConnectionResourceManager* manager = 13756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) GetConnectionResourceManager(browser_context_); 13766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 13776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id); 13786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!connection_ids) 13796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 13806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 13816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) for (base::hash_set<int>::const_iterator iter = connection_ids->begin(); 13826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) iter != connection_ids->end(); 13836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ++iter) { 13846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extensions::BluetoothLowEnergyConnection* conn = 13856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) manager->Get(extension_id, *iter); 13866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (!conn || conn->GetConnection()->GetDeviceAddress() != device_address) 13876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) continue; 13886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 13896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) manager->Remove(extension_id, *iter); 13906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return true; 13916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) } 13926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 13936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return false; 13946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 13956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1396116680a4aac90f2aa7413d9095a592090648e557Ben MurdochBluetoothLowEnergyNotifySession* 1397116680a4aac90f2aa7413d9095a592090648e557Ben MurdochBluetoothLowEnergyEventRouter::FindNotifySession( 1398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& extension_id, 1399116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& characteristic_id) { 1400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch NotifySessionResourceManager* manager = 1401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch GetNotifySessionResourceManager(browser_context_); 1402116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1403116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::hash_set<int>* ids = manager->GetResourceIds(extension_id); 1404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!ids) 1405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return NULL; 1406116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1407116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for (base::hash_set<int>::const_iterator iter = ids->begin(); 1408116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch iter != ids->end(); 1409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ++iter) { 1410116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BluetoothLowEnergyNotifySession* session = 1411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch manager->Get(extension_id, *iter); 1412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!session) 1413116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch continue; 1414116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1415116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (session->GetSession()->GetCharacteristicIdentifier() == 1416116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch characteristic_id) 1417116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return session; 1418116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 1419116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1420116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return NULL; 1421116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 1422116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1423116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool BluetoothLowEnergyEventRouter::RemoveNotifySession( 1424116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& extension_id, 1425116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& characteristic_id) { 1426116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch NotifySessionResourceManager* manager = 1427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch GetNotifySessionResourceManager(browser_context_); 1428116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::hash_set<int>* ids = manager->GetResourceIds(extension_id); 1430116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!ids) 1431116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 1432116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1433116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for (base::hash_set<int>::const_iterator iter = ids->begin(); 1434116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch iter != ids->end(); 1435116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ++iter) { 1436116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch BluetoothLowEnergyNotifySession* session = 1437116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch manager->Get(extension_id, *iter); 1438116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!session || 1439116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch session->GetSession()->GetCharacteristicIdentifier() != 1440116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch characteristic_id) 1441116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch continue; 1442116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1443116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch manager->Remove(extension_id, *iter); 1444116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return true; 1445116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 1446116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1447116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 1448116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 1449116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 14505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} // namespace extensions 1451