chromeos: bluetooth: tie Proxy lifetime to object, not observer
[chromium-blink-merge.git] / chrome / browser / chromeos / dbus / bluetooth_adapter_client.cc
blob7e4a3a0d2522450375935ed48fe9ce0fa4e13384
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/chromeos/dbus/bluetooth_adapter_client.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "chrome/browser/chromeos/dbus/bluetooth_manager_client.h"
13 #include "chrome/browser/chromeos/system/runtime_environment.h"
14 #include "dbus/bus.h"
15 #include "dbus/message.h"
16 #include "dbus/object_proxy.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
19 namespace {
21 // Utility function to convert an array of dbus dict_entry objects into a
22 // DictionaryValue object.
24 // The dict_entry objects must have keys that are strings and values that are
25 // simple variants.
27 // When converting integral types, we use Integer Value objects to represent
28 // uint8, int16, uint16, int32, and uint32 values and Double Value objects to
29 // represent int64 and uint64 values.
31 // We intend to move this to the chrome dbus library's MessageReader class when
32 // it's more fully baked.
34 // TODO(vlaviano):
35 // - Can we handle integral types better?
36 // - Add support for nested complex types.
37 // - Write an equivalent function to convert in the opposite direction.
38 // - Write unit tests.
39 bool PopArrayOfDictEntries(dbus::MessageReader* reader,
40 dbus::Message* message,
41 DictionaryValue* dictionary) {
42 DCHECK(reader);
43 DCHECK(message);
44 DCHECK(dictionary);
45 dbus::MessageReader array_reader(message);
46 if (!reader->PopArray(&array_reader)) {
47 return false;
49 while (array_reader.HasMoreData()) {
50 dbus::MessageReader dict_entry_reader(message);
51 if (!array_reader.PopDictEntry(&dict_entry_reader)) {
52 return false;
54 std::string key;
55 if (!dict_entry_reader.PopString(&key)) {
56 return false;
58 dbus::MessageReader variant_reader(message);
59 if (!dict_entry_reader.PopVariant(&variant_reader)) {
60 return false;
62 const dbus::Message::DataType type = variant_reader.GetDataType();
63 switch (type) {
64 case dbus::Message::BYTE: {
65 uint8 value = 0;
66 if (!variant_reader.PopByte(&value)) {
67 return false;
69 dictionary->SetInteger(key, value);
70 break;
72 case dbus::Message::BOOL: {
73 bool value = false;
74 if (!variant_reader.PopBool(&value)) {
75 return false;
77 dictionary->SetBoolean(key, value);
78 break;
80 case dbus::Message::INT16: {
81 int16 value = 0;
82 if (!variant_reader.PopInt16(&value)) {
83 return false;
85 dictionary->SetInteger(key, value);
86 break;
88 case dbus::Message::UINT16: {
89 uint16 value = 0;
90 if (!variant_reader.PopUint16(&value)) {
91 return false;
93 dictionary->SetInteger(key, value);
94 break;
96 case dbus::Message::INT32: {
97 int32 value = 0;
98 if (!variant_reader.PopInt32(&value)) {
99 return false;
101 dictionary->SetInteger(key, value);
102 break;
104 case dbus::Message::UINT32: {
105 uint32 value = 0;
106 if (!variant_reader.PopUint32(&value)) {
107 return false;
109 dictionary->SetInteger(key, value);
110 break;
112 case dbus::Message::INT64: {
113 int64 value = 0;
114 if (!variant_reader.PopInt64(&value)) {
115 return false;
117 dictionary->SetDouble(key, value);
118 break;
120 case dbus::Message::UINT64: {
121 uint64 value = 0;
122 if (!variant_reader.PopUint64(&value)) {
123 return false;
125 dictionary->SetDouble(key, value);
126 break;
128 case dbus::Message::DOUBLE: {
129 double value = 0;
130 if (!variant_reader.PopDouble(&value)) {
131 return false;
133 dictionary->SetDouble(key, value);
134 break;
136 case dbus::Message::STRING: {
137 std::string value;
138 if (!variant_reader.PopString(&value)) {
139 return false;
141 dictionary->SetString(key, value);
142 break;
144 case dbus::Message::OBJECT_PATH: {
145 std::string value;
146 if (!variant_reader.PopObjectPath(&value)) {
147 return false;
149 dictionary->SetString(key, value);
150 break;
152 case dbus::Message::ARRAY: {
153 // Not yet supported.
154 return false;
156 case dbus::Message::STRUCT: {
157 // Not yet supported.
158 return false;
160 case dbus::Message::DICT_ENTRY: {
161 // Not yet supported.
162 return false;
164 case dbus::Message::VARIANT: {
165 // Not yet supported.
166 return false;
168 default:
169 LOG(FATAL) << "Unknown type: " << type;
172 return true;
175 } // namespace
177 namespace chromeos {
179 // The BluetoothAdapterClient implementation used in production.
180 class BluetoothAdapterClientImpl: public BluetoothAdapterClient,
181 private BluetoothManagerClient::Observer {
182 public:
183 explicit BluetoothAdapterClientImpl(dbus::Bus* bus,
184 BluetoothManagerClient* manager_client)
185 : weak_ptr_factory_(this),
186 bus_(bus) {
187 VLOG(1) << "Creating BluetoothAdapterClientImpl";
189 DCHECK(manager_client);
190 manager_client->AddObserver(this);
193 virtual ~BluetoothAdapterClientImpl() {
196 // BluetoothAdapterClient override.
197 virtual void AddObserver(BluetoothAdapterClient::Observer* observer) {
198 VLOG(1) << "AddObserver";
199 DCHECK(observer);
200 observers_.AddObserver(observer);
203 // BluetoothAdapterClient override.
204 virtual void RemoveObserver(BluetoothAdapterClient::Observer* observer) {
205 VLOG(1) << "RemoveObserver";
206 DCHECK(observer);
207 observers_.RemoveObserver(observer);
210 // BluetoothAdapterClient override.
211 virtual void StartDiscovery(const std::string& object_path) {
212 VLOG(1) << "StartDiscovery: " << object_path;
214 dbus::MethodCall method_call(
215 bluetooth_adapter::kBluetoothAdapterInterface,
216 bluetooth_adapter::kStartDiscovery);
218 dbus::ObjectProxy* adapter_proxy = GetObjectProxyForPath(object_path);
220 adapter_proxy->CallMethod(
221 &method_call,
222 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
223 base::Bind(&BluetoothAdapterClientImpl::OnStartDiscovery,
224 weak_ptr_factory_.GetWeakPtr(), object_path));
227 // BluetoothAdapterClient override.
228 virtual void StopDiscovery(const std::string& object_path) {
229 VLOG(1) << "StopDiscovery: " << object_path;
231 dbus::MethodCall method_call(
232 bluetooth_adapter::kBluetoothAdapterInterface,
233 bluetooth_adapter::kStopDiscovery);
235 dbus::ObjectProxy* adapter_proxy = GetObjectProxyForPath(object_path);
237 adapter_proxy->CallMethod(
238 &method_call,
239 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
240 base::Bind(&BluetoothAdapterClientImpl::OnStopDiscovery,
241 weak_ptr_factory_.GetWeakPtr(), object_path));
244 private:
245 // BluetoothManagerClient::Observer override.
246 virtual void AdapterAdded(const std::string& object_path) OVERRIDE {
247 VLOG(1) << "AdapterAdded: " << object_path;
250 // BluetoothManagerClient::Observer override.
251 virtual void AdapterRemoved(const std::string& object_path) OVERRIDE {
252 VLOG(1) << "AdapterRemoved: " << object_path;
253 RemoveObjectProxyForPath(object_path);
256 // Ensures that we have a dbus object proxy for an adapter with dbus
257 // object path |object_path|, and if not, creates it and stores it in
258 // our |proxy_map_| map.
259 dbus::ObjectProxy* GetObjectProxyForPath(const std::string& object_path) {
260 VLOG(1) << "GetObjectProxyForPath: " << object_path;
262 ProxyMap::iterator it = proxy_map_.find(object_path);
263 if (it != proxy_map_.end())
264 return it->second;
266 DCHECK(bus_);
267 dbus::ObjectProxy* adapter_proxy = bus_->GetObjectProxy(
268 bluetooth_adapter::kBluetoothAdapterServiceName, object_path);
270 proxy_map_[object_path] = adapter_proxy;
272 adapter_proxy->ConnectToSignal(
273 bluetooth_adapter::kBluetoothAdapterInterface,
274 bluetooth_adapter::kPropertyChangedSignal,
275 base::Bind(&BluetoothAdapterClientImpl::PropertyChangedReceived,
276 weak_ptr_factory_.GetWeakPtr(), object_path),
277 base::Bind(&BluetoothAdapterClientImpl::PropertyChangedConnected,
278 weak_ptr_factory_.GetWeakPtr(), object_path));
280 adapter_proxy->ConnectToSignal(
281 bluetooth_adapter::kBluetoothAdapterInterface,
282 bluetooth_adapter::kDeviceFoundSignal,
283 base::Bind(&BluetoothAdapterClientImpl::DeviceFoundReceived,
284 weak_ptr_factory_.GetWeakPtr(), object_path),
285 base::Bind(&BluetoothAdapterClientImpl::DeviceFoundConnected,
286 weak_ptr_factory_.GetWeakPtr(), object_path));
288 adapter_proxy->ConnectToSignal(
289 bluetooth_adapter::kBluetoothAdapterInterface,
290 bluetooth_adapter::kDeviceDisappearedSignal,
291 base::Bind(&BluetoothAdapterClientImpl::DeviceDisappearedReceived,
292 weak_ptr_factory_.GetWeakPtr(), object_path),
293 base::Bind(&BluetoothAdapterClientImpl::DeviceDisappearedConnected,
294 weak_ptr_factory_.GetWeakPtr(), object_path));
296 return adapter_proxy;
299 // Removes the dbus object proxy for the adapter with dbus object path
300 // |object_path| from our |proxy_map_| map.
301 void RemoveObjectProxyForPath(const std::string& object_path) {
302 VLOG(1) << "RemoveObjectProxyForPath: " << object_path;
303 proxy_map_.erase(object_path);
306 // Called by dbus:: when a PropertyChanged signal is received.
307 void PropertyChangedReceived(const std::string& object_path,
308 dbus::Signal* signal) {
309 DCHECK(signal);
310 dbus::MessageReader reader(signal);
311 std::string property_name;
312 if (!reader.PopString(&property_name)) {
313 LOG(ERROR) << object_path
314 << ": PropertyChanged signal has incorrect parameters: "
315 << signal->ToString();
316 return;
319 if (property_name != bluetooth_adapter::kDiscoveringProperty) {
320 VLOG(1) << object_path << ": PropertyChanged: " << property_name;
321 // We don't care.
322 return;
325 bool discovering = false;
326 if (!reader.PopVariantOfBool(&discovering)) {
327 LOG(ERROR) << object_path
328 << ": PropertyChanged signal has incorrect parameters: "
329 << signal->ToString();
330 return;
332 VLOG(1) << object_path << ": PropertyChanged: Discovering = "
333 << discovering;
335 FOR_EACH_OBSERVER(BluetoothAdapterClient::Observer, observers_,
336 DiscoveringPropertyChanged(object_path, discovering));
339 // Called by dbus:: when the PropertyChanged signal is initially connected.
340 void PropertyChangedConnected(const std::string& object_path,
341 const std::string& interface_name,
342 const std::string& signal_name,
343 bool success) {
344 LOG_IF(WARNING, !success) << object_path
345 << ": Failed to connect to PropertyChanged signal.";
348 // Called by dbus:: when a DeviceFound signal is received.
349 void DeviceFoundReceived(const std::string& object_path,
350 dbus::Signal* signal) {
351 DCHECK(signal);
352 dbus::MessageReader reader(signal);
353 std::string address;
354 if (!reader.PopString(&address)) {
355 LOG(ERROR) << object_path
356 << ": DeviceFound signal has incorrect parameters: "
357 << signal->ToString();
358 return;
360 VLOG(1) << object_path << ": Device found: " << address;
362 DictionaryValue device_properties;
363 if (!PopArrayOfDictEntries(&reader, signal, &device_properties)) {
364 LOG(ERROR) << object_path
365 << ": DeviceFound signal has incorrect parameters: "
366 << signal->ToString();
367 return;
370 FOR_EACH_OBSERVER(BluetoothAdapterClient::Observer, observers_,
371 DeviceFound(object_path, address, device_properties));
374 // Called by dbus:: when the DeviceFound signal is initially connected.
375 void DeviceFoundConnected(const std::string& object_path,
376 const std::string& interface_name,
377 const std::string& signal_name,
378 bool success) {
379 LOG_IF(WARNING, !success) << object_path
380 << ": Failed to connect to DeviceFound signal.";
383 // Called by dbus:: when a DeviceDisappeared signal is received.
384 void DeviceDisappearedReceived(const std::string& object_path,
385 dbus::Signal* signal) {
386 DCHECK(signal);
387 dbus::MessageReader reader(signal);
388 std::string address;
389 if (!reader.PopString(&address)) {
390 LOG(ERROR) << object_path
391 << ": DeviceDisappeared signal has incorrect parameters: "
392 << signal->ToString();
393 return;
395 VLOG(1) << object_path << ": Device disappeared: " << address;
396 FOR_EACH_OBSERVER(BluetoothAdapterClient::Observer, observers_,
397 DeviceDisappeared(object_path, address));
400 // Called by dbus:: when the DeviceDisappeared signal is initially connected.
401 void DeviceDisappearedConnected(const std::string& object_path,
402 const std::string& interface_name,
403 const std::string& signal_name,
404 bool success) {
405 LOG_IF(WARNING, !success) << object_path
406 << ": Failed to connect to DeviceDisappeared signal.";
409 // Called when a response for StartDiscovery() is received.
410 void OnStartDiscovery(const std::string& object_path,
411 dbus::Response* response) {
412 VLOG(1) << "OnStartDiscovery: " << object_path;
413 LOG_IF(WARNING, !response) << object_path << ": OnStartDiscovery: failed.";
416 // Called when a response for StopDiscovery() is received.
417 void OnStopDiscovery(const std::string& object_path,
418 dbus::Response* response) {
419 VLOG(1) << "OnStopDiscovery: " << object_path;
420 LOG_IF(WARNING, !response) << object_path << ": OnStopDiscovery: failed.";
423 // Weak pointer factory for generating 'this' pointers that might live longer
424 // than we do.
425 base::WeakPtrFactory<BluetoothAdapterClientImpl> weak_ptr_factory_;
427 dbus::Bus* bus_;
429 // We maintain a collection of dbus object proxies, one for each adapter.
430 typedef std::map<const std::string, dbus::ObjectProxy*> ProxyMap;
431 ProxyMap proxy_map_;
433 // List of observers interested in event notifications from us.
434 ObserverList<BluetoothAdapterClient::Observer> observers_;
436 DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterClientImpl);
439 // The BluetoothAdapterClient implementation used on Linux desktop, which does
440 // nothing.
441 class BluetoothAdapterClientStubImpl : public BluetoothAdapterClient {
442 public:
443 // BluetoothAdapterClient override.
444 virtual void AddObserver(Observer* observer) {
445 VLOG(1) << "AddObserver";
448 // BluetoothAdapterClient override.
449 virtual void RemoveObserver(Observer* observer) {
450 VLOG(1) << "RemoveObserver";
453 // BluetoothAdapterClient override.
454 virtual void StartDiscovery(const std::string& object_path) {
455 VLOG(1) << "StartDiscovery: " << object_path;
458 // BluetoothAdapterClient override.
459 virtual void StopDiscovery(const std::string& object_path) {
460 VLOG(1) << "StopDiscovery: " << object_path;
464 BluetoothAdapterClient::BluetoothAdapterClient() {
467 BluetoothAdapterClient::~BluetoothAdapterClient() {
470 BluetoothAdapterClient* BluetoothAdapterClient::Create(
471 dbus::Bus* bus,
472 BluetoothManagerClient* manager_client) {
473 if (system::runtime_environment::IsRunningOnChromeOS()) {
474 return new BluetoothAdapterClientImpl(bus, manager_client);
475 } else {
476 return new BluetoothAdapterClientStubImpl();
480 } // namespace chromeos