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}
45
46BluetoothDeviceClient::Properties::~Properties() {
47}
48
49
50// The BluetoothDeviceClient implementation used in production.
51class BluetoothDeviceClientImpl
52    : public BluetoothDeviceClient,
53      public dbus::ObjectManager::Interface {
54 public:
55  BluetoothDeviceClientImpl() : weak_ptr_factory_(this) {}
56
57  virtual ~BluetoothDeviceClientImpl() {
58    object_manager_->UnregisterInterface(
59        bluetooth_device::kBluetoothDeviceInterface);
60  }
61
62  // BluetoothDeviceClient override.
63  virtual void AddObserver(BluetoothDeviceClient::Observer* observer)
64      OVERRIDE {
65    DCHECK(observer);
66    observers_.AddObserver(observer);
67  }
68
69  // BluetoothDeviceClient override.
70  virtual void RemoveObserver(BluetoothDeviceClient::Observer* observer)
71      OVERRIDE {
72    DCHECK(observer);
73    observers_.RemoveObserver(observer);
74  }
75
76  // dbus::ObjectManager::Interface override.
77  virtual dbus::PropertySet* CreateProperties(
78      dbus::ObjectProxy* object_proxy,
79      const dbus::ObjectPath& object_path,
80      const std::string& interface_name) OVERRIDE {
81    Properties* properties = new Properties(
82        object_proxy,
83        interface_name,
84        base::Bind(&BluetoothDeviceClientImpl::OnPropertyChanged,
85                   weak_ptr_factory_.GetWeakPtr(),
86                   object_path));
87    return static_cast<dbus::PropertySet*>(properties);
88  }
89
90  // BluetoothDeviceClient override.
91  virtual std::vector<dbus::ObjectPath> GetDevicesForAdapter(
92      const dbus::ObjectPath& adapter_path) OVERRIDE {
93    std::vector<dbus::ObjectPath> object_paths, device_paths;
94    device_paths = object_manager_->GetObjectsWithInterface(
95        bluetooth_device::kBluetoothDeviceInterface);
96    for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
97         iter != device_paths.end(); ++iter) {
98      Properties* properties = GetProperties(*iter);
99      if (properties->adapter.value() == adapter_path)
100        object_paths.push_back(*iter);
101    }
102    return object_paths;
103  }
104
105  // BluetoothDeviceClient override.
106  virtual Properties* GetProperties(const dbus::ObjectPath& object_path)
107      OVERRIDE {
108    return static_cast<Properties*>(
109        object_manager_->GetProperties(
110            object_path,
111            bluetooth_device::kBluetoothDeviceInterface));
112  }
113
114  // BluetoothDeviceClient override.
115  virtual void Connect(const dbus::ObjectPath& object_path,
116                       const base::Closure& callback,
117                       const ErrorCallback& error_callback) OVERRIDE {
118    dbus::MethodCall method_call(
119        bluetooth_device::kBluetoothDeviceInterface,
120        bluetooth_device::kConnect);
121
122    dbus::ObjectProxy* object_proxy =
123        object_manager_->GetObjectProxy(object_path);
124    if (!object_proxy) {
125      error_callback.Run(kUnknownDeviceError, "");
126      return;
127    }
128
129    // Connect may take an arbitrary length of time, so use no timeout.
130    object_proxy->CallMethodWithErrorCallback(
131        &method_call,
132        dbus::ObjectProxy::TIMEOUT_INFINITE,
133        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
134                   weak_ptr_factory_.GetWeakPtr(), callback),
135        base::Bind(&BluetoothDeviceClientImpl::OnError,
136                   weak_ptr_factory_.GetWeakPtr(), error_callback));
137  }
138
139  // BluetoothDeviceClient override.
140  virtual void Disconnect(const dbus::ObjectPath& object_path,
141                          const base::Closure& callback,
142                          const ErrorCallback& error_callback) OVERRIDE {
143    dbus::MethodCall method_call(
144        bluetooth_device::kBluetoothDeviceInterface,
145        bluetooth_device::kDisconnect);
146
147    dbus::ObjectProxy* object_proxy =
148        object_manager_->GetObjectProxy(object_path);
149    if (!object_proxy) {
150      error_callback.Run(kUnknownDeviceError, "");
151      return;
152    }
153
154    object_proxy->CallMethodWithErrorCallback(
155        &method_call,
156        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
157        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
158                   weak_ptr_factory_.GetWeakPtr(), callback),
159        base::Bind(&BluetoothDeviceClientImpl::OnError,
160                   weak_ptr_factory_.GetWeakPtr(), error_callback));
161  }
162
163  // BluetoothDeviceClient override.
164  virtual void ConnectProfile(const dbus::ObjectPath& object_path,
165                              const std::string& uuid,
166                              const base::Closure& callback,
167                              const ErrorCallback& error_callback) OVERRIDE {
168    dbus::MethodCall method_call(
169        bluetooth_device::kBluetoothDeviceInterface,
170        bluetooth_device::kConnectProfile);
171
172    dbus::MessageWriter writer(&method_call);
173    writer.AppendString(uuid);
174
175    dbus::ObjectProxy* object_proxy =
176        object_manager_->GetObjectProxy(object_path);
177    if (!object_proxy) {
178      error_callback.Run(kUnknownDeviceError, "");
179      return;
180    }
181
182    // Connect may take an arbitrary length of time, so use no timeout.
183    object_proxy->CallMethodWithErrorCallback(
184        &method_call,
185        dbus::ObjectProxy::TIMEOUT_INFINITE,
186        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
187                   weak_ptr_factory_.GetWeakPtr(), callback),
188        base::Bind(&BluetoothDeviceClientImpl::OnError,
189                   weak_ptr_factory_.GetWeakPtr(), error_callback));
190  }
191
192  // BluetoothDeviceClient override.
193  virtual void DisconnectProfile(const dbus::ObjectPath& object_path,
194                                 const std::string& uuid,
195                                 const base::Closure& callback,
196                                 const ErrorCallback& error_callback)
197        OVERRIDE {
198    dbus::MethodCall method_call(
199        bluetooth_device::kBluetoothDeviceInterface,
200        bluetooth_device::kDisconnectProfile);
201
202    dbus::MessageWriter writer(&method_call);
203    writer.AppendString(uuid);
204
205    dbus::ObjectProxy* object_proxy =
206        object_manager_->GetObjectProxy(object_path);
207    if (!object_proxy) {
208      error_callback.Run(kUnknownDeviceError, "");
209      return;
210    }
211
212    object_proxy->CallMethodWithErrorCallback(
213        &method_call,
214        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
215        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
216                   weak_ptr_factory_.GetWeakPtr(), callback),
217        base::Bind(&BluetoothDeviceClientImpl::OnError,
218                   weak_ptr_factory_.GetWeakPtr(), error_callback));
219  }
220
221  // BluetoothDeviceClient override.
222  virtual void Pair(const dbus::ObjectPath& object_path,
223                    const base::Closure& callback,
224                    const ErrorCallback& error_callback) OVERRIDE {
225    dbus::MethodCall method_call(
226        bluetooth_device::kBluetoothDeviceInterface,
227        bluetooth_device::kPair);
228
229    dbus::ObjectProxy* object_proxy =
230        object_manager_->GetObjectProxy(object_path);
231    if (!object_proxy) {
232      error_callback.Run(kUnknownDeviceError, "");
233      return;
234    }
235
236    // Pairing may take an arbitrary length of time, so use no timeout.
237    object_proxy->CallMethodWithErrorCallback(
238        &method_call,
239        dbus::ObjectProxy::TIMEOUT_INFINITE,
240        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
241                   weak_ptr_factory_.GetWeakPtr(), callback),
242        base::Bind(&BluetoothDeviceClientImpl::OnError,
243                   weak_ptr_factory_.GetWeakPtr(), error_callback));
244  }
245
246  // BluetoothDeviceClient override.
247  virtual void CancelPairing(const dbus::ObjectPath& object_path,
248                             const base::Closure& callback,
249                             const ErrorCallback& error_callback)
250        OVERRIDE {
251    dbus::MethodCall method_call(
252        bluetooth_device::kBluetoothDeviceInterface,
253        bluetooth_device::kCancelPairing);
254
255    dbus::ObjectProxy* object_proxy =
256        object_manager_->GetObjectProxy(object_path);
257    if (!object_proxy) {
258      error_callback.Run(kUnknownDeviceError, "");
259      return;
260    }
261    object_proxy->CallMethodWithErrorCallback(
262        &method_call,
263        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
264        base::Bind(&BluetoothDeviceClientImpl::OnSuccess,
265                   weak_ptr_factory_.GetWeakPtr(), callback),
266        base::Bind(&BluetoothDeviceClientImpl::OnError,
267                   weak_ptr_factory_.GetWeakPtr(), error_callback));
268  }
269
270 protected:
271  virtual void Init(dbus::Bus* bus) OVERRIDE {
272    object_manager_ = bus->GetObjectManager(
273        bluetooth_object_manager::kBluetoothObjectManagerServiceName,
274        dbus::ObjectPath(
275            bluetooth_object_manager::kBluetoothObjectManagerServicePath));
276    object_manager_->RegisterInterface(
277        bluetooth_device::kBluetoothDeviceInterface, this);
278  }
279
280 private:
281  // Called by dbus::ObjectManager when an object with the device interface
282  // is created. Informs observers.
283  virtual void ObjectAdded(const dbus::ObjectPath& object_path,
284                           const std::string& interface_name) OVERRIDE {
285    FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
286                      DeviceAdded(object_path));
287  }
288
289  // Called by dbus::ObjectManager when an object with the device interface
290  // is removed. Informs observers.
291  virtual void ObjectRemoved(const dbus::ObjectPath& object_path,
292                             const std::string& interface_name) OVERRIDE {
293    FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
294                      DeviceRemoved(object_path));
295  }
296
297  // Called by BluetoothPropertySet when a property value is changed,
298  // either by result of a signal or response to a GetAll() or Get()
299  // call. Informs observers.
300  void OnPropertyChanged(const dbus::ObjectPath& object_path,
301                         const std::string& property_name) {
302    FOR_EACH_OBSERVER(BluetoothDeviceClient::Observer, observers_,
303                      DevicePropertyChanged(object_path, property_name));
304  }
305
306  // Called when a response for successful method call is received.
307  void OnSuccess(const base::Closure& callback,
308                 dbus::Response* response) {
309    DCHECK(response);
310    callback.Run();
311  }
312
313  // Called when a response for a failed method call is received.
314  void OnError(const ErrorCallback& error_callback,
315               dbus::ErrorResponse* response) {
316    // Error response has optional error message argument.
317    std::string error_name;
318    std::string error_message;
319    if (response) {
320      dbus::MessageReader reader(response);
321      error_name = response->GetErrorName();
322      reader.PopString(&error_message);
323    } else {
324      error_name = kNoResponseError;
325      error_message = "";
326    }
327    error_callback.Run(error_name, error_message);
328  }
329
330  dbus::ObjectManager* object_manager_;
331
332  // List of observers interested in event notifications from us.
333  ObserverList<BluetoothDeviceClient::Observer> observers_;
334
335  // Weak pointer factory for generating 'this' pointers that might live longer
336  // than we do.
337  // Note: This should remain the last member so it'll be destroyed and
338  // invalidate its weak pointers before any other members are destroyed.
339  base::WeakPtrFactory<BluetoothDeviceClientImpl> weak_ptr_factory_;
340
341  DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceClientImpl);
342};
343
344BluetoothDeviceClient::BluetoothDeviceClient() {
345}
346
347BluetoothDeviceClient::~BluetoothDeviceClient() {
348}
349
350BluetoothDeviceClient* BluetoothDeviceClient::Create() {
351  return new BluetoothDeviceClientImpl();
352}
353
354}  // namespace chromeos
355