1 // Copyright 2013 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 "device/bluetooth/bluetooth_adapter_chromeos.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/sys_info.h"
13 #include "chromeos/dbus/bluetooth_adapter_client.h"
14 #include "chromeos/dbus/bluetooth_device_client.h"
15 #include "chromeos/dbus/bluetooth_input_client.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "device/bluetooth/bluetooth_device.h"
18 #include "device/bluetooth/bluetooth_device_chromeos.h"
20 using device::BluetoothAdapter;
21 using device::BluetoothDevice;
25 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
26 : weak_ptr_factory_(this) {
27 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
28 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
29 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
31 std::vector<dbus::ObjectPath> object_paths =
32 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
34 if (!object_paths.empty()) {
35 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
36 SetAdapter(object_paths[0]);
40 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
41 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
42 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
43 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
46 void BluetoothAdapterChromeOS::AddObserver(
47 BluetoothAdapter::Observer* observer) {
49 observers_.AddObserver(observer);
52 void BluetoothAdapterChromeOS::RemoveObserver(
53 BluetoothAdapter::Observer* observer) {
55 observers_.RemoveObserver(observer);
58 std::string BluetoothAdapterChromeOS::GetAddress() const {
62 BluetoothAdapterClient::Properties* properties =
63 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
64 GetProperties(object_path_);
67 return properties->address.value();
70 std::string BluetoothAdapterChromeOS::GetName() const {
74 BluetoothAdapterClient::Properties* properties =
75 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
76 GetProperties(object_path_);
79 return properties->alias.value();
82 void BluetoothAdapterChromeOS::SetName(const std::string& name,
83 const base::Closure& callback,
84 const ErrorCallback& error_callback) {
85 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
86 GetProperties(object_path_)->alias.Set(
88 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
89 weak_ptr_factory_.GetWeakPtr(),
94 bool BluetoothAdapterChromeOS::IsInitialized() const {
98 bool BluetoothAdapterChromeOS::IsPresent() const {
99 return !object_path_.value().empty();
102 bool BluetoothAdapterChromeOS::IsPowered() const {
106 BluetoothAdapterClient::Properties* properties =
107 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
108 GetProperties(object_path_);
110 return properties->powered.value();
113 void BluetoothAdapterChromeOS::SetPowered(
115 const base::Closure& callback,
116 const ErrorCallback& error_callback) {
117 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
118 GetProperties(object_path_)->powered.Set(
120 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
121 weak_ptr_factory_.GetWeakPtr(),
126 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
130 BluetoothAdapterClient::Properties* properties =
131 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
132 GetProperties(object_path_);
134 return properties->discoverable.value();
137 void BluetoothAdapterChromeOS::SetDiscoverable(
139 const base::Closure& callback,
140 const ErrorCallback& error_callback) {
141 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
142 GetProperties(object_path_)->discoverable.Set(
144 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
145 weak_ptr_factory_.GetWeakPtr(),
150 bool BluetoothAdapterChromeOS::IsDiscovering() const {
154 BluetoothAdapterClient::Properties* properties =
155 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
156 GetProperties(object_path_);
158 return properties->discovering.value();
161 void BluetoothAdapterChromeOS::StartDiscovering(
162 const base::Closure& callback,
163 const ErrorCallback& error_callback) {
164 // BlueZ counts discovery sessions, and permits multiple sessions for a
165 // single connection, so issue a StartDiscovery() call for every use
166 // within Chromium for the right behavior.
167 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
170 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
171 weak_ptr_factory_.GetWeakPtr(),
173 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
174 weak_ptr_factory_.GetWeakPtr(),
178 void BluetoothAdapterChromeOS::StopDiscovering(
179 const base::Closure& callback,
180 const ErrorCallback& error_callback) {
181 // Inform BlueZ to stop one of our open discovery sessions.
182 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
185 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
186 weak_ptr_factory_.GetWeakPtr(),
188 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
189 weak_ptr_factory_.GetWeakPtr(),
193 void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
194 const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
195 const ErrorCallback& error_callback) {
196 error_callback.Run();
199 void BluetoothAdapterChromeOS::AdapterAdded(
200 const dbus::ObjectPath& object_path) {
201 // Set the adapter to the newly added adapter only if no adapter is present.
203 SetAdapter(object_path);
206 void BluetoothAdapterChromeOS::AdapterRemoved(
207 const dbus::ObjectPath& object_path) {
208 if (object_path == object_path_)
212 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
213 const dbus::ObjectPath& object_path,
214 const std::string& property_name) {
215 if (object_path != object_path_)
218 BluetoothAdapterClient::Properties* properties =
219 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
220 GetProperties(object_path_);
222 if (property_name == properties->powered.name())
223 PoweredChanged(properties->powered.value());
224 else if (property_name == properties->discoverable.name())
225 DiscoverableChanged(properties->discoverable.value());
226 else if (property_name == properties->discovering.name())
227 DiscoveringChanged(properties->discovering.value());
230 void BluetoothAdapterChromeOS::DeviceAdded(
231 const dbus::ObjectPath& object_path) {
232 BluetoothDeviceClient::Properties* properties =
233 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
234 GetProperties(object_path);
235 if (properties->adapter.value() != object_path_)
238 BluetoothDeviceChromeOS* device_chromeos =
239 new BluetoothDeviceChromeOS(this, object_path);
240 DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
242 devices_[device_chromeos->GetAddress()] = device_chromeos;
244 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
245 DeviceAdded(this, device_chromeos));
248 void BluetoothAdapterChromeOS::DeviceRemoved(
249 const dbus::ObjectPath& object_path) {
250 for (DevicesMap::iterator iter = devices_.begin();
251 iter != devices_.end(); ++iter) {
252 BluetoothDeviceChromeOS* device_chromeos =
253 static_cast<BluetoothDeviceChromeOS*>(iter->second);
254 if (device_chromeos->object_path() == object_path) {
255 devices_.erase(iter);
257 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
258 DeviceRemoved(this, device_chromeos));
259 delete device_chromeos;
265 void BluetoothAdapterChromeOS::DevicePropertyChanged(
266 const dbus::ObjectPath& object_path,
267 const std::string& property_name) {
268 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
269 if (!device_chromeos)
272 BluetoothDeviceClient::Properties* properties =
273 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
274 GetProperties(object_path);
276 if (property_name == properties->bluetooth_class.name() ||
277 property_name == properties->address.name() ||
278 property_name == properties->alias.name() ||
279 property_name == properties->paired.name() ||
280 property_name == properties->trusted.name() ||
281 property_name == properties->connected.name() ||
282 property_name == properties->uuids.name())
283 NotifyDeviceChanged(device_chromeos);
285 // UMA connection counting
286 if (property_name == properties->connected.name()) {
289 for (DevicesMap::iterator iter = devices_.begin();
290 iter != devices_.end(); ++iter) {
291 if (iter->second->IsPaired() && iter->second->IsConnected())
295 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
299 void BluetoothAdapterChromeOS::InputPropertyChanged(
300 const dbus::ObjectPath& object_path,
301 const std::string& property_name) {
302 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
303 if (!device_chromeos)
306 BluetoothInputClient::Properties* properties =
307 DBusThreadManager::Get()->GetBluetoothInputClient()->
308 GetProperties(object_path);
310 // Properties structure can be removed, which triggers a change in the
311 // BluetoothDevice::IsConnectable() property, as does a change in the
312 // actual reconnect_mode property.
314 property_name == properties->reconnect_mode.name())
315 NotifyDeviceChanged(device_chromeos);
318 BluetoothDeviceChromeOS*
319 BluetoothAdapterChromeOS::GetDeviceWithPath(
320 const dbus::ObjectPath& object_path) {
321 for (DevicesMap::iterator iter = devices_.begin();
322 iter != devices_.end(); ++iter) {
323 BluetoothDeviceChromeOS* device_chromeos =
324 static_cast<BluetoothDeviceChromeOS*>(iter->second);
325 if (device_chromeos->object_path() == object_path)
326 return device_chromeos;
332 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
333 DCHECK(!IsPresent());
334 object_path_ = object_path;
336 VLOG(1) << object_path_.value() << ": using adapter.";
338 SetDefaultAdapterName();
340 BluetoothAdapterClient::Properties* properties =
341 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
342 GetProperties(object_path_);
344 PresentChanged(true);
346 if (properties->powered.value())
347 PoweredChanged(true);
348 if (properties->discoverable.value())
349 DiscoverableChanged(true);
350 if (properties->discovering.value())
351 DiscoveringChanged(true);
353 std::vector<dbus::ObjectPath> device_paths =
354 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
355 GetDevicesForAdapter(object_path_);
357 for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
358 iter != device_paths.end(); ++iter) {
359 BluetoothDeviceChromeOS* device_chromeos =
360 new BluetoothDeviceChromeOS(this, *iter);
362 devices_[device_chromeos->GetAddress()] = device_chromeos;
364 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
365 DeviceAdded(this, device_chromeos));
369 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
370 std::string board = base::SysInfo::GetLsbReleaseBoard();
372 if (board.substr(0, 6) == "stumpy") {
374 } else if (board.substr(0, 4) == "link") {
375 alias = "Chromebook Pixel";
377 alias = "Chromebook";
380 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
383 void BluetoothAdapterChromeOS::RemoveAdapter() {
385 VLOG(1) << object_path_.value() << ": adapter removed.";
387 BluetoothAdapterClient::Properties* properties =
388 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
389 GetProperties(object_path_);
391 object_path_ = dbus::ObjectPath("");
393 if (properties->powered.value())
394 PoweredChanged(false);
395 if (properties->discoverable.value())
396 DiscoverableChanged(false);
397 if (properties->discovering.value())
398 DiscoveringChanged(false);
400 // Copy the devices list here and clear the original so that when we
401 // send DeviceRemoved(), GetDevices() returns no devices.
402 DevicesMap devices = devices_;
405 for (DevicesMap::iterator iter = devices.begin();
406 iter != devices.end(); ++iter) {
407 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
408 DeviceRemoved(this, iter->second));
412 PresentChanged(false);
415 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
416 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
417 AdapterPoweredChanged(this, powered));
420 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
421 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
422 AdapterDiscoverableChanged(this, discoverable));
425 void BluetoothAdapterChromeOS::DiscoveringChanged(
427 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
428 AdapterDiscoveringChanged(this, discovering));
431 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
432 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
433 AdapterPresentChanged(this, present));
436 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
437 BluetoothDeviceChromeOS* device) {
438 DCHECK(device->adapter_ == this);
440 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
441 DeviceChanged(this, device));
444 void BluetoothAdapterChromeOS::OnSetDiscoverable(
445 const base::Closure& callback,
446 const ErrorCallback& error_callback,
448 // Set the discoverable_timeout property to zero so the adapter remains
449 // discoverable forever.
450 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
451 GetProperties(object_path_)->discoverable_timeout.Set(
453 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
454 weak_ptr_factory_.GetWeakPtr(),
459 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
460 const base::Closure& callback,
461 const ErrorCallback& error_callback,
466 error_callback.Run();
469 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) {
473 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
474 const ErrorCallback& error_callback,
475 const std::string& error_name,
476 const std::string& error_message) {
477 LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
478 << error_name << ": " << error_message;
479 error_callback.Run();
482 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
486 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
487 const ErrorCallback& error_callback,
488 const std::string& error_name,
489 const std::string& error_message) {
490 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
491 << error_name << ": " << error_message;
492 error_callback.Run();
495 } // namespace chromeos