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_agent_manager_client.h"
15 #include "chromeos/dbus/bluetooth_agent_service_provider.h"
16 #include "chromeos/dbus/bluetooth_device_client.h"
17 #include "chromeos/dbus/bluetooth_input_client.h"
18 #include "chromeos/dbus/dbus_thread_manager.h"
19 #include "device/bluetooth/bluetooth_device.h"
20 #include "device/bluetooth/bluetooth_device_chromeos.h"
21 #include "device/bluetooth/bluetooth_pairing_chromeos.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 using device::BluetoothAdapter
;
25 using device::BluetoothDevice
;
29 // The agent path is relatively meaningless since BlueZ only permits one to
30 // exist per D-Bus connection, it just has to be unique within Chromium.
31 const char kAgentPath
[] = "/org/chromium/bluetooth_agent";
33 void OnUnregisterAgentError(const std::string
& error_name
,
34 const std::string
& error_message
) {
35 // It's okay if the agent didn't exist, it means we never saw an adapter.
36 if (error_name
== bluetooth_agent_manager::kErrorDoesNotExist
)
39 LOG(WARNING
) << "Failed to unregister pairing agent: "
40 << error_name
<< ": " << error_message
;
47 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
48 : num_discovery_sessions_(0),
49 discovery_request_pending_(false),
50 weak_ptr_factory_(this) {
51 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
52 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
53 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
55 // Register the pairing agent.
56 dbus::Bus
* system_bus
= DBusThreadManager::Get()->GetSystemBus();
57 agent_
.reset(BluetoothAgentServiceProvider::Create(
58 system_bus
, dbus::ObjectPath(kAgentPath
), this));
61 std::vector
<dbus::ObjectPath
> object_paths
=
62 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
64 if (!object_paths
.empty()) {
65 VLOG(1) << object_paths
.size() << " Bluetooth adapter(s) available.";
66 SetAdapter(object_paths
[0]);
70 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
71 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
72 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
73 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
75 VLOG(1) << "Unregistering pairing agent";
76 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
78 dbus::ObjectPath(kAgentPath
),
79 base::Bind(&base::DoNothing
),
80 base::Bind(&OnUnregisterAgentError
));
83 void BluetoothAdapterChromeOS::AddObserver(
84 BluetoothAdapter::Observer
* observer
) {
86 observers_
.AddObserver(observer
);
89 void BluetoothAdapterChromeOS::RemoveObserver(
90 BluetoothAdapter::Observer
* observer
) {
92 observers_
.RemoveObserver(observer
);
95 std::string
BluetoothAdapterChromeOS::GetAddress() const {
99 BluetoothAdapterClient::Properties
* properties
=
100 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
101 GetProperties(object_path_
);
104 return properties
->address
.value();
107 std::string
BluetoothAdapterChromeOS::GetName() const {
109 return std::string();
111 BluetoothAdapterClient::Properties
* properties
=
112 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
113 GetProperties(object_path_
);
116 return properties
->alias
.value();
119 void BluetoothAdapterChromeOS::SetName(const std::string
& name
,
120 const base::Closure
& callback
,
121 const ErrorCallback
& error_callback
) {
122 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
123 GetProperties(object_path_
)->alias
.Set(
125 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted
,
126 weak_ptr_factory_
.GetWeakPtr(),
131 bool BluetoothAdapterChromeOS::IsInitialized() const {
135 bool BluetoothAdapterChromeOS::IsPresent() const {
136 return !object_path_
.value().empty();
139 bool BluetoothAdapterChromeOS::IsPowered() const {
143 BluetoothAdapterClient::Properties
* properties
=
144 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
145 GetProperties(object_path_
);
147 return properties
->powered
.value();
150 void BluetoothAdapterChromeOS::SetPowered(
152 const base::Closure
& callback
,
153 const ErrorCallback
& error_callback
) {
154 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
155 GetProperties(object_path_
)->powered
.Set(
157 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted
,
158 weak_ptr_factory_
.GetWeakPtr(),
163 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
167 BluetoothAdapterClient::Properties
* properties
=
168 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
169 GetProperties(object_path_
);
171 return properties
->discoverable
.value();
174 void BluetoothAdapterChromeOS::SetDiscoverable(
176 const base::Closure
& callback
,
177 const ErrorCallback
& error_callback
) {
178 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
179 GetProperties(object_path_
)->discoverable
.Set(
181 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable
,
182 weak_ptr_factory_
.GetWeakPtr(),
187 bool BluetoothAdapterChromeOS::IsDiscovering() const {
191 BluetoothAdapterClient::Properties
* properties
=
192 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
193 GetProperties(object_path_
);
195 return properties
->discovering
.value();
198 void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
199 const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback
& callback
,
200 const ErrorCallback
& error_callback
) {
201 error_callback
.Run();
204 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
205 BluetoothDevice::PairingDelegate
* pairing_delegate
) {
206 // Before removing a pairing delegate make sure that there aren't any devices
207 // currently using it; if there are, clear the pairing context which will
208 // make any responses no-ops.
209 for (DevicesMap::iterator iter
= devices_
.begin();
210 iter
!= devices_
.end(); ++iter
) {
211 BluetoothDeviceChromeOS
* device_chromeos
=
212 static_cast<BluetoothDeviceChromeOS
*>(iter
->second
);
214 BluetoothPairingChromeOS
* pairing
= device_chromeos
->GetPairing();
215 if (pairing
&& pairing
->GetPairingDelegate() == pairing_delegate
)
216 device_chromeos
->EndPairing();
220 void BluetoothAdapterChromeOS::AdapterAdded(
221 const dbus::ObjectPath
& object_path
) {
222 // Set the adapter to the newly added adapter only if no adapter is present.
224 SetAdapter(object_path
);
227 void BluetoothAdapterChromeOS::AdapterRemoved(
228 const dbus::ObjectPath
& object_path
) {
229 if (object_path
== object_path_
)
233 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
234 const dbus::ObjectPath
& object_path
,
235 const std::string
& property_name
) {
236 if (object_path
!= object_path_
)
239 BluetoothAdapterClient::Properties
* properties
=
240 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
241 GetProperties(object_path_
);
243 if (property_name
== properties
->powered
.name())
244 PoweredChanged(properties
->powered
.value());
245 else if (property_name
== properties
->discoverable
.name())
246 DiscoverableChanged(properties
->discoverable
.value());
247 else if (property_name
== properties
->discovering
.name())
248 DiscoveringChanged(properties
->discovering
.value());
251 void BluetoothAdapterChromeOS::DeviceAdded(
252 const dbus::ObjectPath
& object_path
) {
253 BluetoothDeviceClient::Properties
* properties
=
254 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
255 GetProperties(object_path
);
256 if (properties
->adapter
.value() != object_path_
)
259 BluetoothDeviceChromeOS
* device_chromeos
=
260 new BluetoothDeviceChromeOS(this, object_path
);
261 DCHECK(devices_
.find(device_chromeos
->GetAddress()) == devices_
.end());
263 devices_
[device_chromeos
->GetAddress()] = device_chromeos
;
265 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
266 DeviceAdded(this, device_chromeos
));
269 void BluetoothAdapterChromeOS::DeviceRemoved(
270 const dbus::ObjectPath
& object_path
) {
271 for (DevicesMap::iterator iter
= devices_
.begin();
272 iter
!= devices_
.end(); ++iter
) {
273 BluetoothDeviceChromeOS
* device_chromeos
=
274 static_cast<BluetoothDeviceChromeOS
*>(iter
->second
);
275 if (device_chromeos
->object_path() == object_path
) {
276 devices_
.erase(iter
);
278 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
279 DeviceRemoved(this, device_chromeos
));
280 delete device_chromeos
;
286 void BluetoothAdapterChromeOS::DevicePropertyChanged(
287 const dbus::ObjectPath
& object_path
,
288 const std::string
& property_name
) {
289 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
290 if (!device_chromeos
)
293 BluetoothDeviceClient::Properties
* properties
=
294 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
295 GetProperties(object_path
);
297 if (property_name
== properties
->bluetooth_class
.name() ||
298 property_name
== properties
->address
.name() ||
299 property_name
== properties
->alias
.name() ||
300 property_name
== properties
->paired
.name() ||
301 property_name
== properties
->trusted
.name() ||
302 property_name
== properties
->connected
.name() ||
303 property_name
== properties
->uuids
.name())
304 NotifyDeviceChanged(device_chromeos
);
306 // When a device becomes paired, mark it as trusted so that the user does
307 // not need to approve every incoming connection
308 if (property_name
== properties
->paired
.name() &&
309 properties
->paired
.value())
310 device_chromeos
->SetTrusted();
312 // UMA connection counting
313 if (property_name
== properties
->connected
.name()) {
316 for (DevicesMap::iterator iter
= devices_
.begin();
317 iter
!= devices_
.end(); ++iter
) {
318 if (iter
->second
->IsPaired() && iter
->second
->IsConnected())
322 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count
);
326 void BluetoothAdapterChromeOS::InputPropertyChanged(
327 const dbus::ObjectPath
& object_path
,
328 const std::string
& property_name
) {
329 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
330 if (!device_chromeos
)
333 BluetoothInputClient::Properties
* properties
=
334 DBusThreadManager::Get()->GetBluetoothInputClient()->
335 GetProperties(object_path
);
337 // Properties structure can be removed, which triggers a change in the
338 // BluetoothDevice::IsConnectable() property, as does a change in the
339 // actual reconnect_mode property.
341 property_name
== properties
->reconnect_mode
.name())
342 NotifyDeviceChanged(device_chromeos
);
345 void BluetoothAdapterChromeOS::Released() {
346 DCHECK(agent_
.get());
347 VLOG(1) << "Release";
349 // Called after we unregister the pairing agent, e.g. when changing I/O
350 // capabilities. Nothing much to be done right now.
353 void BluetoothAdapterChromeOS::RequestPinCode(
354 const dbus::ObjectPath
& device_path
,
355 const PinCodeCallback
& callback
) {
356 DCHECK(agent_
.get());
357 VLOG(1) << device_path
.value() << ": RequestPinCode";
359 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
361 callback
.Run(REJECTED
, "");
365 pairing
->RequestPinCode(callback
);
368 void BluetoothAdapterChromeOS::DisplayPinCode(
369 const dbus::ObjectPath
& device_path
,
370 const std::string
& pincode
) {
371 DCHECK(agent_
.get());
372 VLOG(1) << device_path
.value() << ": DisplayPinCode: " << pincode
;
374 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
378 pairing
->DisplayPinCode(pincode
);
381 void BluetoothAdapterChromeOS::RequestPasskey(
382 const dbus::ObjectPath
& device_path
,
383 const PasskeyCallback
& callback
) {
384 DCHECK(agent_
.get());
385 VLOG(1) << device_path
.value() << ": RequestPasskey";
387 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
389 callback
.Run(REJECTED
, 0);
393 pairing
->RequestPasskey(callback
);
396 void BluetoothAdapterChromeOS::DisplayPasskey(
397 const dbus::ObjectPath
& device_path
,
400 DCHECK(agent_
.get());
401 VLOG(1) << device_path
.value() << ": DisplayPasskey: " << passkey
402 << " (" << entered
<< " entered)";
404 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
409 pairing
->DisplayPasskey(passkey
);
411 pairing
->KeysEntered(entered
);
414 void BluetoothAdapterChromeOS::RequestConfirmation(
415 const dbus::ObjectPath
& device_path
,
417 const ConfirmationCallback
& callback
) {
418 DCHECK(agent_
.get());
419 VLOG(1) << device_path
.value() << ": RequestConfirmation: " << passkey
;
421 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
423 callback
.Run(REJECTED
);
427 pairing
->RequestConfirmation(passkey
, callback
);
430 void BluetoothAdapterChromeOS::RequestAuthorization(
431 const dbus::ObjectPath
& device_path
,
432 const ConfirmationCallback
& callback
) {
433 DCHECK(agent_
.get());
434 VLOG(1) << device_path
.value() << ": RequestAuthorization";
436 BluetoothPairingChromeOS
* pairing
= GetPairing(device_path
);
438 callback
.Run(REJECTED
);
442 pairing
->RequestAuthorization(callback
);
445 void BluetoothAdapterChromeOS::AuthorizeService(
446 const dbus::ObjectPath
& device_path
,
447 const std::string
& uuid
,
448 const ConfirmationCallback
& callback
) {
449 DCHECK(agent_
.get());
450 VLOG(1) << device_path
.value() << ": AuthorizeService: " << uuid
;
452 // TODO(keybuk): implement
453 callback
.Run(CANCELLED
);
456 void BluetoothAdapterChromeOS::Cancel() {
457 DCHECK(agent_
.get());
461 void BluetoothAdapterChromeOS::OnRegisterAgent() {
462 VLOG(1) << "Pairing agent registered, requesting to be made default";
464 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
466 dbus::ObjectPath(kAgentPath
),
467 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent
,
468 weak_ptr_factory_
.GetWeakPtr()),
469 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError
,
470 weak_ptr_factory_
.GetWeakPtr()));
474 void BluetoothAdapterChromeOS::OnRegisterAgentError(
475 const std::string
& error_name
,
476 const std::string
& error_message
) {
477 // Our agent being already registered isn't an error.
478 if (error_name
== bluetooth_agent_manager::kErrorAlreadyExists
)
481 LOG(WARNING
) << ": Failed to register pairing agent: "
482 << error_name
<< ": " << error_message
;
485 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
486 VLOG(1) << "Pairing agent now default";
489 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
490 const std::string
& error_name
,
491 const std::string
& error_message
) {
492 LOG(WARNING
) << ": Failed to make pairing agent default: "
493 << error_name
<< ": " << error_message
;
496 BluetoothDeviceChromeOS
*
497 BluetoothAdapterChromeOS::GetDeviceWithPath(
498 const dbus::ObjectPath
& object_path
) {
499 for (DevicesMap::iterator iter
= devices_
.begin();
500 iter
!= devices_
.end(); ++iter
) {
501 BluetoothDeviceChromeOS
* device_chromeos
=
502 static_cast<BluetoothDeviceChromeOS
*>(iter
->second
);
503 if (device_chromeos
->object_path() == object_path
)
504 return device_chromeos
;
510 BluetoothPairingChromeOS
* BluetoothAdapterChromeOS::GetPairing(
511 const dbus::ObjectPath
& object_path
)
513 BluetoothDeviceChromeOS
* device_chromeos
= GetDeviceWithPath(object_path
);
514 if (!device_chromeos
) {
515 LOG(WARNING
) << "Pairing Agent request for unknown device: "
516 << object_path
.value();
520 BluetoothPairingChromeOS
* pairing
= device_chromeos
->GetPairing();
524 // The device doesn't have its own pairing context, so this is an incoming
525 // pairing request that should use our best default delegate (if we have one).
526 BluetoothDevice::PairingDelegate
* pairing_delegate
= DefaultPairingDelegate();
527 if (!pairing_delegate
)
530 return device_chromeos
->BeginPairing(pairing_delegate
);
533 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath
& object_path
) {
534 DCHECK(!IsPresent());
535 object_path_
= object_path
;
537 VLOG(1) << object_path_
.value() << ": using adapter.";
539 VLOG(1) << "Registering pairing agent";
540 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
542 dbus::ObjectPath(kAgentPath
),
543 bluetooth_agent_manager::kKeyboardDisplayCapability
,
544 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent
,
545 weak_ptr_factory_
.GetWeakPtr()),
546 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError
,
547 weak_ptr_factory_
.GetWeakPtr()));
549 SetDefaultAdapterName();
551 BluetoothAdapterClient::Properties
* properties
=
552 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
553 GetProperties(object_path_
);
555 PresentChanged(true);
557 if (properties
->powered
.value())
558 PoweredChanged(true);
559 if (properties
->discoverable
.value())
560 DiscoverableChanged(true);
561 if (properties
->discovering
.value())
562 DiscoveringChanged(true);
564 std::vector
<dbus::ObjectPath
> device_paths
=
565 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
566 GetDevicesForAdapter(object_path_
);
568 for (std::vector
<dbus::ObjectPath
>::iterator iter
= device_paths
.begin();
569 iter
!= device_paths
.end(); ++iter
) {
570 BluetoothDeviceChromeOS
* device_chromeos
=
571 new BluetoothDeviceChromeOS(this, *iter
);
573 devices_
[device_chromeos
->GetAddress()] = device_chromeos
;
575 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
576 DeviceAdded(this, device_chromeos
));
580 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
581 std::string board
= base::SysInfo::GetLsbReleaseBoard();
583 if (board
.substr(0, 6) == "stumpy") {
585 } else if (board
.substr(0, 4) == "link") {
586 alias
= "Chromebook Pixel";
588 alias
= "Chromebook";
591 SetName(alias
, base::Bind(&base::DoNothing
), base::Bind(&base::DoNothing
));
594 void BluetoothAdapterChromeOS::RemoveAdapter() {
596 VLOG(1) << object_path_
.value() << ": adapter removed.";
598 BluetoothAdapterClient::Properties
* properties
=
599 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
600 GetProperties(object_path_
);
602 object_path_
= dbus::ObjectPath("");
604 if (properties
->powered
.value())
605 PoweredChanged(false);
606 if (properties
->discoverable
.value())
607 DiscoverableChanged(false);
608 if (properties
->discovering
.value())
609 DiscoveringChanged(false);
611 // Copy the devices list here and clear the original so that when we
612 // send DeviceRemoved(), GetDevices() returns no devices.
613 DevicesMap devices
= devices_
;
616 for (DevicesMap::iterator iter
= devices
.begin();
617 iter
!= devices
.end(); ++iter
) {
618 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
619 DeviceRemoved(this, iter
->second
));
623 PresentChanged(false);
626 void BluetoothAdapterChromeOS::PoweredChanged(bool powered
) {
627 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
628 AdapterPoweredChanged(this, powered
));
631 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable
) {
632 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
633 AdapterDiscoverableChanged(this, discoverable
));
636 void BluetoothAdapterChromeOS::DiscoveringChanged(
638 // If the adapter stopped discovery due to a reason other than a request by
639 // us, reset the count to 0.
640 VLOG(1) << "Discovering changed: " << discovering
;
641 if (!discovering
&& !discovery_request_pending_
642 && num_discovery_sessions_
> 0) {
643 VLOG(1) << "Marking sessions as inactive.";
644 num_discovery_sessions_
= 0;
645 MarkDiscoverySessionsAsInactive();
647 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
648 AdapterDiscoveringChanged(this, discovering
));
651 void BluetoothAdapterChromeOS::PresentChanged(bool present
) {
652 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
653 AdapterPresentChanged(this, present
));
656 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
657 BluetoothDeviceChromeOS
* device
) {
658 DCHECK(device
->adapter_
== this);
660 FOR_EACH_OBSERVER(BluetoothAdapter::Observer
, observers_
,
661 DeviceChanged(this, device
));
664 void BluetoothAdapterChromeOS::OnSetDiscoverable(
665 const base::Closure
& callback
,
666 const ErrorCallback
& error_callback
,
668 // Set the discoverable_timeout property to zero so the adapter remains
669 // discoverable forever.
670 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
671 GetProperties(object_path_
)->discoverable_timeout
.Set(
673 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted
,
674 weak_ptr_factory_
.GetWeakPtr(),
679 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
680 const base::Closure
& callback
,
681 const ErrorCallback
& error_callback
,
686 error_callback
.Run();
689 void BluetoothAdapterChromeOS::AddDiscoverySession(
690 const base::Closure
& callback
,
691 const ErrorCallback
& error_callback
) {
693 if (discovery_request_pending_
) {
694 // The pending request is either to stop a previous session or to start a
695 // new one. Either way, queue this one.
696 DCHECK(num_discovery_sessions_
== 1 || num_discovery_sessions_
== 0);
697 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
698 << "request to start a new discovery session.";
699 discovery_request_queue_
.push(std::make_pair(callback
, error_callback
));
703 // The adapter is already discovering.
704 if (num_discovery_sessions_
> 0) {
705 DCHECK(IsDiscovering());
706 DCHECK(!discovery_request_pending_
);
707 num_discovery_sessions_
++;
712 // There are no active discovery sessions.
713 DCHECK(num_discovery_sessions_
== 0);
715 // This is the first request to start device discovery.
716 discovery_request_pending_
= true;
717 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
720 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery
,
721 weak_ptr_factory_
.GetWeakPtr(),
723 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError
,
724 weak_ptr_factory_
.GetWeakPtr(),
729 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
730 const base::Closure
& callback
,
731 const ErrorCallback
& error_callback
) {
733 // There are active sessions other than the one currently being removed.
734 if (num_discovery_sessions_
> 1) {
735 DCHECK(IsDiscovering());
736 DCHECK(!discovery_request_pending_
);
737 num_discovery_sessions_
--;
742 // If there is a pending request to BlueZ, then queue this request.
743 if (discovery_request_pending_
) {
744 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
745 << "request to stop discovery session.";
746 error_callback
.Run();
750 // There are no active sessions. Return error.
751 if (num_discovery_sessions_
== 0) {
752 // TODO(armansito): This should never happen once we have the
753 // DiscoverySession API. Replace this case with an assert once it's
754 // the deprecated methods have been removed. (See crbug.com/3445008).
755 VLOG(1) << "No active discovery sessions. Returning error.";
756 error_callback
.Run();
760 // There is exactly one active discovery session. Request BlueZ to stop
762 DCHECK(num_discovery_sessions_
== 1);
763 discovery_request_pending_
= true;
764 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
767 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery
,
768 weak_ptr_factory_
.GetWeakPtr(),
770 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError
,
771 weak_ptr_factory_
.GetWeakPtr(),
775 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure
& callback
) {
776 // Report success on the original request and increment the count.
778 DCHECK(discovery_request_pending_
);
779 DCHECK(num_discovery_sessions_
== 0);
780 discovery_request_pending_
= false;
781 num_discovery_sessions_
++;
784 // Try to add a new discovery session for each queued request.
785 ProcessQueuedDiscoveryRequests();
788 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
789 const base::Closure
& callback
,
790 const ErrorCallback
& error_callback
,
791 const std::string
& error_name
,
792 const std::string
& error_message
) {
793 LOG(WARNING
) << object_path_
.value() << ": Failed to start discovery: "
794 << error_name
<< ": " << error_message
;
796 // Failed to start discovery. This can only happen if the count is at 0.
797 DCHECK(num_discovery_sessions_
== 0);
798 DCHECK(discovery_request_pending_
);
799 discovery_request_pending_
= false;
801 // Discovery request may fail if discovery was previously initiated by Chrome,
802 // but the session were invalidated due to the discovery state unexpectedly
803 // changing to false and then back to true. In this case, report success.
804 if (error_name
== bluetooth_device::kErrorInProgress
&& IsDiscovering()) {
805 VLOG(1) << "Discovery previously initiated. Reporting success.";
806 num_discovery_sessions_
++;
809 error_callback
.Run();
812 // Try to add a new discovery session for each queued request.
813 ProcessQueuedDiscoveryRequests();
816 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure
& callback
) {
817 // Report success on the original request and decrement the count.
819 DCHECK(discovery_request_pending_
);
820 DCHECK(num_discovery_sessions_
== 1);
821 discovery_request_pending_
= false;
822 num_discovery_sessions_
--;
825 // Try to add a new discovery session for each queued request.
826 ProcessQueuedDiscoveryRequests();
829 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
830 const ErrorCallback
& error_callback
,
831 const std::string
& error_name
,
832 const std::string
& error_message
) {
833 LOG(WARNING
) << object_path_
.value() << ": Failed to stop discovery: "
834 << error_name
<< ": " << error_message
;
836 // Failed to stop discovery. This can only happen if the count is at 1.
837 DCHECK(discovery_request_pending_
);
838 DCHECK(num_discovery_sessions_
== 1);
839 discovery_request_pending_
= false;
840 error_callback
.Run();
842 // Try to add a new discovery session for each queued request.
843 ProcessQueuedDiscoveryRequests();
846 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
847 while (!discovery_request_queue_
.empty()) {
848 VLOG(1) << "Process queued discovery request.";
849 DiscoveryCallbackPair callbacks
= discovery_request_queue_
.front();
850 discovery_request_queue_
.pop();
851 AddDiscoverySession(callbacks
.first
, callbacks
.second
);
853 // If the queued request resulted in a pending call, then let it
854 // asynchonously process the remaining queued requests once the pending
856 if (discovery_request_pending_
)
861 } // namespace chromeos