Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(455)

Side by Side Diff: chrome/browser/chromeos/dbus/bluetooth_adapter_client.cc

Issue 8375042: Chrome OS: Add bluetooth dbus clients for device discovery (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address satorux@ review comments Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome/browser/chromeos/dbus/bluetooth_adapter_client.h"
6
7 #include <map>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "chrome/browser/chromeos/system/runtime_environment.h"
13 #include "dbus/bus.h"
14 #include "dbus/message.h"
15 #include "dbus/object_proxy.h"
16 #include "third_party/cros_system_api/dbus/service_constants.h"
17
18 namespace {
19
20 // Utility function to convert an array of dbus dict_entry objects into a
21 // DictionaryValue object.
22 //
23 // The dict_entry objects must have keys that are strings and values that are
24 // simple variants.
25 //
26 // When converting integral types, we use Integer Value objects to represent
27 // uint8, int16, uint16, int32, and uint32 values and Double Value objects to
28 // represent int64 and uint64 values.
29 //
30 // We intend to move this to the chrome dbus library's MessageReader class when
31 // it's more fully baked.
32 //
33 // TODO(vlaviano):
34 // - Can we handle integral types better?
35 // - Add support for nested complex types.
36 // - Write an equivalent function to convert in the opposite direction.
37 // - Write unit tests.
38 bool PopArrayOfDictEntries(dbus::MessageReader* reader,
39 dbus::Message* message,
40 DictionaryValue* dictionary) {
41 DCHECK(reader != NULL);
42 DCHECK(message != NULL);
43 DCHECK(dictionary != NULL);
44 dbus::MessageReader array_reader(message);
45 if (!reader->PopArray(&array_reader)) {
46 return false;
47 }
48 while (array_reader.HasMoreData()) {
49 dbus::MessageReader dict_entry_reader(message);
50 if (!array_reader.PopDictEntry(&dict_entry_reader)) {
51 return false;
52 }
53 std::string key;
54 if (!dict_entry_reader.PopString(&key)) {
55 return false;
56 }
57 dbus::MessageReader variant_reader(message);
58 if (!dict_entry_reader.PopVariant(&variant_reader)) {
59 return false;
60 }
61 const dbus::Message::DataType type = variant_reader.GetDataType();
62 switch (type) {
63 case dbus::Message::BYTE: {
64 uint8 value = 0;
65 if (!variant_reader.PopByte(&value)) {
66 return false;
67 }
68 dictionary->SetInteger(key, value);
69 break;
70 }
71 case dbus::Message::BOOL: {
72 bool value = false;
73 if (!variant_reader.PopBool(&value)) {
74 return false;
75 }
76 dictionary->SetBoolean(key, value);
77 break;
78 }
79 case dbus::Message::INT16: {
80 int16 value = 0;
81 if (!variant_reader.PopInt16(&value)) {
82 return false;
83 }
84 dictionary->SetInteger(key, value);
85 break;
86 }
87 case dbus::Message::UINT16: {
88 uint16 value = 0;
89 if (!variant_reader.PopUint16(&value)) {
90 return false;
91 }
92 dictionary->SetInteger(key, value);
93 break;
94 }
95 case dbus::Message::INT32: {
96 int32 value = 0;
97 if (!variant_reader.PopInt32(&value)) {
98 return false;
99 }
100 dictionary->SetInteger(key, value);
101 break;
102 }
103 case dbus::Message::UINT32: {
104 uint32 value = 0;
105 if (!variant_reader.PopUint32(&value)) {
106 return false;
107 }
108 dictionary->SetInteger(key, value);
109 break;
110 }
111 case dbus::Message::INT64: {
112 int64 value = 0;
113 if (!variant_reader.PopInt64(&value)) {
114 return false;
115 }
116 dictionary->SetDouble(key, value);
117 break;
118 }
119 case dbus::Message::UINT64: {
120 uint64 value = 0;
121 if (!variant_reader.PopUint64(&value)) {
122 return false;
123 }
124 dictionary->SetDouble(key, value);
125 break;
126 }
127 case dbus::Message::DOUBLE: {
128 double value = 0;
129 if (!variant_reader.PopDouble(&value)) {
130 return false;
131 }
132 dictionary->SetDouble(key, value);
133 break;
134 }
135 case dbus::Message::STRING: {
136 std::string value;
137 if (!variant_reader.PopString(&value)) {
138 return false;
139 }
140 dictionary->SetString(key, value);
141 break;
142 }
143 case dbus::Message::OBJECT_PATH: {
144 std::string value;
145 if (!variant_reader.PopObjectPath(&value)) {
146 return false;
147 }
148 dictionary->SetString(key, value);
149 break;
150 }
151 case dbus::Message::ARRAY: {
152 // Not yet supported.
153 return false;
154 }
155 case dbus::Message::STRUCT: {
156 // Not yet supported.
157 return false;
158 }
159 case dbus::Message::DICT_ENTRY: {
160 // Not yet supported.
161 return false;
162 }
163 case dbus::Message::VARIANT: {
164 // Not yet supported.
165 return false;
166 }
167 default:
168 LOG(FATAL) << "Unknown type: " << type;
169 }
170 }
171 return true;
172 }
173
174 } // namespace
175
176 namespace chromeos {
177
178 // The BluetoothAdapterClient implementation used in production.
179 class BluetoothAdapterClientImpl: public BluetoothAdapterClient {
180 public:
181 explicit BluetoothAdapterClientImpl(dbus::Bus* bus)
182 : weak_ptr_factory_(this),
183 bus_(bus) {
184 VLOG(1) << "Creating BluetoothAdapterClientImpl";
185 }
186
187 virtual ~BluetoothAdapterClientImpl() {
188 }
189
190 // BluetoothAdapterClient override.
191 virtual void AddObserver(Observer* observer, const std::string& object_path) {
192 VLOG(1) << "AddObserver: " << object_path;
193 DCHECK(observer != NULL);
satorux1 2011/10/25 19:55:17 I think DCHECK(observer) is more common in Chrome
Vince Laviano 2011/10/25 20:31:42 Done.
194 observers_.AddObserver(observer);
195 AddObjectProxyForPath(object_path);
196 }
197
198 // BluetoothAdapterClient override.
199 virtual void RemoveObserver(Observer* observer,
200 const std::string& object_path) {
201 VLOG(1) << "RemoveObserver: " << object_path;
202 CHECK(observer != NULL);
203 observers_.RemoveObserver(observer);
204 RemoveObjectProxyForPath(object_path);
205 }
206
207 // BluetoothAdapterClient override.
208 virtual void StartDiscovery(const std::string& object_path) {
209 VLOG(1) << "StartDiscovery: " << object_path;
210
211 dbus::MethodCall method_call(
212 bluetooth_adapter::kBluetoothAdapterInterface,
213 bluetooth_adapter::kStartDiscovery);
214
215 ProxyMap::iterator it = proxy_map_.find(object_path);
216 if (it == proxy_map_.end()) {
217 LOG(ERROR) << "Couldn't find proxy for object path " << object_path;
218 return;
219 }
220 dbus::ObjectProxy* adapter_proxy =
221 static_cast<dbus::ObjectProxy*>(it->second);
satorux1 2011/10/25 19:55:17 I think the static cast is unnecessary here.
Vince Laviano 2011/10/25 20:31:42 Done.
222 DCHECK(adapter_proxy != NULL);
satorux1 2011/10/25 19:55:17 This may sound like an overuse of DCHECK(), but it
Vince Laviano 2011/10/25 20:31:42 Done.
223
224 adapter_proxy->CallMethod(
225 &method_call,
226 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
227 base::Bind(&BluetoothAdapterClientImpl::OnStartDiscovery,
228 weak_ptr_factory_.GetWeakPtr(), object_path));
229 }
230
231 // BluetoothAdapterClient override.
232 virtual void StopDiscovery(const std::string& object_path) {
233 VLOG(1) << "StopDiscovery: " << object_path;
234
235 dbus::MethodCall method_call(
236 bluetooth_adapter::kBluetoothAdapterInterface,
237 bluetooth_adapter::kStopDiscovery);
238
239 ProxyMap::iterator it = proxy_map_.find(object_path);
240 if (it == proxy_map_.end()) {
241 LOG(ERROR) << "Couldn't find proxy for object path " << object_path;
242 return;
243 }
244 dbus::ObjectProxy* adapter_proxy =
245 static_cast<dbus::ObjectProxy*>(it->second);
satorux1 2011/10/25 19:55:17 ditto.
Vince Laviano 2011/10/25 20:31:42 Done.
246 DCHECK(adapter_proxy != NULL);
247
248 adapter_proxy->CallMethod(
249 &method_call,
250 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
251 base::Bind(&BluetoothAdapterClientImpl::OnStopDiscovery,
252 weak_ptr_factory_.GetWeakPtr(), object_path));
253 }
254
255 private:
256 // Gets a dbus object proxy for an adapter with dbus object path |object_path|
257 // and stores it in our |proxy_map_| map.
258 void AddObjectProxyForPath(const std::string& object_path) {
259 VLOG(1) << "AddObjectProxyForPath: " << object_path;
260
261 DCHECK(bus_ != NULL);
262 dbus::ObjectProxy* adapter_proxy = bus_->GetObjectProxy(
263 bluetooth_adapter::kBluetoothAdapterServiceName, object_path);
264 DCHECK(adapter_proxy != NULL);
satorux1 2011/10/25 19:55:17 we don't need this. GetObjectProxy guarantees not
Vince Laviano 2011/10/25 20:31:42 Done.
265
266 proxy_map_[object_path] = adapter_proxy;
267
268 adapter_proxy->ConnectToSignal(
269 bluetooth_adapter::kBluetoothAdapterInterface,
270 bluetooth_adapter::kPropertyChangedSignal,
271 base::Bind(&BluetoothAdapterClientImpl::PropertyChangedReceived,
272 weak_ptr_factory_.GetWeakPtr(), object_path),
273 base::Bind(&BluetoothAdapterClientImpl::PropertyChangedConnected,
274 weak_ptr_factory_.GetWeakPtr(), object_path));
275
276 adapter_proxy->ConnectToSignal(
277 bluetooth_adapter::kBluetoothAdapterInterface,
278 bluetooth_adapter::kDeviceFoundSignal,
279 base::Bind(&BluetoothAdapterClientImpl::DeviceFoundReceived,
280 weak_ptr_factory_.GetWeakPtr(), object_path),
281 base::Bind(&BluetoothAdapterClientImpl::DeviceFoundConnected,
282 weak_ptr_factory_.GetWeakPtr(), object_path));
283
284 adapter_proxy->ConnectToSignal(
285 bluetooth_adapter::kBluetoothAdapterInterface,
286 bluetooth_adapter::kDeviceDisappearedSignal,
287 base::Bind(&BluetoothAdapterClientImpl::DeviceDisappearedReceived,
288 weak_ptr_factory_.GetWeakPtr(), object_path),
289 base::Bind(&BluetoothAdapterClientImpl::DeviceDisappearedConnected,
290 weak_ptr_factory_.GetWeakPtr(), object_path));
291 }
292
293 // Removes the dbus object proxy for the adapter with dbus object path
294 // |object_path| from our |proxy_map_| map.
295 void RemoveObjectProxyForPath(const std::string& object_path) {
296 VLOG(1) << "RemoveObjectProxyForPath: " << object_path;
297 proxy_map_.erase(object_path);
298 }
299
300 // Called by dbus:: when a PropertyChanged signal is received.
301 void PropertyChangedReceived(const std::string& object_path,
302 dbus::Signal* signal) {
303 DCHECK(signal != NULL);
304 dbus::MessageReader reader(signal);
305 std::string property_name;
306 if (!reader.PopString(&property_name)) {
307 LOG(ERROR) << object_path
308 << ": PropertyChanged signal has incorrect parameters: "
309 << signal->ToString();
310 return;
311 }
312
313 if (property_name != bluetooth_adapter::kDiscoveringProperty) {
314 VLOG(1) << object_path << ": PropertyChanged: " << property_name;
315 // We don't care.
316 return;
317 }
318
319 bool discovering = false;
320 if (!reader.PopVariantOfBool(&discovering)) {
321 LOG(ERROR) << object_path
322 << ": PropertyChanged signal has incorrect parameters: "
323 << signal->ToString();
324 return;
325 }
326 VLOG(1) << object_path << ": PropertyChanged: Discovering = "
327 << discovering;
328
329 FOR_EACH_OBSERVER(Observer, observers_,
330 DiscoveringPropertyChanged(object_path, discovering));
331 }
332
333 // Called by dbus:: when the PropertyChanged signal is initially connected.
334 void PropertyChangedConnected(const std::string& object_path,
335 const std::string& interface_name,
336 const std::string& signal_name,
337 bool success) {
338 LOG_IF(WARNING, !success) << object_path
339 << ": Failed to connect to PropertyChanged signal.";
340 }
341
342 // Called by dbus:: when a DeviceFound signal is received.
343 void DeviceFoundReceived(const std::string& object_path,
344 dbus::Signal* signal) {
345 DCHECK(signal != NULL);
346 dbus::MessageReader reader(signal);
347 std::string address;
348 if (!reader.PopString(&address)) {
349 LOG(ERROR) << object_path
350 << ": DeviceFound signal has incorrect parameters: "
351 << signal->ToString();
352 return;
353 }
354 VLOG(1) << object_path << ": Device found: " << address;
355
356 DictionaryValue device_properties;
357 if (!PopArrayOfDictEntries(&reader, signal, &device_properties)) {
358 LOG(ERROR) << object_path
359 << ": DeviceFound signal has incorrect parameters: "
360 << signal->ToString();
361 return;
362 }
363
364 FOR_EACH_OBSERVER(Observer, observers_, DeviceFound(object_path, address,
365 device_properties));
366 }
367
368 // Called by dbus:: when the DeviceFound signal is initially connected.
369 void DeviceFoundConnected(const std::string& object_path,
370 const std::string& interface_name,
371 const std::string& signal_name,
372 bool success) {
373 LOG_IF(WARNING, !success) << object_path
374 << ": Failed to connect to DeviceFound signal.";
375 }
376
377 // Called by dbus:: when a DeviceDisappeared signal is received.
378 void DeviceDisappearedReceived(const std::string& object_path,
379 dbus::Signal* signal) {
380 DCHECK(signal != NULL);
381 dbus::MessageReader reader(signal);
382 std::string address;
383 if (!reader.PopString(&address)) {
384 LOG(ERROR) << object_path
385 << ": DeviceDisappeared signal has incorrect parameters: "
386 << signal->ToString();
387 return;
388 }
389 VLOG(1) << object_path << ": Device disappeared: " << address;
390 FOR_EACH_OBSERVER(Observer, observers_, DeviceDisappeared(object_path,
391 address));
392 }
393
394 // Called by dbus:: when the DeviceDisappeared signal is initially connected.
395 void DeviceDisappearedConnected(const std::string& object_path,
396 const std::string& interface_name,
397 const std::string& signal_name,
398 bool success) {
399 LOG_IF(WARNING, !success) << object_path
400 << ": Failed to connect to DeviceDisappeared signal.";
401 }
402
403 // Called when a response for StartDiscovery() is received.
404 void OnStartDiscovery(const std::string& object_path,
405 dbus::Response* response) {
406 VLOG(1) << "OnStartDiscovery: " << object_path;
407 DCHECK(response != NULL);
satorux1 2011/10/25 19:55:17 LOG_IF(WARNING, response) << ... would be nicer.
Vince Laviano 2011/10/25 20:31:42 Done.
408 }
409
410 // Called when a response for StopDiscovery() is received.
411 void OnStopDiscovery(const std::string& object_path,
412 dbus::Response* response) {
413 VLOG(1) << "OnStopDiscovery: " << object_path;
414 DCHECK(response != NULL);
satorux1 2011/10/25 19:55:17 ditto.
Vince Laviano 2011/10/25 20:31:42 Done.
415 }
416
417 // Weak pointer factory for generating 'this' pointers that might live longer
418 // than we do.
419 base::WeakPtrFactory<BluetoothAdapterClientImpl> weak_ptr_factory_;
420
421 dbus::Bus* bus_;
422
423 // We maintain a collection of dbus object proxies, one for each adapter.
424 typedef std::map<const std::string, dbus::ObjectProxy*> ProxyMap;
425 ProxyMap proxy_map_;
426
427 // List of observers interested in event notifications from us.
428 ObserverList<Observer> observers_;
429
430 DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterClientImpl);
431 };
432
433 // The BluetoothAdapterClient implementation used on Linux desktop, which does
434 // nothing.
435 class BluetoothAdapterClientStubImpl : public BluetoothAdapterClient {
436 public:
437 // BluetoothAdapterClient override.
438 virtual void AddObserver(Observer* observer, const std::string& object_path) {
439 VLOG(1) << "AddObserver: " << object_path;
440 }
441
442 // BluetoothAdapterClient override.
443 virtual void RemoveObserver(Observer* observer,
444 const std::string& object_path) {
445 VLOG(1) << "RemoveObserver: " << object_path;
446 }
447
448 // BluetoothAdapterClient override.
449 virtual void StartDiscovery(const std::string& object_path) {
450 VLOG(1) << "StartDiscovery: " << object_path;
451 }
452
453 // BluetoothAdapterClient override.
454 virtual void StopDiscovery(const std::string& object_path) {
455 VLOG(1) << "StopDiscovery: " << object_path;
456 }
457 };
458
459 BluetoothAdapterClient::BluetoothAdapterClient() {
460 }
461
462 BluetoothAdapterClient::~BluetoothAdapterClient() {
463 }
464
465 BluetoothAdapterClient* BluetoothAdapterClient::Create(dbus::Bus* bus) {
466 if (system::runtime_environment::IsRunningOnChromeOS()) {
467 return new BluetoothAdapterClientImpl(bus);
468 } else {
469 return new BluetoothAdapterClientStubImpl();
470 }
471 }
472
473 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698