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"
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"
15 #include "dbus/message.h"
16 #include "dbus/object_proxy.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
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
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.
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
) {
45 dbus::MessageReader
array_reader(message
);
46 if (!reader
->PopArray(&array_reader
)) {
49 while (array_reader
.HasMoreData()) {
50 dbus::MessageReader
dict_entry_reader(message
);
51 if (!array_reader
.PopDictEntry(&dict_entry_reader
)) {
55 if (!dict_entry_reader
.PopString(&key
)) {
58 dbus::MessageReader
variant_reader(message
);
59 if (!dict_entry_reader
.PopVariant(&variant_reader
)) {
62 const dbus::Message::DataType type
= variant_reader
.GetDataType();
64 case dbus::Message::BYTE
: {
66 if (!variant_reader
.PopByte(&value
)) {
69 dictionary
->SetInteger(key
, value
);
72 case dbus::Message::BOOL
: {
74 if (!variant_reader
.PopBool(&value
)) {
77 dictionary
->SetBoolean(key
, value
);
80 case dbus::Message::INT16
: {
82 if (!variant_reader
.PopInt16(&value
)) {
85 dictionary
->SetInteger(key
, value
);
88 case dbus::Message::UINT16
: {
90 if (!variant_reader
.PopUint16(&value
)) {
93 dictionary
->SetInteger(key
, value
);
96 case dbus::Message::INT32
: {
98 if (!variant_reader
.PopInt32(&value
)) {
101 dictionary
->SetInteger(key
, value
);
104 case dbus::Message::UINT32
: {
106 if (!variant_reader
.PopUint32(&value
)) {
109 dictionary
->SetInteger(key
, value
);
112 case dbus::Message::INT64
: {
114 if (!variant_reader
.PopInt64(&value
)) {
117 dictionary
->SetDouble(key
, value
);
120 case dbus::Message::UINT64
: {
122 if (!variant_reader
.PopUint64(&value
)) {
125 dictionary
->SetDouble(key
, value
);
128 case dbus::Message::DOUBLE
: {
130 if (!variant_reader
.PopDouble(&value
)) {
133 dictionary
->SetDouble(key
, value
);
136 case dbus::Message::STRING
: {
138 if (!variant_reader
.PopString(&value
)) {
141 dictionary
->SetString(key
, value
);
144 case dbus::Message::OBJECT_PATH
: {
146 if (!variant_reader
.PopObjectPath(&value
)) {
149 dictionary
->SetString(key
, value
);
152 case dbus::Message::ARRAY
: {
153 // Not yet supported.
156 case dbus::Message::STRUCT
: {
157 // Not yet supported.
160 case dbus::Message::DICT_ENTRY
: {
161 // Not yet supported.
164 case dbus::Message::VARIANT
: {
165 // Not yet supported.
169 LOG(FATAL
) << "Unknown type: " << type
;
179 // The BluetoothAdapterClient implementation used in production.
180 class BluetoothAdapterClientImpl
: public BluetoothAdapterClient
,
181 private BluetoothManagerClient::Observer
{
183 explicit BluetoothAdapterClientImpl(dbus::Bus
* bus
,
184 BluetoothManagerClient
* manager_client
)
185 : weak_ptr_factory_(this),
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";
200 observers_
.AddObserver(observer
);
203 // BluetoothAdapterClient override.
204 virtual void RemoveObserver(BluetoothAdapterClient::Observer
* observer
) {
205 VLOG(1) << "RemoveObserver";
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(
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(
239 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
240 base::Bind(&BluetoothAdapterClientImpl::OnStopDiscovery
,
241 weak_ptr_factory_
.GetWeakPtr(), object_path
));
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())
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
) {
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();
319 if (property_name
!= bluetooth_adapter::kDiscoveringProperty
) {
320 VLOG(1) << object_path
<< ": PropertyChanged: " << property_name
;
325 bool discovering
= false;
326 if (!reader
.PopVariantOfBool(&discovering
)) {
327 LOG(ERROR
) << object_path
328 << ": PropertyChanged signal has incorrect parameters: "
329 << signal
->ToString();
332 VLOG(1) << object_path
<< ": PropertyChanged: 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
,
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
) {
352 dbus::MessageReader
reader(signal
);
354 if (!reader
.PopString(&address
)) {
355 LOG(ERROR
) << object_path
356 << ": DeviceFound signal has incorrect parameters: "
357 << signal
->ToString();
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();
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
,
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
) {
387 dbus::MessageReader
reader(signal
);
389 if (!reader
.PopString(&address
)) {
390 LOG(ERROR
) << object_path
391 << ": DeviceDisappeared signal has incorrect parameters: "
392 << signal
->ToString();
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
,
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
425 base::WeakPtrFactory
<BluetoothAdapterClientImpl
> weak_ptr_factory_
;
429 // We maintain a collection of dbus object proxies, one for each adapter.
430 typedef std::map
<const std::string
, dbus::ObjectProxy
*> ProxyMap
;
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
441 class BluetoothAdapterClientStubImpl
: public BluetoothAdapterClient
{
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(
472 BluetoothManagerClient
* manager_client
) {
473 if (system::runtime_environment::IsRunningOnChromeOS()) {
474 return new BluetoothAdapterClientImpl(bus
, manager_client
);
476 return new BluetoothAdapterClientStubImpl();
480 } // namespace chromeos