1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_EVENT_ROUTER_H_
6#define CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_EVENT_ROUTER_H_
7
8#include <map>
9#include <set>
10#include <string>
11#include <vector>
12
13#include "base/callback.h"
14#include "base/memory/linked_ptr.h"
15#include "base/memory/weak_ptr.h"
16#include "chrome/common/extensions/api/bluetooth_low_energy.h"
17#include "content/public/browser/notification_observer.h"
18#include "device/bluetooth/bluetooth_adapter.h"
19#include "device/bluetooth/bluetooth_device.h"
20#include "device/bluetooth/bluetooth_gatt_service.h"
21
22namespace base {
23
24class ListValue;
25
26}  // namespace base
27
28namespace content {
29
30class BrowserContext;
31
32}  // namespace content
33
34namespace device {
35
36class BluetoothGattNotifySession;
37
38}  // namespace device
39
40namespace extensions {
41
42class BluetoothLowEnergyConnection;
43class BluetoothLowEnergyNotifySession;
44class Extension;
45
46// The BluetoothLowEnergyEventRouter is used by the bluetoothLowEnergy API to
47// interface with the internal Bluetooth API in device/bluetooth.
48class BluetoothLowEnergyEventRouter
49    : public device::BluetoothAdapter::Observer,
50      public device::BluetoothDevice::Observer,
51      public device::BluetoothGattService::Observer {
52 public:
53  explicit BluetoothLowEnergyEventRouter(content::BrowserContext* context);
54  virtual ~BluetoothLowEnergyEventRouter();
55
56  // Possible ways that an API method can fail or succeed.
57  enum Status {
58    kStatusSuccess = 0,
59    kStatusErrorPermissionDenied,
60    kStatusErrorNotFound,
61    kStatusErrorAlreadyConnected,
62    kStatusErrorAlreadyNotifying,
63    kStatusErrorNotConnected,
64    kStatusErrorNotNotifying,
65    kStatusErrorInProgress,
66    kStatusErrorFailed
67  };
68
69  // Error callback is used by asynchronous methods to report failures.
70  typedef base::Callback<void(Status)> ErrorCallback;
71
72  // Returns true if Bluetooth is supported on the current platform or if the
73  // internal |adapter_| instance has been initialized for testing.
74  bool IsBluetoothSupported() const;
75
76  // Obtains a handle on the BluetoothAdapter and invokes |callback|. Returns
77  // false, if Bluetooth is not supported. Otherwise, asynchronously initializes
78  // it and invokes |callback|. Until the first successful call to this method,
79  // none of the methods in this class will succeed and no device::Bluetooth*
80  // API events will be observed.
81  bool InitializeAdapterAndInvokeCallback(const base::Closure& callback);
82
83  // Returns true, if the BluetoothAdapter was initialized.
84  bool HasAdapter() const;
85
86  // Creates a GATT connection to the device with address |device_address| for
87  // extension |extension|. The connection is kept alive until the extension is
88  // unloaded, the device is removed, or is disconnect by the host subsystem.
89  // |error_callback| is called with an error status in case of failure. If
90  // |persistent| is true, then the allocated connection resource is persistent
91  // across unloads.
92  void Connect(bool persistent,
93               const Extension* extension,
94               const std::string& device_address,
95               const base::Closure& callback,
96               const ErrorCallback& error_callback);
97
98  // Disconnects the currently open GATT connection of extension |extension| to
99  // device with address |device_address|. |error_callback| is called with an
100  // error status in case of failure, e.g. if the device is not found or the
101  // given
102  // extension does not have an open connection to the device.
103  void Disconnect(const Extension* extension,
104                  const std::string& device_address,
105                  const base::Closure& callback,
106                  const ErrorCallback& error_callback);
107
108  // Returns the list of api::bluetooth_low_energy::Service objects associated
109  // with the Bluetooth device with address |device_address| in |out_services|.
110  // Returns false, if no device with the given address is known. If the device
111  // is found but it has no GATT services, then returns true and leaves
112  // |out_services| empty. Returns true, on success. |out_services| must not
113  // be NULL. If it is non-empty, then its contents will be cleared.
114  typedef std::vector<linked_ptr<api::bluetooth_low_energy::Service> >
115      ServiceList;
116  bool GetServices(const std::string& device_address,
117                   ServiceList* out_services) const;
118
119  // Populates |out_service| based on GATT service with instance ID
120  // |instance_id|. |out_service| must not be NULL.
121  Status GetService(const std::string& instance_id,
122                    api::bluetooth_low_energy::Service* out_service) const;
123
124  // Populates |out_services| with the list of GATT services that are included
125  // by the GATT service with instance ID |instance_id|. Returns false, if not
126  // GATT service with the given ID is known. If the given service has no
127  // included services, then |out_service| will be empty. |out_service| must not
128  // be NULL. If it is non-empty, then its contents will be cleared.
129  Status GetIncludedServices(const std::string& instance_id,
130                             ServiceList* out_services) const;
131
132  // Returns the list of api::bluetooth_low_energy::Characteristic objects
133  // associated with the GATT service with instance ID |instance_id| in
134  // |out_characteristics|. Returns false, if no service with the given instance
135  // ID is known. If the service is found but it has no characteristics, then
136  // returns true and leaves |out_characteristics| empty.
137  // |out_characteristics| must not be NULL and if it is non-empty,
138  // then its contents will be cleared. |extension| is the extension that made
139  // the call.
140  typedef std::vector<linked_ptr<api::bluetooth_low_energy::Characteristic> >
141      CharacteristicList;
142  Status GetCharacteristics(const Extension* extension,
143                            const std::string& instance_id,
144                            CharacteristicList* out_characteristics) const;
145
146  // Populates |out_characteristic| based on GATT characteristic with instance
147  // ID |instance_id|. |out_characteristic| must not be NULL. |extension| is the
148  // extension that made the call.
149  Status GetCharacteristic(
150      const Extension* extension,
151      const std::string& instance_id,
152      api::bluetooth_low_energy::Characteristic* out_characteristic) const;
153
154  // Returns the list of api::bluetooth_low_energy::Descriptor objects
155  // associated with the GATT characteristic with instance ID |instance_id| in
156  // |out_descriptors|. If the characteristic is found but it has no
157  // descriptors, then returns true and leaves |out_descriptors| empty.
158  // |out_descriptors| must not be NULL and if it is non-empty,
159  // then its contents will be cleared. |extension| is the extension that made
160  // the call.
161  typedef std::vector<linked_ptr<api::bluetooth_low_energy::Descriptor> >
162      DescriptorList;
163  Status GetDescriptors(const Extension* extension,
164                        const std::string& instance_id,
165                        DescriptorList* out_descriptors) const;
166
167  // Populates |out_descriptor| based on GATT characteristic descriptor with
168  // instance ID |instance_id|. |out_descriptor| must not be NULL.
169  // |extension| is the extension that made the call.
170  Status GetDescriptor(
171      const Extension* extension,
172      const std::string& instance_id,
173      api::bluetooth_low_energy::Descriptor* out_descriptor) const;
174
175  // Sends a request to read the value of the characteristic with intance ID
176  // |instance_id|. Invokes |callback| on success and |error_callback| on
177  // failure. |extension| is the extension that made the call.
178  void ReadCharacteristicValue(const Extension* extension,
179                               const std::string& instance_id,
180                               const base::Closure& callback,
181                               const ErrorCallback& error_callback);
182
183  // Sends a request to write the value of the characteristic with instance ID
184  // |instance_id|. Invokes |callback| on success and |error_callback| on
185  // failure. |extension| is the extension that made the call.
186  void WriteCharacteristicValue(const Extension* extension,
187                                const std::string& instance_id,
188                                const std::vector<uint8>& value,
189                                const base::Closure& callback,
190                                const ErrorCallback& error_callback);
191
192  // Sends a request to start characteristic notifications from characteristic
193  // with instance ID |instance_id|, for extension |extension|. Invokes
194  // |callback| on success and |error_callback| on failure. If |persistent| is
195  // true, then the allocated connection resource is persistent across unloads.
196  void StartCharacteristicNotifications(bool persistent,
197                                        const Extension* extension,
198                                        const std::string& instance_id,
199                                        const base::Closure& callback,
200                                        const ErrorCallback& error_callback);
201
202  // Sends a request to stop characteristic notifications from characteristic
203  // with instance ID |instance_id|, for extension |extension|. Invokes
204  // |callback| on success and |error_callback| on failure.
205  void StopCharacteristicNotifications(const Extension* extension,
206                                       const std::string& instance_id,
207                                       const base::Closure& callback,
208                                       const ErrorCallback& error_callback);
209
210  // Sends a request to read the value of the descriptor with instance ID
211  // |instance_id|. Invokes |callback| on success and |error_callback| on
212  // failure. |extension| is the extension that made the call.
213  void ReadDescriptorValue(const Extension* extension,
214                           const std::string& instance_id,
215                           const base::Closure& callback,
216                           const ErrorCallback& error_callback);
217
218  // Sends a request to write the value of the descriptor with instance ID
219  // |instance_id|. Invokes |callback| on success and |error_callback| on
220  // failure. |extension| is the extension that made the call.
221  void WriteDescriptorValue(const Extension* extension,
222                            const std::string& instance_id,
223                            const std::vector<uint8>& value,
224                            const base::Closure& callback,
225                            const ErrorCallback& error_callback);
226
227  // Initializes the adapter for testing. Used by unit tests only.
228  void SetAdapterForTesting(device::BluetoothAdapter* adapter);
229
230  // device::BluetoothAdapter::Observer overrides.
231  virtual void DeviceAdded(device::BluetoothAdapter* adapter,
232                           device::BluetoothDevice* device) OVERRIDE;
233  virtual void DeviceRemoved(device::BluetoothAdapter* adapter,
234                             device::BluetoothDevice* device) OVERRIDE;
235
236  // device::BluetoothDevice::Observer overrides.
237  virtual void GattServiceAdded(device::BluetoothDevice* device,
238                                device::BluetoothGattService* service) OVERRIDE;
239  virtual void GattServiceRemoved(
240      device::BluetoothDevice* device,
241      device::BluetoothGattService* service) OVERRIDE;
242
243  // device::BluetoothGattService::Observer overrides.
244  virtual void GattServiceChanged(
245      device::BluetoothGattService* service) OVERRIDE;
246  virtual void GattCharacteristicAdded(
247      device::BluetoothGattService* service,
248      device::BluetoothGattCharacteristic* characteristic) OVERRIDE;
249  virtual void GattCharacteristicRemoved(
250      device::BluetoothGattService* service,
251      device::BluetoothGattCharacteristic* characteristic) OVERRIDE;
252  virtual void GattDescriptorAdded(
253      device::BluetoothGattCharacteristic* characteristic,
254      device::BluetoothGattDescriptor* descriptor) OVERRIDE;
255  virtual void GattDescriptorRemoved(
256      device::BluetoothGattCharacteristic* characteristic,
257      device::BluetoothGattDescriptor* descriptor) OVERRIDE;
258  virtual void GattCharacteristicValueChanged(
259      device::BluetoothGattService* service,
260      device::BluetoothGattCharacteristic* characteristic,
261      const std::vector<uint8>& value) OVERRIDE;
262  virtual void GattDescriptorValueChanged(
263      device::BluetoothGattCharacteristic* characteristic,
264      device::BluetoothGattDescriptor* descriptor,
265      const std::vector<uint8>& value) OVERRIDE;
266
267 private:
268  // Called by BluetoothAdapterFactory.
269  void OnGetAdapter(const base::Closure& callback,
270                    scoped_refptr<device::BluetoothAdapter> adapter);
271
272  // Initializes the identifier for all existing GATT objects and devices.
273  // Called by OnGetAdapter and SetAdapterForTesting.
274  void InitializeIdentifierMappings();
275
276  // Sends the event named |event_name| to all listeners of that event that
277  // have the Bluetooth UUID manifest permission for UUID |uuid| and the
278  // "low_energy" manifest permission, with |args| as the argument to that
279  // event. If the event involves a characteristic, then |characteristic_id|
280  // should be the instance ID of the involved characteristic. Otherwise, an
281  // empty string should be passed.
282  void DispatchEventToExtensionsWithPermission(
283      const std::string& event_name,
284      const device::BluetoothUUID& uuid,
285      const std::string& characteristic_id,
286      scoped_ptr<base::ListValue> args);
287
288  // Returns a BluetoothGattService by its instance ID |instance_id|. Returns
289  // NULL, if the service cannot be found.
290  device::BluetoothGattService* FindServiceById(
291      const std::string& instance_id) const;
292
293  // Returns a BluetoothGattCharacteristic by its instance ID |instance_id|.
294  // Returns NULL, if the characteristic cannot be found.
295  device::BluetoothGattCharacteristic* FindCharacteristicById(
296      const std::string& instance_id) const;
297
298  // Returns a BluetoothGattDescriptor by its instance ID |instance_id|.
299  // Returns NULL, if the descriptor cannot be found.
300  device::BluetoothGattDescriptor* FindDescriptorById(
301      const std::string& instance_id) const;
302
303  // Called by BluetoothGattCharacteristic and BluetoothGattDescriptor in
304  // response to ReadRemoteCharacteristic and ReadRemoteDescriptor.
305  void OnValueSuccess(const base::Closure& callback,
306                      const std::vector<uint8>& value);
307
308  // Called by BluetoothDevice in response to a call to CreateGattConnection.
309  void OnCreateGattConnection(
310      bool persistent,
311      const std::string& extension_id,
312      const std::string& device_address,
313      const base::Closure& callback,
314      scoped_ptr<device::BluetoothGattConnection> connection);
315
316  // Called by BluetoothGattConnection in response to a call to Disconnect.
317  void OnDisconnect(const std::string& extension_id,
318                    const std::string& device_address,
319                    const base::Closure& callback);
320
321  // Called by BluetoothGattCharacteristic and BluetoothGattDescriptor in
322  // case of an error during the read/write operations.
323  void OnError(const ErrorCallback& error_callback);
324
325  // Called by BluetoothDevice in response to a call to CreateGattConnection.
326  void OnConnectError(const std::string& extension_id,
327                      const std::string& device_address,
328                      const ErrorCallback& error_callback,
329                      device::BluetoothDevice::ConnectErrorCode error_code);
330
331  // Called by BluetoothGattCharacteristic in response to a call to
332  // StartNotifySession.
333  void OnStartNotifySession(
334      bool persistent,
335      const std::string& extension_id,
336      const std::string& characteristic_id,
337      const base::Closure& callback,
338      scoped_ptr<device::BluetoothGattNotifySession> session);
339
340  // Called by BluetoothGattCharacteristic in response to a call to
341  // StartNotifySession.
342  void OnStartNotifySessionError(const std::string& extension_id,
343                                 const std::string& characteristic_id,
344                                 const ErrorCallback& error_callback);
345
346  // Called by BluetoothGattNotifySession in response to a call to Stop.
347  void OnStopNotifySession(const std::string& extension_id,
348                           const std::string& characteristic_id,
349                           const base::Closure& callback);
350
351  // Finds and returns a BluetoothLowEnergyConnection to device with address
352  // |device_address| from the managed API resources for extension with ID
353  // |extension_id|.
354  BluetoothLowEnergyConnection* FindConnection(
355      const std::string& extension_id,
356      const std::string& device_address);
357
358  // Removes the connection to device with address |device_address| from the
359  // managed API resources for extension with ID |extension_id|. Returns false,
360  // if the connection could not be found.
361  bool RemoveConnection(const std::string& extension_id,
362                        const std::string& device_address);
363
364  // Finds and returns a BluetoothLowEnergyNotifySession associated with
365  // characteristic with instance ID |characteristic_id| from the managed API
366  // API resources for extension with ID |extension_id|.
367  BluetoothLowEnergyNotifySession* FindNotifySession(
368      const std::string& extension_id,
369      const std::string& characteristic_id);
370
371  // Removes the notify session associated with characteristic with
372  // instance ID |characteristic_id| from the managed API resources for
373  // extension with ID |extension_id|. Returns false, if the session could
374  // not be found.
375  bool RemoveNotifySession(const std::string& extension_id,
376                           const std::string& characteristic_id);
377
378  // Mapping from instance ids to identifiers of owning instances. The keys are
379  // used to identify individual instances of GATT objects and are used by
380  // bluetoothLowEnergy API functions to obtain the correct GATT object to
381  // operate on. Instance IDs are string identifiers that are returned by the
382  // device/bluetooth API, by calling GetIdentifier() on the corresponding
383  // device::BluetoothGatt* instance.
384  //
385  // This mapping is necessary, as GATT object instances can only be obtained
386  // from the object that owns it, where raw pointers should not be cached. E.g.
387  // to obtain a device::BluetoothGattCharacteristic, it is necessary to obtain
388  // a pointer to the associated device::BluetoothDevice, and then to the
389  // device::BluetoothGattService that owns the characteristic.
390  typedef std::map<std::string, std::string> InstanceIdMap;
391  InstanceIdMap service_id_to_device_address_;
392  InstanceIdMap chrc_id_to_service_id_;
393  InstanceIdMap desc_id_to_chrc_id_;
394
395  // Sets of BluetoothDevice and BluetoothGattService objects that are being
396  // observed, used to remove the BluetoothLowEnergyEventRouter as an observer
397  // during clean up.
398  std::set<std::string> observed_devices_;
399  std::set<std::string> observed_gatt_services_;
400
401  // Pointer to the current BluetoothAdapter instance. This represents a local
402  // Bluetooth adapter of the system.
403  scoped_refptr<device::BluetoothAdapter> adapter_;
404
405  // Set of extension ID + device addresses to which a connect/disconnect is
406  // currently pending.
407  std::set<std::string> connecting_devices_;
408  std::set<std::string> disconnecting_devices_;
409
410  // Set of extension ID + characteristic ID to which a request to start a
411  // notify session is currently pending.
412  std::set<std::string> pending_session_calls_;
413
414  // BrowserContext passed during initialization.
415  content::BrowserContext* browser_context_;
416
417  // Note: This should remain the last member so it'll be destroyed and
418  // invalidate its weak pointers before any other members are destroyed.
419  base::WeakPtrFactory<BluetoothLowEnergyEventRouter> weak_ptr_factory_;
420
421  DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyEventRouter);
422};
423
424}  // namespace extensions
425
426#endif  // CHROME_BROWSER_EXTENSIONS_API_BLUETOOTH_LOW_ENERGY_BLUETOOTH_LOW_ENERGY_EVENT_ROUTER_H_
427