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 bool BluetoothAdapterChromeOS::IsInitialized() const {
86 bool BluetoothAdapterChromeOS::IsPresent() const {
87 return !object_path_
.value().empty();
90 bool BluetoothAdapterChromeOS::IsPowered() const {
94 BluetoothAdapterClient::Properties
* properties
=
95 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
96 GetProperties(object_path_
);
98 return properties
->powered
.value();
101 void BluetoothAdapterChromeOS::SetPowered(
103 const base::Closure
& callback
,
104 const ErrorCallback
& error_callback
) {
105 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
106 GetProperties(object_path_
)->powered
.Set(
108 base::Bind(&BluetoothAdapterChromeOS::OnSetPowered
,
109 weak_ptr_factory_
.GetWeakPtr(),
114 bool BluetoothAdapterChromeOS::IsDiscovering() const {
118 BluetoothAdapterClient::Properties
* properties
=
119 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
120 GetProperties(object_path_
);
122 return properties
->discovering
.value();
125 void BluetoothAdapterChromeOS::StartDiscovering(
126 const base::Closure
& callback
,
127 const ErrorCallback
& error_callback
) {
128 // BlueZ counts discovery sessions, and permits multiple sessions for a
129 // single connection, so issue a StartDiscovery() call for every use
130 // within Chromium for the right behavior.
131 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
134 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery
,
135 weak_ptr_factory_
.GetWeakPtr(),
137 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError
,
138 weak_ptr_factory_
.GetWeakPtr(),
142 void BluetoothAdapterChromeOS::StopDiscovering(
143 const base::Closure
& callback
,
144 const ErrorCallback
& error_callback
) {
145 // Inform BlueZ to stop one of our open discovery sessions.
146 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
149 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery
,
150 weak_ptr_factory_
.GetWeakPtr(),
152 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError
,
153 weak_ptr_factory_
.GetWeakPtr(),
157 void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
158 const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback
& callback
,
159 const ErrorCallback
& error_callback
) {
160 error_callback
.Run();
163 void BluetoothAdapterChromeOS::AdapterAdded(
164 const dbus::ObjectPath
& object_path
) {
165 // Set the adapter to the newly added adapter only if no adapter is present.
167 SetAdapter(object_path
);
170 void BluetoothAdapterChromeOS::AdapterRemoved(
171 const dbus::ObjectPath
& object_path
) {
172 if (object_path
== object_path_
)
176 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
177 const dbus::ObjectPath
& object_path
,
178 const std::string
& property_name
) {
179 if (object_path
!= object_path_
)
182 BluetoothAdapterClient::Properties
* properties
=
183 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
184 GetProperties(object_path_
);
186 if (property_name
== properties
->powered
.name())
187 PoweredChanged(properties
->powered
.value());
188 else if (property_name
== properties
->discovering
.name())
189 DiscoveringChanged(properties
->discovering
.value());
192 void BluetoothAdapterChromeOS::DeviceAdded(
193 const dbus::ObjectPath
& object_path
) {
194 BluetoothDeviceClient::Properties
* properties
=
195 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
196 GetProperties(object_path
);
197 if (properties
->adapter
.value() != object_path_
)
200 BluetoothDeviceChromeOS
* device_chromeos
=
201 new BluetoothDeviceChromeOS(this, object_path
);
202 DCHECK(devices_
.find(device_chromeos
->GetAddress()) == devices_
.end());
204 devices_
[device_chromeos
->GetAddress()] = device_chromeos
;
206 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
207 DeviceAdded(this, device_chromeos
));
210 void BluetoothAdapterChromeOS::DeviceRemoved(
211 const dbus::ObjectPath
& object_path
) {
212 for (DevicesMap::iterator iter
= devices_
.begin();
213 iter
!= devices_
.end(); ++iter
) {
214 BluetoothDeviceChromeOS
* device_chromeos
=
215 static_cast<BluetoothDeviceChromeOS
*>(iter
->second
);
216 if (device_chromeos
->object_path() == object_path
) {
217 devices_
.erase(iter
);
219 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
220 DeviceRemoved(this, device_chromeos
));
221 delete device_chromeos
;
227 void BluetoothAdapterChromeOS::DevicePropertyChanged(
228 const dbus::ObjectPath
& object_path
,
229 const std::string
& property_name
) {
230 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
231 if (!device_chromeos
)
234 BluetoothDeviceClient::Properties
* properties
=
235 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
236 GetProperties(object_path
);
238 if (property_name
== properties
->bluetooth_class
.name() ||
239 property_name
== properties
->address
.name() ||
240 property_name
== properties
->alias
.name() ||
241 property_name
== properties
->paired
.name() ||
242 property_name
== properties
->trusted
.name() ||
243 property_name
== properties
->connected
.name() ||
244 property_name
== properties
->uuids
.name())
245 NotifyDeviceChanged(device_chromeos
);
247 // UMA connection counting
248 if (property_name
== properties
->connected
.name()) {
251 for (DevicesMap::iterator iter
= devices_
.begin();
252 iter
!= devices_
.end(); ++iter
) {
253 if (iter
->second
->IsPaired() && iter
->second
->IsConnected())
257 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count
);
261 void BluetoothAdapterChromeOS::InputPropertyChanged(
262 const dbus::ObjectPath
& object_path
,
263 const std::string
& property_name
) {
264 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
265 if (!device_chromeos
)
268 BluetoothInputClient::Properties
* properties
=
269 DBusThreadManager::Get()->GetBluetoothInputClient()->
270 GetProperties(object_path
);
272 // Properties structure can be removed, which triggers a change in the
273 // BluetoothDevice::IsConnectable() property, as does a change in the
274 // actual reconnect_mode property.
276 property_name
== properties
->reconnect_mode
.name())
277 NotifyDeviceChanged(device_chromeos
);
280 BluetoothDeviceChromeOS
*
281 BluetoothAdapterChromeOS::GetDeviceWithPath(
282 const dbus::ObjectPath
& object_path
) {
283 for (DevicesMap::iterator iter
= devices_
.begin();
284 iter
!= devices_
.end(); ++iter
) {
285 BluetoothDeviceChromeOS
* device_chromeos
=
286 static_cast<BluetoothDeviceChromeOS
*>(iter
->second
);
287 if (device_chromeos
->object_path() == object_path
)
288 return device_chromeos
;
294 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath
& object_path
) {
295 DCHECK(!IsPresent());
296 object_path_
= object_path
;
298 VLOG(1) << object_path_
.value() << ": using adapter.";
302 BluetoothAdapterClient::Properties
* properties
=
303 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
304 GetProperties(object_path_
);
306 PresentChanged(true);
308 if (properties
->powered
.value())
309 PoweredChanged(true);
310 if (properties
->discovering
.value())
311 DiscoveringChanged(true);
313 std::vector
<dbus::ObjectPath
> device_paths
=
314 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
315 GetDevicesForAdapter(object_path_
);
317 for (std::vector
<dbus::ObjectPath
>::iterator iter
= device_paths
.begin();
318 iter
!= device_paths
.end(); ++iter
) {
319 BluetoothDeviceChromeOS
* device_chromeos
=
320 new BluetoothDeviceChromeOS(this, *iter
);
322 devices_
[device_chromeos
->GetAddress()] = device_chromeos
;
324 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
325 DeviceAdded(this, device_chromeos
));
329 void BluetoothAdapterChromeOS::SetAdapterName() {
330 std::string board
= base::SysInfo::GetLsbReleaseBoard();
332 if (board
.substr(0, 6) == "stumpy") {
334 } else if (board
.substr(0, 4) == "link") {
335 alias
= "Chromebook Pixel";
337 alias
= "Chromebook";
340 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
341 GetProperties(object_path_
)->alias
.Set(
343 base::Bind(&BluetoothAdapterChromeOS::OnSetAlias
,
344 weak_ptr_factory_
.GetWeakPtr()));
347 void BluetoothAdapterChromeOS::OnSetAlias(bool success
) {
348 LOG_IF(WARNING
, !success
) << object_path_
.value()
349 << ": Failed to set adapter alias";
352 void BluetoothAdapterChromeOS::RemoveAdapter() {
354 VLOG(1) << object_path_
.value() << ": adapter removed.";
356 BluetoothAdapterClient::Properties
* properties
=
357 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
358 GetProperties(object_path_
);
360 object_path_
= dbus::ObjectPath("");
362 if (properties
->powered
.value())
363 PoweredChanged(false);
364 if (properties
->discovering
.value())
365 DiscoveringChanged(false);
367 // Copy the devices list here and clear the original so that when we
368 // send DeviceRemoved(), GetDevices() returns no devices.
369 DevicesMap devices
= devices_
;
372 for (DevicesMap::iterator iter
= devices
.begin();
373 iter
!= devices
.end(); ++iter
) {
374 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
375 DeviceRemoved(this, iter
->second
));
379 PresentChanged(false);
382 void BluetoothAdapterChromeOS::PoweredChanged(bool powered
) {
383 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
384 AdapterPoweredChanged(this, powered
));
387 void BluetoothAdapterChromeOS::DiscoveringChanged(
389 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
390 AdapterDiscoveringChanged(this, discovering
));
393 void BluetoothAdapterChromeOS::PresentChanged(bool present
) {
394 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
395 AdapterPresentChanged(this, present
));
398 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
399 BluetoothDeviceChromeOS
* device
) {
400 DCHECK(device
->adapter_
== this);
402 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
403 DeviceChanged(this, device
));
406 void BluetoothAdapterChromeOS::OnSetPowered(const base::Closure
& callback
,
407 const ErrorCallback
& error_callback
,
412 error_callback
.Run();
415 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure
& callback
) {
419 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
420 const ErrorCallback
& error_callback
,
421 const std::string
& error_name
,
422 const std::string
& error_message
) {
423 LOG(WARNING
) << object_path_
.value() << ": Failed to start discovery: "
424 << error_name
<< ": " << error_message
;
425 error_callback
.Run();
428 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure
& callback
) {
432 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
433 const ErrorCallback
& error_callback
,
434 const std::string
& error_name
,
435 const std::string
& error_message
) {
436 LOG(WARNING
) << object_path_
.value() << ": Failed to stop discovery: "
437 << error_name
<< ": " << error_message
;
438 error_callback
.Run();
441 } // namespace chromeos