OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/chromeos/bluetooth/bluetooth_adapter.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/lazy_instance.h" | |
9 #include "base/logging.h" | |
10 #include "base/stl_util.h" | |
11 #include "base/values.h" | |
12 #include "chrome/browser/chromeos/bluetooth/bluetooth_device.h" | |
13 #include "chromeos/dbus/bluetooth_adapter_client.h" | |
14 #include "chromeos/dbus/bluetooth_device_client.h" | |
15 #include "chromeos/dbus/bluetooth_manager_client.h" | |
16 #include "chromeos/dbus/bluetooth_out_of_band_client.h" | |
17 #include "chromeos/dbus/dbus_thread_manager.h" | |
18 #include "dbus/object_path.h" | |
19 | |
20 namespace { | |
21 | |
22 // Shared default adapter instance, we don't want to keep this class around | |
23 // if nobody is using it so use a WeakPtr and create the object when needed; | |
24 // since Google C++ Style (and clang's static analyzer) forbids us having | |
25 // exit-time destructors we use a leaky lazy instance for it. | |
26 base::LazyInstance<base::WeakPtr<chromeos::BluetoothAdapter> >::Leaky | |
27 default_adapter = LAZY_INSTANCE_INITIALIZER; | |
28 | |
29 } // namespace | |
30 | |
31 namespace chromeos { | |
32 | |
33 BluetoothAdapter::BluetoothAdapter() : track_default_(false), | |
34 powered_(false), | |
35 discovering_(false), | |
36 weak_ptr_factory_(this) { | |
37 DBusThreadManager::Get()->GetBluetoothManagerClient()-> | |
38 AddObserver(this); | |
39 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
40 AddObserver(this); | |
41 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | |
42 AddObserver(this); | |
43 } | |
44 | |
45 BluetoothAdapter::~BluetoothAdapter() { | |
46 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | |
47 RemoveObserver(this); | |
48 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
49 RemoveObserver(this); | |
50 DBusThreadManager::Get()->GetBluetoothManagerClient()-> | |
51 RemoveObserver(this); | |
52 | |
53 STLDeleteValues(&devices_); | |
54 } | |
55 | |
56 void BluetoothAdapter::AddObserver(Observer* observer) { | |
57 DCHECK(observer); | |
58 observers_.AddObserver(observer); | |
59 } | |
60 | |
61 void BluetoothAdapter::RemoveObserver(Observer* observer) { | |
62 DCHECK(observer); | |
63 observers_.RemoveObserver(observer); | |
64 } | |
65 | |
66 bool BluetoothAdapter::IsPresent() const { | |
67 return !object_path_.value().empty() && !address_.empty(); | |
68 } | |
69 | |
70 bool BluetoothAdapter::IsPowered() const { | |
71 return powered_; | |
72 } | |
73 | |
74 void BluetoothAdapter::SetPowered(bool powered, | |
75 const base::Closure& callback, | |
76 const ErrorCallback& error_callback) { | |
77 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
78 GetProperties(object_path_)->powered.Set( | |
79 powered, | |
80 base::Bind(&BluetoothAdapter::OnSetPowered, | |
81 weak_ptr_factory_.GetWeakPtr(), | |
82 callback, | |
83 error_callback)); | |
84 } | |
85 | |
86 bool BluetoothAdapter::IsDiscovering() const { | |
87 return discovering_; | |
88 } | |
89 | |
90 void BluetoothAdapter::SetDiscovering(bool discovering, | |
91 const base::Closure& callback, | |
92 const ErrorCallback& error_callback) { | |
93 if (discovering) { | |
94 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
95 StartDiscovery(object_path_, | |
96 base::Bind(&BluetoothAdapter::OnStartDiscovery, | |
97 weak_ptr_factory_.GetWeakPtr(), | |
98 callback, | |
99 error_callback)); | |
100 } else { | |
101 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
102 StopDiscovery(object_path_, | |
103 base::Bind(&BluetoothAdapter::OnStopDiscovery, | |
104 weak_ptr_factory_.GetWeakPtr(), | |
105 callback, | |
106 error_callback)); | |
107 } | |
108 } | |
109 | |
110 BluetoothAdapter::DeviceList BluetoothAdapter::GetDevices() { | |
111 ConstDeviceList const_devices = | |
112 const_cast<const BluetoothAdapter *>(this)->GetDevices(); | |
113 | |
114 DeviceList devices; | |
115 for (ConstDeviceList::const_iterator i = const_devices.begin(); | |
116 i != const_devices.end(); ++i) | |
117 devices.push_back(const_cast<BluetoothDevice *>(*i)); | |
118 | |
119 return devices; | |
120 } | |
121 | |
122 BluetoothAdapter::ConstDeviceList BluetoothAdapter::GetDevices() const { | |
123 ConstDeviceList devices; | |
124 for (DevicesMap::const_iterator iter = devices_.begin(); | |
125 iter != devices_.end(); ++iter) | |
126 devices.push_back(iter->second); | |
127 | |
128 return devices; | |
129 } | |
130 | |
131 BluetoothDevice* BluetoothAdapter::GetDevice(const std::string& address) { | |
132 return const_cast<BluetoothDevice *>( | |
133 const_cast<const BluetoothAdapter *>(this)->GetDevice(address)); | |
134 } | |
135 | |
136 const BluetoothDevice* BluetoothAdapter::GetDevice( | |
137 const std::string& address) const { | |
138 DevicesMap::const_iterator iter = devices_.find(address); | |
139 if (iter != devices_.end()) | |
140 return iter->second; | |
141 | |
142 return NULL; | |
143 } | |
144 | |
145 void BluetoothAdapter::ReadLocalOutOfBandPairingData( | |
146 const BluetoothOutOfBandPairingDataCallback& callback, | |
147 const ErrorCallback& error_callback) { | |
148 DBusThreadManager::Get()->GetBluetoothOutOfBandClient()-> | |
149 ReadLocalData(object_path_, | |
150 base::Bind(&BluetoothAdapter::OnReadLocalData, | |
151 weak_ptr_factory_.GetWeakPtr(), | |
152 callback, | |
153 error_callback)); | |
154 } | |
155 | |
156 void BluetoothAdapter::TrackDefaultAdapter() { | |
157 DVLOG(1) << "Tracking default adapter"; | |
158 track_default_ = true; | |
159 DBusThreadManager::Get()->GetBluetoothManagerClient()-> | |
160 DefaultAdapter(base::Bind(&BluetoothAdapter::AdapterCallback, | |
161 weak_ptr_factory_.GetWeakPtr())); | |
162 } | |
163 | |
164 void BluetoothAdapter::FindAdapter(const std::string& address) { | |
165 DVLOG(1) << "Using adapter " << address; | |
166 track_default_ = false; | |
167 DBusThreadManager::Get()->GetBluetoothManagerClient()-> | |
168 FindAdapter(address, | |
169 base::Bind(&BluetoothAdapter::AdapterCallback, | |
170 weak_ptr_factory_.GetWeakPtr())); | |
171 } | |
172 | |
173 void BluetoothAdapter::AdapterCallback(const dbus::ObjectPath& adapter_path, | |
174 bool success) { | |
175 if (success) { | |
176 ChangeAdapter(adapter_path); | |
177 } else if (!object_path_.value().empty()) { | |
178 RemoveAdapter(); | |
179 } | |
180 } | |
181 | |
182 void BluetoothAdapter::DefaultAdapterChanged( | |
183 const dbus::ObjectPath& adapter_path) { | |
184 if (track_default_) | |
185 ChangeAdapter(adapter_path); | |
186 } | |
187 | |
188 void BluetoothAdapter::AdapterRemoved(const dbus::ObjectPath& adapter_path) { | |
189 if (adapter_path == object_path_) | |
190 RemoveAdapter(); | |
191 } | |
192 | |
193 void BluetoothAdapter::ChangeAdapter(const dbus::ObjectPath& adapter_path) { | |
194 if (object_path_.value().empty()) { | |
195 DVLOG(1) << "Adapter path initialized to " << adapter_path.value(); | |
196 } else if (object_path_.value() != adapter_path.value()) { | |
197 DVLOG(1) << "Adapter path changed from " << object_path_.value() | |
198 << " to " << adapter_path.value(); | |
199 | |
200 RemoveAdapter(); | |
201 } else { | |
202 DVLOG(1) << "Adapter address updated"; | |
203 } | |
204 | |
205 object_path_ = adapter_path; | |
206 | |
207 // Update properties to their new values. | |
208 BluetoothAdapterClient::Properties* properties = | |
209 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
210 GetProperties(object_path_); | |
211 | |
212 address_ = properties->address.value(); | |
213 name_ = properties->name.value(); | |
214 | |
215 // Delay announcing a new adapter until we have an address. | |
216 if (address_.empty()) { | |
217 DVLOG(1) << "Adapter address not yet known"; | |
218 return; | |
219 } | |
220 | |
221 PoweredChanged(properties->powered.value()); | |
222 DiscoveringChanged(properties->discovering.value()); | |
223 DevicesChanged(properties->devices.value()); | |
224 | |
225 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
226 AdapterPresentChanged(this, true)); | |
227 } | |
228 | |
229 void BluetoothAdapter::RemoveAdapter() { | |
230 const bool adapter_was_present = IsPresent(); | |
231 | |
232 DVLOG(1) << "Adapter lost."; | |
233 PoweredChanged(false); | |
234 DiscoveringChanged(false); | |
235 ClearDevices(); | |
236 | |
237 object_path_ = dbus::ObjectPath(""); | |
238 address_.clear(); | |
239 name_.clear(); | |
240 | |
241 if (adapter_was_present) | |
242 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
243 AdapterPresentChanged(this, false)); | |
244 } | |
245 | |
246 void BluetoothAdapter::OnSetPowered(const base::Closure& callback, | |
247 const ErrorCallback& error_callback, | |
248 bool success) { | |
249 if (success) | |
250 callback.Run(); | |
251 else | |
252 error_callback.Run(); | |
253 } | |
254 | |
255 void BluetoothAdapter::PoweredChanged(bool powered) { | |
256 if (powered == powered_) | |
257 return; | |
258 | |
259 powered_ = powered; | |
260 | |
261 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
262 AdapterPoweredChanged(this, powered_)); | |
263 } | |
264 | |
265 void BluetoothAdapter::OnStartDiscovery(const base::Closure& callback, | |
266 const ErrorCallback& error_callback, | |
267 const dbus::ObjectPath& adapter_path, | |
268 bool success) { | |
269 if (success) { | |
270 DVLOG(1) << object_path_.value() << ": started discovery."; | |
271 | |
272 // Clear devices found in previous discovery attempts | |
273 ClearDiscoveredDevices(); | |
274 callback.Run(); | |
275 } else { | |
276 // TODO(keybuk): in future, don't run the callback if the error was just | |
277 // that we were already discovering. | |
278 error_callback.Run(); | |
279 } | |
280 } | |
281 | |
282 void BluetoothAdapter::OnStopDiscovery(const base::Closure& callback, | |
283 const ErrorCallback& error_callback, | |
284 const dbus::ObjectPath& adapter_path, | |
285 bool success) { | |
286 if (success) { | |
287 DVLOG(1) << object_path_.value() << ": stopped discovery."; | |
288 callback.Run(); | |
289 // Leave found devices available for perusing. | |
290 } else { | |
291 // TODO(keybuk): in future, don't run the callback if the error was just | |
292 // that we weren't discovering. | |
293 error_callback.Run(); | |
294 } | |
295 } | |
296 | |
297 void BluetoothAdapter::DiscoveringChanged(bool discovering) { | |
298 if (discovering == discovering_) | |
299 return; | |
300 | |
301 discovering_ = discovering; | |
302 | |
303 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
304 AdapterDiscoveringChanged(this, discovering_)); | |
305 } | |
306 | |
307 void BluetoothAdapter::OnReadLocalData( | |
308 const BluetoothOutOfBandPairingDataCallback& callback, | |
309 const ErrorCallback& error_callback, | |
310 const BluetoothOutOfBandPairingData& data, | |
311 bool success) { | |
312 if (success) | |
313 callback.Run(data); | |
314 else | |
315 error_callback.Run(); | |
316 } | |
317 | |
318 void BluetoothAdapter::AdapterPropertyChanged( | |
319 const dbus::ObjectPath& adapter_path, | |
320 const std::string& property_name) { | |
321 if (adapter_path != object_path_) | |
322 return; | |
323 | |
324 BluetoothAdapterClient::Properties* properties = | |
325 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
326 GetProperties(object_path_); | |
327 | |
328 if (property_name == properties->powered.name()) { | |
329 PoweredChanged(properties->powered.value()); | |
330 | |
331 } else if (property_name == properties->discovering.name()) { | |
332 DiscoveringChanged(properties->discovering.value()); | |
333 | |
334 } else if (property_name == properties->devices.name()) { | |
335 DevicesChanged(properties->devices.value()); | |
336 | |
337 } else if (property_name == properties->address.name()) { | |
338 ChangeAdapter(object_path_); | |
339 | |
340 } else if (property_name == properties->name.name()) { | |
341 name_ = properties->name.value(); | |
342 | |
343 } | |
344 } | |
345 | |
346 void BluetoothAdapter::DevicePropertyChanged( | |
347 const dbus::ObjectPath& device_path, | |
348 const std::string& property_name) { | |
349 UpdateDevice(device_path); | |
350 } | |
351 | |
352 void BluetoothAdapter::UpdateDevice(const dbus::ObjectPath& device_path) { | |
353 BluetoothDeviceClient::Properties* properties = | |
354 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | |
355 GetProperties(device_path); | |
356 | |
357 // When we first see a device, we may not know the address yet and need to | |
358 // wait for the DevicePropertyChanged signal before adding the device. | |
359 const std::string address = properties->address.value(); | |
360 if (address.empty()) | |
361 return; | |
362 | |
363 // The device may be already known to us, either because this is an update | |
364 // to properties, or the device going from discovered to connected and | |
365 // pairing gaining an object path in the process. In any case, we want | |
366 // to update the existing object, not create a new one. | |
367 DevicesMap::iterator iter = devices_.find(address); | |
368 BluetoothDevice* device; | |
369 const bool update_device = (iter != devices_.end()); | |
370 if (update_device) { | |
371 device = iter->second; | |
372 } else { | |
373 device = BluetoothDevice::Create(this); | |
374 devices_[address] = device; | |
375 } | |
376 | |
377 const bool was_paired = device->IsPaired(); | |
378 if (!was_paired) { | |
379 DVLOG(1) << "Assigned object path " << device_path.value() << " to device " | |
380 << address; | |
381 device->SetObjectPath(device_path); | |
382 } | |
383 device->Update(properties, true); | |
384 | |
385 // Don't send a duplicate added event for supported devices that were | |
386 // previously visible or for already paired devices, send a changed | |
387 // event instead. We always send one event or the other since we always | |
388 // inform observers about paired devices whether or not they're supported. | |
389 if (update_device && (device->IsSupported() || was_paired)) { | |
390 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
391 DeviceChanged(this, device)); | |
392 } else { | |
393 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
394 DeviceAdded(this, device)); | |
395 } | |
396 } | |
397 | |
398 void BluetoothAdapter::ClearDevices() { | |
399 DevicesMap replace; | |
400 devices_.swap(replace); | |
401 for (DevicesMap::iterator iter = replace.begin(); | |
402 iter != replace.end(); ++iter) { | |
403 BluetoothDevice* device = iter->second; | |
404 if (device->IsSupported() || device->IsPaired()) | |
405 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
406 DeviceRemoved(this, device)); | |
407 | |
408 delete device; | |
409 } | |
410 } | |
411 | |
412 void BluetoothAdapter::DeviceCreated(const dbus::ObjectPath& adapter_path, | |
413 const dbus::ObjectPath& device_path) { | |
414 if (adapter_path != object_path_) | |
415 return; | |
416 | |
417 UpdateDevice(device_path); | |
418 } | |
419 | |
420 void BluetoothAdapter::DeviceRemoved(const dbus::ObjectPath& adapter_path, | |
421 const dbus::ObjectPath& device_path) { | |
422 if (adapter_path != object_path_) | |
423 return; | |
424 | |
425 DevicesMap::iterator iter = devices_.begin(); | |
426 while (iter != devices_.end()) { | |
427 BluetoothDevice* device = iter->second; | |
428 DevicesMap::iterator temp = iter; | |
429 ++iter; | |
430 | |
431 if (device->object_path_ != device_path) | |
432 continue; | |
433 | |
434 // DeviceRemoved can also be called to indicate a device that is visible | |
435 // during discovery has disconnected, but it is still visible to the | |
436 // adapter, so don't remove in that case and only clear the object path. | |
437 if (!device->IsVisible()) { | |
438 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
439 DeviceRemoved(this, device)); | |
440 | |
441 DVLOG(1) << "Removed device " << device->address(); | |
442 | |
443 delete device; | |
444 devices_.erase(temp); | |
445 } else { | |
446 DVLOG(1) << "Removed object path from device " << device->address(); | |
447 device->RemoveObjectPath(); | |
448 | |
449 // If the device is not supported then we want to act as if it was | |
450 // removed, even though it is still visible to the adapter. | |
451 if (!device->IsSupported()) { | |
452 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
453 DeviceRemoved(this, device)); | |
454 } else { | |
455 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
456 DeviceChanged(this, device)); | |
457 } | |
458 } | |
459 } | |
460 } | |
461 | |
462 void BluetoothAdapter::DevicesChanged( | |
463 const std::vector<dbus::ObjectPath>& devices) { | |
464 for (std::vector<dbus::ObjectPath>::const_iterator iter = | |
465 devices.begin(); iter != devices.end(); ++iter) | |
466 UpdateDevice(*iter); | |
467 } | |
468 | |
469 void BluetoothAdapter::ClearDiscoveredDevices() { | |
470 DevicesMap::iterator iter = devices_.begin(); | |
471 while (iter != devices_.end()) { | |
472 BluetoothDevice* device = iter->second; | |
473 DevicesMap::iterator temp = iter; | |
474 ++iter; | |
475 | |
476 if (!device->IsPaired()) { | |
477 if (device->IsSupported()) | |
478 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
479 DeviceRemoved(this, device)); | |
480 | |
481 delete device; | |
482 devices_.erase(temp); | |
483 } | |
484 } | |
485 } | |
486 | |
487 void BluetoothAdapter::DeviceFound( | |
488 const dbus::ObjectPath& adapter_path, const std::string& address, | |
489 const BluetoothDeviceClient::Properties& properties) { | |
490 if (adapter_path != object_path_) | |
491 return; | |
492 | |
493 // DeviceFound can also be called to indicate that a device we've | |
494 // paired with is now visible to the adapter during discovery, in which | |
495 // case we want to update the existing object, not create a new one. | |
496 BluetoothDevice* device; | |
497 DevicesMap::iterator iter = devices_.find(address); | |
498 const bool update_device = (iter != devices_.end()); | |
499 if (update_device) { | |
500 device = iter->second; | |
501 } else { | |
502 device = BluetoothDevice::Create(this); | |
503 devices_[address] = device; | |
504 } | |
505 | |
506 DVLOG(1) << "Device " << address << " is visible to the adapter"; | |
507 device->SetVisible(true); | |
508 device->Update(&properties, false); | |
509 | |
510 // Don't send a duplicated added event for duplicate signals for supported | |
511 // devices that were previously visible (should never happen) or for already | |
512 // paired devices, send a changed event instead. We do not inform observers | |
513 // if we find or update an unconnected and unsupported device. | |
514 if (update_device && (device->IsSupported() || device->IsPaired())) { | |
515 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
516 DeviceChanged(this, device)); | |
517 } else if (device->IsSupported()) { | |
518 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
519 DeviceAdded(this, device)); | |
520 } | |
521 } | |
522 | |
523 void BluetoothAdapter::DeviceDisappeared(const dbus::ObjectPath& adapter_path, | |
524 const std::string& address) { | |
525 if (adapter_path != object_path_) | |
526 return; | |
527 | |
528 DevicesMap::iterator iter = devices_.find(address); | |
529 if (iter == devices_.end()) | |
530 return; | |
531 | |
532 BluetoothDevice* device = iter->second; | |
533 | |
534 // DeviceDisappeared can also be called to indicate that a device we've | |
535 // paired with is no longer visible to the adapter, so don't remove | |
536 // in that case and only clear the visible flag. | |
537 if (!device->IsPaired()) { | |
538 if (device->IsSupported()) | |
539 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
540 DeviceRemoved(this, device)); | |
541 | |
542 DVLOG(1) << "Discovered device " << device->address() | |
543 << " is no longer visible to the adapter"; | |
544 | |
545 delete device; | |
546 devices_.erase(iter); | |
547 } else { | |
548 DVLOG(1) << "Paired device " << device->address() | |
549 << " is no longer visible to the adapter"; | |
550 device->SetVisible(false); | |
551 | |
552 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
553 DeviceChanged(this, device)); | |
554 } | |
555 } | |
556 | |
557 | |
558 // static | |
559 scoped_refptr<BluetoothAdapter> BluetoothAdapter::DefaultAdapter() { | |
560 if (!default_adapter.Get().get()) { | |
561 BluetoothAdapter* new_adapter = new BluetoothAdapter; | |
562 default_adapter.Get() = new_adapter->weak_ptr_factory_.GetWeakPtr(); | |
563 default_adapter.Get()->TrackDefaultAdapter(); | |
564 } | |
565 | |
566 return scoped_refptr<BluetoothAdapter>(default_adapter.Get()); | |
567 } | |
568 | |
569 // static | |
570 BluetoothAdapter* BluetoothAdapter::Create(const std::string& address) { | |
571 BluetoothAdapter* adapter = new BluetoothAdapter; | |
572 adapter->FindAdapter(address); | |
573 return adapter; | |
574 } | |
575 | |
576 } // namespace chromeos | |
OLD | NEW |