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 "device/bluetooth/bluetooth_adapter_chromeos.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/logging.h" | |
11 #include "base/stl_util.h" | |
12 #include "base/values.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 #include "device/bluetooth/bluetooth_device_chromeos.h" | |
20 #include "device/bluetooth/bluetooth_out_of_band_pairing_data.h" | |
21 | |
22 using device::BluetoothAdapter; | |
23 using device::BluetoothDevice; | |
24 using device::BluetoothOutOfBandPairingData; | |
25 | |
26 namespace chromeos { | |
27 | |
28 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS() : BluetoothAdapter(), | |
29 powered_(false), | |
30 discovering_(false), | |
31 discovering_count_(0), | |
32 weak_ptr_factory_(this) { | |
33 DBusThreadManager::Get()->GetBluetoothManagerClient()-> | |
34 AddObserver(this); | |
35 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
36 AddObserver(this); | |
37 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | |
38 AddObserver(this); | |
39 | |
40 DBusThreadManager::Get()->GetBluetoothManagerClient()-> | |
41 DefaultAdapter(base::Bind(&BluetoothAdapterChromeOS::AdapterCallback, | |
42 weak_ptr_factory_.GetWeakPtr())); | |
43 } | |
44 | |
45 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() { | |
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 BluetoothAdapterChromeOS::AddObserver( | |
57 BluetoothAdapter::Observer* observer) { | |
58 DCHECK(observer); | |
59 observers_.AddObserver(observer); | |
60 } | |
61 | |
62 void BluetoothAdapterChromeOS::RemoveObserver( | |
63 BluetoothAdapter::Observer* observer) { | |
64 DCHECK(observer); | |
65 observers_.RemoveObserver(observer); | |
66 } | |
67 | |
68 std::string BluetoothAdapterChromeOS::GetAddress() const { | |
69 return address_; | |
70 } | |
71 | |
72 std::string BluetoothAdapterChromeOS::GetName() const { | |
73 return name_; | |
74 } | |
75 | |
76 // TODO(youngki) Return true when object path and properties of the adapter are | |
77 // initialized. | |
78 bool BluetoothAdapterChromeOS::IsInitialized() const { | |
79 return true; | |
80 } | |
81 | |
82 bool BluetoothAdapterChromeOS::IsPresent() const { | |
83 return !object_path_.value().empty() && !address_.empty(); | |
84 } | |
85 | |
86 bool BluetoothAdapterChromeOS::IsPowered() const { | |
87 return powered_; | |
88 } | |
89 | |
90 void BluetoothAdapterChromeOS::SetPowered(bool powered, | |
91 const base::Closure& callback, | |
92 const ErrorCallback& error_callback) { | |
93 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
94 GetProperties(object_path_)->powered.Set( | |
95 powered, | |
96 base::Bind(&BluetoothAdapterChromeOS::OnSetPowered, | |
97 weak_ptr_factory_.GetWeakPtr(), | |
98 callback, | |
99 error_callback)); | |
100 } | |
101 | |
102 bool BluetoothAdapterChromeOS::IsDiscovering() const { | |
103 return discovering_; | |
104 } | |
105 | |
106 void BluetoothAdapterChromeOS::StartDiscovering( | |
107 const base::Closure& callback, | |
108 const ErrorCallback& error_callback) { | |
109 // BlueZ counts discovery sessions, and permits multiple sessions for a | |
110 // single connection, so issue a StartDiscovery() call for every use | |
111 // within Chromium for the right behavior. | |
112 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
113 StartDiscovery(object_path_, | |
114 base::Bind( | |
115 &BluetoothAdapterChromeOS::OnStartDiscovery, | |
116 weak_ptr_factory_.GetWeakPtr(), | |
117 callback, error_callback)); | |
118 } | |
119 | |
120 void BluetoothAdapterChromeOS::StopDiscovering( | |
121 const base::Closure& callback, | |
122 const ErrorCallback& error_callback) { | |
123 // Inform BlueZ to stop one of our open discovery sessions. | |
124 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
125 StopDiscovery(object_path_, | |
126 base::Bind( | |
127 &BluetoothAdapterChromeOS::OnStopDiscovery, | |
128 weak_ptr_factory_.GetWeakPtr(), | |
129 callback, error_callback)); | |
130 } | |
131 | |
132 void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData( | |
133 const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback, | |
134 const ErrorCallback& error_callback) { | |
135 DBusThreadManager::Get()->GetBluetoothOutOfBandClient()-> | |
136 ReadLocalData(object_path_, | |
137 base::Bind(&BluetoothAdapterChromeOS::OnReadLocalData, | |
138 weak_ptr_factory_.GetWeakPtr(), | |
139 callback, | |
140 error_callback)); | |
141 } | |
142 | |
143 void BluetoothAdapterChromeOS::AdapterCallback( | |
144 const dbus::ObjectPath& adapter_path, | |
145 bool success) { | |
146 if (success) { | |
147 ChangeAdapter(adapter_path); | |
148 } else if (!object_path_.value().empty()) { | |
149 RemoveAdapter(); | |
150 } | |
151 } | |
152 | |
153 void BluetoothAdapterChromeOS::DefaultAdapterChanged( | |
154 const dbus::ObjectPath& adapter_path) { | |
155 ChangeAdapter(adapter_path); | |
156 } | |
157 | |
158 void BluetoothAdapterChromeOS::AdapterRemoved( | |
159 const dbus::ObjectPath& adapter_path) { | |
160 if (adapter_path == object_path_) | |
161 RemoveAdapter(); | |
162 } | |
163 | |
164 void BluetoothAdapterChromeOS::ChangeAdapter( | |
165 const dbus::ObjectPath& adapter_path) { | |
166 if (object_path_.value().empty()) { | |
167 VLOG(1) << "Adapter path initialized to " << adapter_path.value(); | |
168 } else if (object_path_.value() != adapter_path.value()) { | |
169 VLOG(1) << "Adapter path changed from " << object_path_.value() | |
170 << " to " << adapter_path.value(); | |
171 | |
172 RemoveAdapter(); | |
173 } else { | |
174 VLOG(1) << "Adapter address updated"; | |
175 } | |
176 | |
177 object_path_ = adapter_path; | |
178 | |
179 // Update properties to their new values. | |
180 BluetoothAdapterClient::Properties* properties = | |
181 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
182 GetProperties(object_path_); | |
183 | |
184 address_ = properties->address.value(); | |
185 name_ = properties->name.value(); | |
186 | |
187 // Delay announcing a new adapter until we have an address. | |
188 if (address_.empty()) { | |
189 VLOG(1) << "Adapter address not yet known"; | |
190 return; | |
191 } | |
192 | |
193 PoweredChanged(properties->powered.value()); | |
194 DiscoveringChanged(properties->discovering.value()); | |
195 DevicesChanged(properties->devices.value()); | |
196 | |
197 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
198 AdapterPresentChanged(this, true)); | |
199 } | |
200 | |
201 void BluetoothAdapterChromeOS::RemoveAdapter() { | |
202 const bool adapter_was_present = IsPresent(); | |
203 | |
204 VLOG(1) << "Adapter lost."; | |
205 PoweredChanged(false); | |
206 DiscoveringChanged(false); | |
207 ClearDevices(); | |
208 | |
209 object_path_ = dbus::ObjectPath(""); | |
210 address_.clear(); | |
211 name_.clear(); | |
212 | |
213 if (adapter_was_present) | |
214 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
215 AdapterPresentChanged(this, false)); | |
216 } | |
217 | |
218 void BluetoothAdapterChromeOS::OnSetPowered(const base::Closure& callback, | |
219 const ErrorCallback& error_callback, | |
220 bool success) { | |
221 if (success) | |
222 callback.Run(); | |
223 else | |
224 error_callback.Run(); | |
225 } | |
226 | |
227 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) { | |
228 if (powered == powered_) | |
229 return; | |
230 | |
231 powered_ = powered; | |
232 | |
233 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
234 AdapterPoweredChanged(this, powered_)); | |
235 } | |
236 | |
237 void BluetoothAdapterChromeOS::NotifyDeviceChanged( | |
238 BluetoothDeviceChromeOS* device) { | |
239 DCHECK(device->adapter_ == this); | |
240 | |
241 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
242 DeviceChanged(this, device)); | |
243 } | |
244 | |
245 void BluetoothAdapterChromeOS::OnStartDiscovery( | |
246 const base::Closure& callback, | |
247 const ErrorCallback& error_callback, | |
248 const dbus::ObjectPath& adapter_path, | |
249 bool success) { | |
250 if (success) { | |
251 if (discovering_count_++ == 0) { | |
252 VLOG(1) << object_path_.value() << ": started discovery."; | |
253 | |
254 // Clear devices found in previous discovery attempts | |
255 ClearDiscoveredDevices(); | |
256 } | |
257 | |
258 callback.Run(); | |
259 } else { | |
260 error_callback.Run(); | |
261 } | |
262 } | |
263 | |
264 void BluetoothAdapterChromeOS::OnStopDiscovery( | |
265 const base::Closure& callback, | |
266 const ErrorCallback& error_callback, | |
267 const dbus::ObjectPath& adapter_path, | |
268 bool success) { | |
269 if (success) { | |
270 if (--discovering_count_ == 0) { | |
271 VLOG(1) << object_path_.value() << ": stopped discovery."; | |
272 } else if (discovering_count_ < 0) { | |
273 LOG(WARNING) << adapter_path.value() << ": call to StopDiscovering " | |
274 << "without matching StartDiscovering."; | |
275 error_callback.Run(); | |
276 return; | |
277 } | |
278 | |
279 callback.Run(); | |
280 | |
281 // Leave found devices available for perusing. | |
282 } else { | |
283 error_callback.Run(); | |
284 } | |
285 } | |
286 | |
287 void BluetoothAdapterChromeOS::DiscoveringChanged(bool discovering) { | |
288 if (discovering == discovering_) | |
289 return; | |
290 | |
291 discovering_ = discovering; | |
292 | |
293 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
294 AdapterDiscoveringChanged(this, discovering_)); | |
295 } | |
296 | |
297 void BluetoothAdapterChromeOS::OnReadLocalData( | |
298 const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback, | |
299 const ErrorCallback& error_callback, | |
300 const BluetoothOutOfBandPairingData& data, | |
301 bool success) { | |
302 if (success) | |
303 callback.Run(data); | |
304 else | |
305 error_callback.Run(); | |
306 } | |
307 | |
308 void BluetoothAdapterChromeOS::AdapterPropertyChanged( | |
309 const dbus::ObjectPath& adapter_path, | |
310 const std::string& property_name) { | |
311 if (adapter_path != object_path_) | |
312 return; | |
313 | |
314 BluetoothAdapterClient::Properties* properties = | |
315 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
316 GetProperties(object_path_); | |
317 | |
318 if (property_name == properties->address.name()) { | |
319 ChangeAdapter(object_path_); | |
320 | |
321 } else if (!address_.empty()) { | |
322 if (property_name == properties->powered.name()) { | |
323 PoweredChanged(properties->powered.value()); | |
324 | |
325 } else if (property_name == properties->discovering.name()) { | |
326 DiscoveringChanged(properties->discovering.value()); | |
327 | |
328 } else if (property_name == properties->devices.name()) { | |
329 DevicesChanged(properties->devices.value()); | |
330 | |
331 } else if (property_name == properties->name.name()) { | |
332 name_ = properties->name.value(); | |
333 | |
334 } | |
335 } | |
336 } | |
337 | |
338 void BluetoothAdapterChromeOS::DevicePropertyChanged( | |
339 const dbus::ObjectPath& device_path, | |
340 const std::string& property_name) { | |
341 UpdateDevice(device_path); | |
342 } | |
343 | |
344 void BluetoothAdapterChromeOS::UpdateDevice( | |
345 const dbus::ObjectPath& device_path) { | |
346 BluetoothDeviceClient::Properties* properties = | |
347 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | |
348 GetProperties(device_path); | |
349 | |
350 // When we first see a device, we may not know the address yet and need to | |
351 // wait for the DevicePropertyChanged signal before adding the device. | |
352 const std::string address = properties->address.value(); | |
353 if (address.empty()) | |
354 return; | |
355 | |
356 // The device may be already known to us, either because this is an update | |
357 // to properties, or the device going from discovered to connected and | |
358 // pairing gaining an object path in the process. In any case, we want | |
359 // to update the existing object, not create a new one. | |
360 DevicesMap::iterator iter = devices_.find(address); | |
361 BluetoothDeviceChromeOS* device; | |
362 const bool update_device = (iter != devices_.end()); | |
363 if (update_device) { | |
364 device = static_cast<BluetoothDeviceChromeOS*>(iter->second); | |
365 } else { | |
366 device = BluetoothDeviceChromeOS::Create(this); | |
367 devices_[address] = device; | |
368 } | |
369 | |
370 if (!device->HasObjectPath()) { | |
371 VLOG(1) << "Assigned object path " << device_path.value() << " to device " | |
372 << address; | |
373 device->SetObjectPath(device_path); | |
374 } | |
375 device->Update(properties, true); | |
376 | |
377 if (update_device) | |
378 NotifyDeviceChanged(device); | |
379 else { | |
380 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
381 DeviceAdded(this, device)); | |
382 } | |
383 } | |
384 | |
385 void BluetoothAdapterChromeOS::ClearDevices() { | |
386 DevicesMap replace; | |
387 devices_.swap(replace); | |
388 for (DevicesMap::iterator iter = replace.begin(); | |
389 iter != replace.end(); ++iter) { | |
390 BluetoothDevice* device = iter->second; | |
391 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
392 DeviceRemoved(this, device)); | |
393 | |
394 delete device; | |
395 } | |
396 } | |
397 | |
398 void BluetoothAdapterChromeOS::DeviceCreated( | |
399 const dbus::ObjectPath& adapter_path, | |
400 const dbus::ObjectPath& device_path) { | |
401 if (adapter_path != object_path_) | |
402 return; | |
403 | |
404 UpdateDevice(device_path); | |
405 } | |
406 | |
407 void BluetoothAdapterChromeOS::DeviceRemoved( | |
408 const dbus::ObjectPath& adapter_path, | |
409 const dbus::ObjectPath& device_path) { | |
410 if (adapter_path != object_path_) | |
411 return; | |
412 | |
413 DevicesMap::iterator iter = devices_.begin(); | |
414 while (iter != devices_.end()) { | |
415 BluetoothDeviceChromeOS* device = | |
416 static_cast<BluetoothDeviceChromeOS*>(iter->second); | |
417 DevicesMap::iterator temp = iter; | |
418 ++iter; | |
419 | |
420 if (device->object_path_ != device_path) | |
421 continue; | |
422 | |
423 // DeviceRemoved can also be called to indicate a device that is visible | |
424 // during discovery has disconnected, but it is still visible to the | |
425 // adapter, so don't remove in that case and only clear the object path. | |
426 if (!device->WasDiscovered()) { | |
427 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
428 DeviceRemoved(this, device)); | |
429 | |
430 VLOG(1) << "Removed device " << device->GetAddress(); | |
431 | |
432 delete device; | |
433 devices_.erase(temp); | |
434 } else { | |
435 VLOG(1) << "Removed object path from device " << device->GetAddress(); | |
436 device->RemoveObjectPath(); | |
437 | |
438 NotifyDeviceChanged(device); | |
439 } | |
440 } | |
441 } | |
442 | |
443 void BluetoothAdapterChromeOS::DevicesChanged( | |
444 const std::vector<dbus::ObjectPath>& devices) { | |
445 for (std::vector<dbus::ObjectPath>::const_iterator iter = | |
446 devices.begin(); iter != devices.end(); ++iter) | |
447 UpdateDevice(*iter); | |
448 } | |
449 | |
450 void BluetoothAdapterChromeOS::ClearDiscoveredDevices() { | |
451 DevicesMap::iterator iter = devices_.begin(); | |
452 while (iter != devices_.end()) { | |
453 BluetoothDeviceChromeOS* device = | |
454 static_cast<BluetoothDeviceChromeOS*>(iter->second); | |
455 DevicesMap::iterator temp = iter; | |
456 ++iter; | |
457 | |
458 if (!device->HasObjectPath()) { | |
459 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
460 DeviceRemoved(this, device)); | |
461 | |
462 delete device; | |
463 devices_.erase(temp); | |
464 | |
465 } else | |
466 device->SetDiscovered(false); | |
467 } | |
468 } | |
469 | |
470 void BluetoothAdapterChromeOS::DeviceFound( | |
471 const dbus::ObjectPath& adapter_path, | |
472 const std::string& address, | |
473 const BluetoothDeviceClient::Properties& properties) { | |
474 if (adapter_path != object_path_) | |
475 return; | |
476 | |
477 // DeviceFound can also be called to indicate that a device we've | |
478 // paired with is now visible to the adapter during discovery, in which | |
479 // case we want to update the existing object, not create a new one. | |
480 BluetoothDeviceChromeOS* device; | |
481 DevicesMap::iterator iter = devices_.find(address); | |
482 const bool update_device = (iter != devices_.end()); | |
483 if (update_device) { | |
484 device = static_cast<BluetoothDeviceChromeOS*>(iter->second); | |
485 } else { | |
486 device = BluetoothDeviceChromeOS::Create(this); | |
487 devices_[address] = device; | |
488 } | |
489 | |
490 VLOG(1) << "Device " << address << " is visible to the adapter"; | |
491 device->SetDiscovered(true); | |
492 device->Update(&properties, false); | |
493 | |
494 if (update_device) | |
495 NotifyDeviceChanged(device); | |
496 else { | |
497 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
498 DeviceAdded(this, device)); | |
499 } | |
500 } | |
501 | |
502 void BluetoothAdapterChromeOS::DeviceDisappeared( | |
503 const dbus::ObjectPath& adapter_path, | |
504 const std::string& address) { | |
505 if (adapter_path != object_path_) | |
506 return; | |
507 | |
508 DevicesMap::iterator iter = devices_.find(address); | |
509 if (iter == devices_.end()) | |
510 return; | |
511 | |
512 BluetoothDeviceChromeOS* device = | |
513 static_cast<BluetoothDeviceChromeOS*>(iter->second); | |
514 | |
515 // DeviceDisappeared can also be called to indicate that a device we've | |
516 // paired with is no longer visible to the adapter, so don't remove | |
517 // in that case and only clear the visible flag. | |
518 if (!device->HasObjectPath()) { | |
519 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
520 DeviceRemoved(this, device)); | |
521 | |
522 VLOG(1) << "Discovered device " << device->GetAddress() | |
523 << " is no longer visible to the adapter"; | |
524 | |
525 delete device; | |
526 devices_.erase(iter); | |
527 } else { | |
528 VLOG(1) << "Paired device " << device->GetAddress() | |
529 << " is no longer visible to the adapter"; | |
530 device->SetDiscovered(false); | |
531 | |
532 NotifyDeviceChanged(device); | |
533 } | |
534 } | |
535 | |
536 } // namespace chromeos | |
OLD | NEW |