1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos/dbus/bluetooth_gatt_characteristic_client.h"
6
7#include "base/bind.h"
8#include "base/memory/weak_ptr.h"
9#include "base/observer_list.h"
10#include "dbus/bus.h"
11#include "dbus/object_manager.h"
12#include "third_party/cros_system_api/dbus/service_constants.h"
13
14namespace chromeos {
15
16// static
17const char BluetoothGattCharacteristicClient::kNoResponseError[] =
18    "org.chromium.Error.NoResponse";
19// static
20const char BluetoothGattCharacteristicClient::kUnknownCharacteristicError[] =
21    "org.chromium.Error.UnknownCharacteristic";
22
23BluetoothGattCharacteristicClient::Properties::Properties(
24    dbus::ObjectProxy* object_proxy,
25    const std::string& interface_name,
26    const PropertyChangedCallback& callback)
27    : dbus::PropertySet(object_proxy, interface_name, callback) {
28  RegisterProperty(bluetooth_gatt_characteristic::kUUIDProperty, &uuid);
29  RegisterProperty(bluetooth_gatt_characteristic::kServiceProperty, &service);
30  RegisterProperty(bluetooth_gatt_characteristic::kNotifyingProperty,
31                   &notifying);
32  RegisterProperty(bluetooth_gatt_characteristic::kFlagsProperty, &flags);
33  RegisterProperty(bluetooth_gatt_characteristic::kDescriptorsProperty,
34                   &descriptors);
35}
36
37BluetoothGattCharacteristicClient::Properties::~Properties() {
38}
39
40// The BluetoothGattCharacteristicClient implementation used in production.
41class BluetoothGattCharacteristicClientImpl
42    : public BluetoothGattCharacteristicClient,
43      public dbus::ObjectManager::Interface {
44 public:
45  BluetoothGattCharacteristicClientImpl()
46      : object_manager_(NULL),
47        weak_ptr_factory_(this) {
48  }
49
50  virtual ~BluetoothGattCharacteristicClientImpl() {
51    object_manager_->UnregisterInterface(
52        bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface);
53  }
54
55  // BluetoothGattCharacteristicClient override.
56  virtual void AddObserver(
57      BluetoothGattCharacteristicClient::Observer* observer) OVERRIDE {
58    DCHECK(observer);
59    observers_.AddObserver(observer);
60  }
61
62  // BluetoothGattCharacteristicClient override.
63  virtual void RemoveObserver(
64      BluetoothGattCharacteristicClient::Observer* observer) OVERRIDE {
65    DCHECK(observer);
66    observers_.RemoveObserver(observer);
67  }
68
69  // BluetoothGattCharacteristicClient override.
70  virtual std::vector<dbus::ObjectPath> GetCharacteristics() OVERRIDE {
71    DCHECK(object_manager_);
72    return object_manager_->GetObjectsWithInterface(
73        bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface);
74  }
75
76  // BluetoothGattCharacteristicClient override.
77  virtual Properties* GetProperties(
78      const dbus::ObjectPath& object_path) OVERRIDE {
79    DCHECK(object_manager_);
80    return static_cast<Properties*>(
81        object_manager_->GetProperties(
82            object_path,
83            bluetooth_gatt_characteristic::
84                kBluetoothGattCharacteristicInterface));
85  }
86
87  // BluetoothGattCharacteristicClient override.
88  virtual void ReadValue(const dbus::ObjectPath& object_path,
89                         const ValueCallback& callback,
90                         const ErrorCallback& error_callback) OVERRIDE {
91    dbus::ObjectProxy* object_proxy =
92        object_manager_->GetObjectProxy(object_path);
93    if (!object_proxy) {
94      error_callback.Run(kUnknownCharacteristicError, "");
95      return;
96    }
97
98    dbus::MethodCall method_call(
99        bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
100        bluetooth_gatt_characteristic::kReadValue);
101
102    object_proxy->CallMethodWithErrorCallback(
103        &method_call,
104        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
105        base::Bind(&BluetoothGattCharacteristicClientImpl::OnValueSuccess,
106                   weak_ptr_factory_.GetWeakPtr(),
107                   callback),
108        base::Bind(&BluetoothGattCharacteristicClientImpl::OnError,
109                   weak_ptr_factory_.GetWeakPtr(),
110                   error_callback));
111  }
112
113  // BluetoothGattCharacteristicClient override.
114  virtual void WriteValue(const dbus::ObjectPath& object_path,
115                          const std::vector<uint8>& value,
116                          const base::Closure& callback,
117                          const ErrorCallback& error_callback) OVERRIDE {
118    dbus::ObjectProxy* object_proxy =
119        object_manager_->GetObjectProxy(object_path);
120    if (!object_proxy) {
121      error_callback.Run(kUnknownCharacteristicError, "");
122      return;
123    }
124
125    dbus::MethodCall method_call(
126        bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
127        bluetooth_gatt_characteristic::kWriteValue);
128    dbus::MessageWriter writer(&method_call);
129    writer.AppendArrayOfBytes(value.data(), value.size());
130
131    object_proxy->CallMethodWithErrorCallback(
132        &method_call,
133        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
134        base::Bind(&BluetoothGattCharacteristicClientImpl::OnSuccess,
135                   weak_ptr_factory_.GetWeakPtr(),
136                   callback),
137        base::Bind(&BluetoothGattCharacteristicClientImpl::OnError,
138                   weak_ptr_factory_.GetWeakPtr(),
139                   error_callback));
140  }
141
142  // BluetoothGattCharacteristicClient override.
143  virtual void StartNotify(const dbus::ObjectPath& object_path,
144                           const base::Closure& callback,
145                           const ErrorCallback& error_callback) OVERRIDE {
146    dbus::ObjectProxy* object_proxy =
147        object_manager_->GetObjectProxy(object_path);
148    if (!object_proxy) {
149      error_callback.Run(kUnknownCharacteristicError, "");
150      return;
151    }
152
153    dbus::MethodCall method_call(
154        bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
155        bluetooth_gatt_characteristic::kStartNotify);
156
157    object_proxy->CallMethodWithErrorCallback(
158        &method_call,
159        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
160        base::Bind(&BluetoothGattCharacteristicClientImpl::OnSuccess,
161                   weak_ptr_factory_.GetWeakPtr(),
162                   callback),
163        base::Bind(&BluetoothGattCharacteristicClientImpl::OnError,
164                   weak_ptr_factory_.GetWeakPtr(),
165                   error_callback));
166  }
167
168  // BluetoothGattCharacteristicClient override.
169  virtual void StopNotify(const dbus::ObjectPath& object_path,
170                          const base::Closure& callback,
171                          const ErrorCallback& error_callback) OVERRIDE {
172    dbus::ObjectProxy* object_proxy =
173        object_manager_->GetObjectProxy(object_path);
174    if (!object_proxy) {
175      error_callback.Run(kUnknownCharacteristicError, "");
176      return;
177    }
178
179    dbus::MethodCall method_call(
180        bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
181        bluetooth_gatt_characteristic::kStopNotify);
182
183    object_proxy->CallMethodWithErrorCallback(
184        &method_call,
185        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
186        base::Bind(&BluetoothGattCharacteristicClientImpl::OnSuccess,
187                   weak_ptr_factory_.GetWeakPtr(),
188                   callback),
189        base::Bind(&BluetoothGattCharacteristicClientImpl::OnError,
190                   weak_ptr_factory_.GetWeakPtr(),
191                   error_callback));
192  }
193
194  // dbus::ObjectManager::Interface override.
195  virtual dbus::PropertySet* CreateProperties(
196      dbus::ObjectProxy *object_proxy,
197      const dbus::ObjectPath& object_path,
198      const std::string& interface_name) OVERRIDE {
199    Properties* properties = new Properties(
200        object_proxy,
201        interface_name,
202        base::Bind(&BluetoothGattCharacteristicClientImpl::OnPropertyChanged,
203                   weak_ptr_factory_.GetWeakPtr(),
204                   object_path));
205    return static_cast<dbus::PropertySet*>(properties);
206  }
207
208  // dbus::ObjectManager::Interface override.
209  virtual void ObjectAdded(const dbus::ObjectPath& object_path,
210                           const std::string& interface_name) OVERRIDE {
211    VLOG(2) << "Remote GATT characteristic added: " << object_path.value();
212    FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer, observers_,
213                      GattCharacteristicAdded(object_path));
214
215    // Connect the "ValueUpdated" signal.
216    dbus::ObjectProxy* object_proxy =
217        object_manager_->GetObjectProxy(object_path);
218    DCHECK(object_proxy);
219
220    object_proxy->ConnectToSignal(
221        bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
222        bluetooth_gatt_characteristic::kValueUpdatedSignal,
223        base::Bind(&BluetoothGattCharacteristicClientImpl::ValueUpdatedReceived,
224                   weak_ptr_factory_.GetWeakPtr(),
225                   object_path),
226        base::Bind(
227            &BluetoothGattCharacteristicClientImpl::ValueUpdatedConnected,
228            weak_ptr_factory_.GetWeakPtr()));
229  }
230
231  // dbus::ObjectManager::Interface override.
232  virtual void ObjectRemoved(const dbus::ObjectPath& object_path,
233                             const std::string& interface_name) OVERRIDE {
234    VLOG(2) << "Remote GATT characteristic removed: " << object_path.value();
235    FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer, observers_,
236                      GattCharacteristicRemoved(object_path));
237  }
238
239 protected:
240  // chromeos::DBusClient override.
241  virtual void Init(dbus::Bus* bus) OVERRIDE {
242    object_manager_ = bus->GetObjectManager(
243        bluetooth_object_manager::kBluetoothObjectManagerServiceName,
244        dbus::ObjectPath(
245            bluetooth_object_manager::kBluetoothObjectManagerServicePath));
246    object_manager_->RegisterInterface(
247        bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
248        this);
249  }
250
251 private:
252  // Called by dbus::PropertySet when a property value is changed, either by
253  // result of a signal or response to a GetAll() or Get() call. Informs
254  // observers.
255  virtual void OnPropertyChanged(const dbus::ObjectPath& object_path,
256                                 const std::string& property_name) {
257    VLOG(2) << "Remote GATT characteristic property changed: "
258            << object_path.value() << ": " << property_name;
259    FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer, observers_,
260                      GattCharacteristicPropertyChanged(object_path,
261                                                        property_name));
262  }
263
264  // Called by dbus:: when a "ValueUpdated" signal is received.
265  void ValueUpdatedReceived(const dbus::ObjectPath& object_path,
266                            dbus::Signal* signal) {
267    DCHECK(signal);
268    const uint8* bytes = NULL;
269    size_t length = 0;
270    dbus::MessageReader reader(signal);
271    if (!reader.PopArrayOfBytes(&bytes, &length)) {
272      LOG(WARNING) << "ValueUpdated signal has incorrect parameters: "
273                   << signal->ToString();
274      return;
275    }
276
277    std::vector<uint8> value;
278    if (bytes)
279      value.assign(bytes, bytes + length);
280
281    FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer,
282                      observers_,
283                      GattCharacteristicValueUpdated(object_path, value));
284  }
285
286  // Called by dbus:: when the "ValueUpdated" signal is initially connected.
287  void ValueUpdatedConnected(const std::string& interface_name,
288                             const std::string& signal_name,
289                             bool success) {
290    LOG_IF(WARNING, !success) << "Failed to connect to the ValueUpdated signal";
291  }
292
293  // Called when a response for successful method call is received.
294  void OnSuccess(const base::Closure& callback, dbus::Response* response) {
295    DCHECK(response);
296    callback.Run();
297  }
298
299  // Called when a characteristic value response for a successful method call
300  // is received.
301  void OnValueSuccess(const ValueCallback& callback, dbus::Response* response) {
302    DCHECK(response);
303    dbus::MessageReader reader(response);
304
305    const uint8* bytes = NULL;
306    size_t length = 0;
307
308    if (!reader.PopArrayOfBytes(&bytes, &length))
309      VLOG(2) << "Error reading array of bytes in ValueCallback";
310
311    std::vector<uint8> value;
312
313    if (bytes)
314      value.assign(bytes, bytes + length);
315
316    callback.Run(value);
317  }
318
319  // Called when a response for a failed method call is received.
320  void OnError(const ErrorCallback& error_callback,
321               dbus::ErrorResponse* response) {
322    // Error response has optional error message argument.
323    std::string error_name;
324    std::string error_message;
325    if (response) {
326      dbus::MessageReader reader(response);
327      error_name = response->GetErrorName();
328      reader.PopString(&error_message);
329    } else {
330      error_name = kNoResponseError;
331      error_message = "";
332    }
333    error_callback.Run(error_name, error_message);
334  }
335
336  dbus::ObjectManager* object_manager_;
337
338  // List of observers interested in event notifications from us.
339  ObserverList<BluetoothGattCharacteristicClient::Observer> observers_;
340
341  // Weak pointer factory for generating 'this' pointers that might live longer
342  // than we do.
343  // Note: This should remain the last member so it'll be destroyed and
344  // invalidate its weak pointers before any other members are destroyed.
345  base::WeakPtrFactory<BluetoothGattCharacteristicClientImpl>
346      weak_ptr_factory_;
347
348  DISALLOW_COPY_AND_ASSIGN(BluetoothGattCharacteristicClientImpl);
349};
350
351BluetoothGattCharacteristicClient::BluetoothGattCharacteristicClient() {
352}
353
354BluetoothGattCharacteristicClient::~BluetoothGattCharacteristicClient() {
355}
356
357// static
358BluetoothGattCharacteristicClient* BluetoothGattCharacteristicClient::Create() {
359  return new BluetoothGattCharacteristicClientImpl();
360}
361
362}  // namespace chromeos
363