1// Copyright 2013 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_device_client.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/stl_util.h"
10#include "dbus/bus.h"
11#include "dbus/message.h"
12#include "dbus/object_manager.h"
13#include "dbus/object_path.h"
14#include "dbus/object_proxy.h"
15#include "third_party/cros_system_api/dbus/service_constants.h"
16
17namespace chromeos {
18
19const char BluetoothDeviceClient::kNoResponseError[] =
20    "org.chromium.Error.NoResponse";
21const char BluetoothDeviceClient::kUnknownDeviceError[] =
22    "org.chromium.Error.UnknownDevice";
23
24BluetoothDeviceClient::Properties::Properties(
25    dbus::ObjectProxy* object_proxy,
26    const std::string& interface_name,
27    const PropertyChangedCallback& callback)
28    : dbus::PropertySet(object_proxy, interface_name, callback) {
29  RegisterProperty(bluetooth_device::kAddressProperty, &address);
30  RegisterProperty(bluetooth_device::kNameProperty, &name);
31  RegisterProperty(bluetooth_device::kIconProperty, &icon);
32  RegisterProperty(bluetooth_device::kClassProperty, &bluetooth_class);
33  RegisterProperty(bluetooth_device::kAppearanceProperty, &appearance);
34  RegisterProperty(bluetooth_device::kUUIDsProperty, &uuids);
35  RegisterProperty(bluetooth_device::kPairedProperty, &paired);
36  RegisterProperty(bluetooth_device::kConnectedProperty, &connected);
37  RegisterProperty(bluetooth_device::kTrustedProperty, &trusted);
38  RegisterProperty(bluetooth_device::kBlockedProperty, &blocked);
39  RegisterProperty(bluetooth_device::kAliasProperty, &alias);
40  RegisterProperty(bluetooth_device::kAdapterProperty, &adapter);
41  RegisterProperty(bluetooth_device::kLegacyPairingProperty, &legacy_pairing);
42  RegisterProperty(bluetooth_device::kModaliasProperty, &modalias);
43  RegisterProperty(bluetooth_device::kRSSIProperty, &rssi);
44  RegisterProperty(bluetooth_device::kConnectionRSSI, &connection_rssi);
45  RegisterProperty(bluetooth_device::kConnectionTXPower, &connection_tx_power);
46  RegisterProperty(bluetooth_device::kConnectionTXPowerMax,
47                   &connection_tx_power_max);
48}
49
50BluetoothDeviceClient::Properties::~Properties() {
51}
52
53
54// The BluetoothDeviceClient implementation used in production.
55class BluetoothDeviceClientImpl
56    : public BluetoothDeviceClient,
57      public dbus::ObjectManager::Interface {
58 public:
59  BluetoothDeviceClientImpl()
60      : object_manager_(NULL), weak_ptr_factory_(this) {}
61
62  virtual ~BluetoothDeviceClientImpl() {
63    object_manager_->UnregisterInterface(
64        bluetooth_device::kBluetoothDeviceInterface);
65  }
66
67  // BluetoothDeviceClient override.
68  virtual void AddObserver(BluetoothDeviceClient::Observer* observer)
69      OVERRIDE {
70    DCHECK(observer);
71    observers_.AddObserver(observer);
72  }
73
74  // BluetoothDeviceClient override.
75  virtual void RemoveObserver(BluetoothDeviceClient::Observer* observer)
76      OVERRIDE {
77    DCHECK(observer);
78    observers_.RemoveObserver(observer);
79  }
80
81  // dbus::ObjectManager::Interface override.
82  virtual dbus::PropertySet* CreateProperties(
83      dbus::ObjectProxy* object_proxy,
84      const dbus::ObjectPath& object_path,
85      const std::string& interface_name) OVERRIDE {
86    Properties* properties = new Properties(
87        object_proxy,
88        interface_name,
89        base::Bind(&BluetoothDeviceClientImpl::OnPropertyChanged,
90                   weak_ptr_factory_.GetWeakPtr(),
91                   object_path));
92    return static_cast<dbus::PropertySet*>(properties);
93  }
94
95  // BluetoothDeviceClient override.
96  virtual std::vector<dbus::ObjectPath> GetDevicesForAdapter(
97      const dbus::ObjectPath& adapter_path) OVERRIDE {
98    std::vector<dbus::ObjectPath> object_paths, device_paths;
99    device_paths = object_manager_->GetObjectsWithInterface(
100        bluetooth_device::kBluetoothDeviceInterface);
101    for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
102         iter != device_paths.end(); ++iter) {
103      Properties* properties = GetProperties(*iter);
104      if (properties->adapter.value() == adapter_path)
105        object_paths.push_back(*iter);
106    }
107    return object_paths;
108  }
109
110  // BluetoothDeviceClient override.
111  virtual Properties* GetProperties(const dbus::ObjectPath& object_path)
112      OVERRIDE {
113    return static_cast<Properties*>(
114        object_manager_->GetProperties(
115            object_path,
116            bluetooth_device::kBluetoothDeviceInterface));
117  }
118
119  // BluetoothDeviceClient override.
120  virtual void Connect(const dbus::ObjectPath& object_path,
121                       const base::Closure& callback,
122                       const ErrorCallback& error_callback) OVERRIDE {
123    dbus::MethodCall method_call(
124        bluetooth_device::kBluetoothDeviceInterface,
125        bluetooth_device::kConnect);
126
127    dbus::ObjectProxy* object_proxy =
128        object_manager_->GetObjectProxy(object_path);
129    if (!object_proxy) {
130      error_callback.Run(kUnknownDeviceError, "");
131      return;
132    }
133
134    // Connect may take an arbitrary length of time, so use no timeout.
135    object_proxy->CallMethodWithErrorCallback(
136        &method_call,
137        dbus::ObjectProxy::TIMEOUT_INFINITE,
138        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
139                   weak_ptr_factory_.GetWeakPtr(), callback),
140        base::Bind(&BluetoothDeviceClientImpl::OnError,
141                   weak_ptr_factory_.GetWeakPtr(), error_callback));
142  }
143
144  // BluetoothDeviceClient override.
145  virtual void Disconnect(const dbus::ObjectPath& object_path,
146                          const base::Closure& callback,
147                          const ErrorCallback& error_callback) OVERRIDE {
148    dbus::MethodCall method_call(
149        bluetooth_device::kBluetoothDeviceInterface,
150        bluetooth_device::kDisconnect);
151
152    dbus::ObjectProxy* object_proxy =
153        object_manager_->GetObjectProxy(object_path);
154    if (!object_proxy) {
155      error_callback.Run(kUnknownDeviceError, "");
156      return;
157    }
158
159    object_proxy->CallMethodWithErrorCallback(
160        &method_call,
161        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
162        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
163                   weak_ptr_factory_.GetWeakPtr(), callback),
164        base::Bind(&BluetoothDeviceClientImpl::OnError,
165                   weak_ptr_factory_.GetWeakPtr(), error_callback));
166  }
167
168  // BluetoothDeviceClient override.
169  virtual void ConnectProfile(const dbus::ObjectPath& object_path,
170                              const std::string& uuid,
171                              const base::Closure& callback,
172                              const ErrorCallback& error_callback) OVERRIDE {
173    dbus::MethodCall method_call(
174        bluetooth_device::kBluetoothDeviceInterface,
175        bluetooth_device::kConnectProfile);
176
177    dbus::MessageWriter writer(&method_call);
178    writer.AppendString(uuid);
179
180    dbus::ObjectProxy* object_proxy =
181        object_manager_->GetObjectProxy(object_path);
182    if (!object_proxy) {
183      error_callback.Run(kUnknownDeviceError, "");
184      return;
185    }
186
187    // Connect may take an arbitrary length of time, so use no timeout.
188    object_proxy->CallMethodWithErrorCallback(
189        &method_call,
190        dbus::ObjectProxy::TIMEOUT_INFINITE,
191        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
192                   weak_ptr_factory_.GetWeakPtr(), callback),
193        base::Bind(&BluetoothDeviceClientImpl::OnError,
194                   weak_ptr_factory_.GetWeakPtr(), error_callback));
195  }
196
197  // BluetoothDeviceClient override.
198  virtual void DisconnectProfile(const dbus::ObjectPath& object_path,
199                                 const std::string& uuid,
200                                 const base::Closure& callback,
201                                 const ErrorCallback& error_callback)
202        OVERRIDE {
203    dbus::MethodCall method_call(
204        bluetooth_device::kBluetoothDeviceInterface,
205        bluetooth_device::kDisconnectProfile);
206
207    dbus::MessageWriter writer(&method_call);
208    writer.AppendString(uuid);
209
210    dbus::ObjectProxy* object_proxy =
211        object_manager_->GetObjectProxy(object_path);
212    if (!object_proxy) {
213      error_callback.Run(kUnknownDeviceError, "");
214      return;
215    }
216
217    object_proxy->CallMethodWithErrorCallback(
218        &method_call,
219        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
220        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
221                   weak_ptr_factory_.GetWeakPtr(), callback),
222        base::Bind(&BluetoothDeviceClientImpl::OnError,
223                   weak_ptr_factory_.GetWeakPtr(), error_callback));
224  }
225
226  // BluetoothDeviceClient override.
227  virtual void Pair(const dbus::ObjectPath& object_path,
228                    const base::Closure& callback,
229                    const ErrorCallback& error_callback) OVERRIDE {
230    dbus::MethodCall method_call(
231        bluetooth_device::kBluetoothDeviceInterface,
232        bluetooth_device::kPair);
233
234    dbus::ObjectProxy* object_proxy =
235        object_manager_->GetObjectProxy(object_path);
236    if (!object_proxy) {
237      error_callback.Run(kUnknownDeviceError, "");
238      return;
239    }
240
241    // Pairing may take an arbitrary length of time, so use no timeout.
242    object_proxy->CallMethodWithErrorCallback(
243        &method_call,
244        dbus::ObjectProxy::TIMEOUT_INFINITE,
245        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
246                   weak_ptr_factory_.GetWeakPtr(), callback),
247        base::Bind(&BluetoothDeviceClientImpl::OnError,
248                   weak_ptr_factory_.GetWeakPtr(), error_callback));
249  }
250
251  // BluetoothDeviceClient override.
252  virtual void CancelPairing(const dbus::ObjectPath& object_path,
253                             const base::Closure& callback,
254                             const ErrorCallback& error_callback)
255        OVERRIDE {
256    dbus::MethodCall method_call(
257        bluetooth_device::kBluetoothDeviceInterface,
258        bluetooth_device::kCancelPairing);
259
260    dbus::ObjectProxy* object_proxy =
261        object_manager_->GetObjectProxy(object_path);
262    if (!object_proxy) {
263      error_callback.Run(kUnknownDeviceError, "");
264      return;
265    }
266    object_proxy->CallMethodWithErrorCallback(
267        &method_call,
268        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
269        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
270                   weak_ptr_factory_.GetWeakPtr(), callback),
271        base::Bind(&BluetoothDeviceClientImpl::OnError,
272                   weak_ptr_factory_.GetWeakPtr(), error_callback));
273  }
274
275  // BluetoothDeviceClient override.
276  virtual void StartConnectionMonitor(
277      const dbus::ObjectPath& object_path,
278      const base::Closure& callback,
279      const ErrorCallback& error_callback) OVERRIDE {
280    dbus::MethodCall method_call(bluetooth_device::kBluetoothDeviceInterface,
281                                 bluetooth_device::kStartConnectionMonitor);
282
283    dbus::ObjectProxy* object_proxy =
284        object_manager_->GetObjectProxy(object_path);
285    if (!object_proxy) {
286      error_callback.Run(kUnknownDeviceError, "");
287      return;
288    }
289    object_proxy->CallMethodWithErrorCallback(
290        &method_call,
291        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
292        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
293                   weak_ptr_factory_.GetWeakPtr(),
294                   callback),
295        base::Bind(&BluetoothDeviceClientImpl::OnError,
296                   weak_ptr_factory_.GetWeakPtr(),
297                   error_callback));
298  }
299
300  // BluetoothDeviceClient override.
301  virtual void StopConnectionMonitor(
302      const dbus::ObjectPath& object_path,
303      const base::Closure& callback,
304      const ErrorCallback& error_callback) OVERRIDE {
305    dbus::MethodCall method_call(bluetooth_device::kBluetoothDeviceInterface,
306                                 bluetooth_device::kStopConnectionMonitor);
307
308    dbus::ObjectProxy* object_proxy =
309        object_manager_->GetObjectProxy(object_path);
310    if (!object_proxy) {
311      error_callback.Run(kUnknownDeviceError, "");
312      return;
313    }
314    object_proxy->CallMethodWithErrorCallback(
315        &method_call,
316        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
317        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
318                   weak_ptr_factory_.GetWeakPtr(),
319                   callback),
320        base::Bind(&BluetoothDeviceClientImpl::OnError,
321                   weak_ptr_factory_.GetWeakPtr(),
322                   error_callback));
323  }
324
325 protected:
326  virtual void Init(dbus::Bus* bus) OVERRIDE {
327    object_manager_ = bus->GetObjectManager(
328        bluetooth_object_manager::kBluetoothObjectManagerServiceName,
329        dbus::ObjectPath(
330            bluetooth_object_manager::kBluetoothObjectManagerServicePath));
331    object_manager_->RegisterInterface(
332        bluetooth_device::kBluetoothDeviceInterface, this);
333  }
334
335 private:
336  // Called by dbus::ObjectManager when an object with the device interface
337  // is created. Informs observers.
338  virtual void ObjectAdded(const dbus::ObjectPath& object_path,
339                           const std::string& interface_name) OVERRIDE {
340    FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
341                      DeviceAdded(object_path));
342  }
343
344  // Called by dbus::ObjectManager when an object with the device interface
345  // is removed. Informs observers.
346  virtual void ObjectRemoved(const dbus::ObjectPath& object_path,
347                             const std::string& interface_name) OVERRIDE {
348    FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
349                      DeviceRemoved(object_path));
350  }
351
352  // Called by BluetoothPropertySet when a property value is changed,
353  // either by result of a signal or response to a GetAll() or Get()
354  // call. Informs observers.
355  void OnPropertyChanged(const dbus::ObjectPath& object_path,
356                         const std::string& property_name) {
357    FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
358                      DevicePropertyChanged(object_path, property_name));
359  }
360
361  // Called when a response for successful method call is received.
362  void OnSuccess(const base::Closure& callback,
363                 dbus::Response* response) {
364    DCHECK(response);
365    callback.Run();
366  }
367
368  // Called when a response for a failed method call is received.
369  void OnError(const ErrorCallback& error_callback,
370               dbus::ErrorResponse* response) {
371    // Error response has optional error message argument.
372    std::string error_name;
373    std::string error_message;
374    if (response) {
375      dbus::MessageReader reader(response);
376      error_name = response->GetErrorName();
377      reader.PopString(&error_message);
378    } else {
379      error_name = kNoResponseError;
380      error_message = "";
381    }
382    error_callback.Run(error_name, error_message);
383  }
384
385  dbus::ObjectManager* object_manager_;
386
387  // List of observers interested in event notifications from us.
388  ObserverList<BluetoothDeviceClient::Observer> observers_;
389
390  // Weak pointer factory for generating 'this' pointers that might live longer
391  // than we do.
392  // Note: This should remain the last member so it'll be destroyed and
393  // invalidate its weak pointers before any other members are destroyed.
394  base::WeakPtrFactory<BluetoothDeviceClientImpl> weak_ptr_factory_;
395
396  DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceClientImpl);
397};
398
399BluetoothDeviceClient::BluetoothDeviceClient() {
400}
401
402BluetoothDeviceClient::~BluetoothDeviceClient() {
403}
404
405BluetoothDeviceClient* BluetoothDeviceClient::Create() {
406  return new BluetoothDeviceClientImpl();
407}
408
409}  // namespace chromeos
410