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