Simplify About Chrome settings page.
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_chromeos.cc
blob9ba2cbd7692ba5a4362157d6555fcd0b76a7d123
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"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/sys_info.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "chromeos/dbus/bluetooth_adapter_client.h"
18 #include "chromeos/dbus/bluetooth_agent_manager_client.h"
19 #include "chromeos/dbus/bluetooth_agent_service_provider.h"
20 #include "chromeos/dbus/bluetooth_device_client.h"
21 #include "chromeos/dbus/bluetooth_input_client.h"
22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "device/bluetooth/bluetooth_adapter_profile_chromeos.h"
24 #include "device/bluetooth/bluetooth_advertisement_chromeos.h"
25 #include "device/bluetooth/bluetooth_audio_sink_chromeos.h"
26 #include "device/bluetooth/bluetooth_device.h"
27 #include "device/bluetooth/bluetooth_device_chromeos.h"
28 #include "device/bluetooth/bluetooth_pairing_chromeos.h"
29 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
30 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
31 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
32 #include "device/bluetooth/bluetooth_socket_chromeos.h"
33 #include "device/bluetooth/bluetooth_socket_thread.h"
34 #include "device/bluetooth/bluetooth_uuid.h"
35 #include "third_party/cros_system_api/dbus/service_constants.h"
37 using device::BluetoothAdapter;
38 using device::BluetoothAudioSink;
39 using device::BluetoothDevice;
40 using device::BluetoothDiscoveryFilter;
41 using device::BluetoothSocket;
42 using device::BluetoothUUID;
44 namespace {
46 // The agent path is relatively meaningless since BlueZ only permits one to
47 // exist per D-Bus connection, it just has to be unique within Chromium.
48 const char kAgentPath[] = "/org/chromium/bluetooth_agent";
50 void OnUnregisterAgentError(const std::string& error_name,
51 const std::string& error_message) {
52 // It's okay if the agent didn't exist, it means we never saw an adapter.
53 if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
54 return;
56 LOG(WARNING) << "Failed to unregister pairing agent: "
57 << error_name << ": " << error_message;
60 } // namespace
62 namespace device {
64 // static
65 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
66 const InitCallback& init_callback) {
67 return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
70 } // namespace device
72 namespace chromeos {
74 // static
75 base::WeakPtr<BluetoothAdapter> BluetoothAdapterChromeOS::CreateAdapter() {
76 BluetoothAdapterChromeOS* adapter = new BluetoothAdapterChromeOS();
77 return adapter->weak_ptr_factory_.GetWeakPtr();
80 void BluetoothAdapterChromeOS::Shutdown() {
81 if (dbus_is_shutdown_)
82 return;
83 DCHECK(DBusThreadManager::IsInitialized())
84 << "Call BluetoothAdapterFactory::Shutdown() before "
85 "DBusThreadManager::Shutdown().";
87 if (IsPresent())
88 RemoveAdapter(); // Also deletes devices_.
89 DCHECK(devices_.empty());
90 // profiles_ is empty because all BluetoothSockets have been notified
91 // that this adapter is disappearing.
92 DCHECK(profiles_.empty());
94 for (auto& it : profile_queues_)
95 delete it.second;
96 profile_queues_.clear();
98 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
99 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
100 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
102 VLOG(1) << "Unregistering pairing agent";
103 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->UnregisterAgent(
104 dbus::ObjectPath(kAgentPath), base::Bind(&base::DoNothing),
105 base::Bind(&OnUnregisterAgentError));
107 agent_.reset();
108 dbus_is_shutdown_ = true;
111 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
112 : dbus_is_shutdown_(false),
113 num_discovery_sessions_(0),
114 discovery_request_pending_(false),
115 weak_ptr_factory_(this) {
116 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
117 socket_thread_ = device::BluetoothSocketThread::Get();
119 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
120 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
121 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
123 // Register the pairing agent.
124 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
125 agent_.reset(BluetoothAgentServiceProvider::Create(
126 system_bus, dbus::ObjectPath(kAgentPath), this));
127 DCHECK(agent_.get());
129 std::vector<dbus::ObjectPath> object_paths =
130 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
132 if (!object_paths.empty()) {
133 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
134 SetAdapter(object_paths[0]);
138 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
139 Shutdown();
142 std::string BluetoothAdapterChromeOS::GetAddress() const {
143 if (!IsPresent())
144 return std::string();
146 BluetoothAdapterClient::Properties* properties =
147 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
148 GetProperties(object_path_);
149 DCHECK(properties);
151 return BluetoothDevice::CanonicalizeAddress(properties->address.value());
154 std::string BluetoothAdapterChromeOS::GetName() const {
155 if (!IsPresent())
156 return std::string();
158 BluetoothAdapterClient::Properties* properties =
159 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
160 GetProperties(object_path_);
161 DCHECK(properties);
163 return properties->alias.value();
166 void BluetoothAdapterChromeOS::SetName(const std::string& name,
167 const base::Closure& callback,
168 const ErrorCallback& error_callback) {
169 if (!IsPresent()) {
170 error_callback.Run();
171 return;
174 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
175 GetProperties(object_path_)->alias.Set(
176 name,
177 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
178 weak_ptr_factory_.GetWeakPtr(),
179 callback,
180 error_callback));
183 bool BluetoothAdapterChromeOS::IsInitialized() const {
184 return true;
187 bool BluetoothAdapterChromeOS::IsPresent() const {
188 return !dbus_is_shutdown_ && !object_path_.value().empty();
191 bool BluetoothAdapterChromeOS::IsPowered() const {
192 if (!IsPresent())
193 return false;
195 BluetoothAdapterClient::Properties* properties =
196 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
197 GetProperties(object_path_);
199 return properties->powered.value();
202 void BluetoothAdapterChromeOS::SetPowered(
203 bool powered,
204 const base::Closure& callback,
205 const ErrorCallback& error_callback) {
206 if (!IsPresent()) {
207 error_callback.Run();
208 return;
211 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
212 GetProperties(object_path_)->powered.Set(
213 powered,
214 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
215 weak_ptr_factory_.GetWeakPtr(),
216 callback,
217 error_callback));
220 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
221 if (!IsPresent())
222 return false;
224 BluetoothAdapterClient::Properties* properties =
225 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
226 GetProperties(object_path_);
228 return properties->discoverable.value();
231 void BluetoothAdapterChromeOS::SetDiscoverable(
232 bool discoverable,
233 const base::Closure& callback,
234 const ErrorCallback& error_callback) {
235 if (!IsPresent()) {
236 error_callback.Run();
237 return;
240 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
241 GetProperties(object_path_)->discoverable.Set(
242 discoverable,
243 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
244 weak_ptr_factory_.GetWeakPtr(),
245 callback,
246 error_callback));
249 bool BluetoothAdapterChromeOS::IsDiscovering() const {
250 if (!IsPresent())
251 return false;
253 BluetoothAdapterClient::Properties* properties =
254 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
255 GetProperties(object_path_);
257 return properties->discovering.value();
260 void BluetoothAdapterChromeOS::CreateRfcommService(
261 const BluetoothUUID& uuid,
262 const ServiceOptions& options,
263 const CreateServiceCallback& callback,
264 const CreateServiceErrorCallback& error_callback) {
265 DCHECK(!dbus_is_shutdown_);
266 VLOG(1) << object_path_.value() << ": Creating RFCOMM service: "
267 << uuid.canonical_value();
268 scoped_refptr<BluetoothSocketChromeOS> socket =
269 BluetoothSocketChromeOS::CreateBluetoothSocket(
270 ui_task_runner_, socket_thread_);
271 socket->Listen(this,
272 BluetoothSocketChromeOS::kRfcomm,
273 uuid,
274 options,
275 base::Bind(callback, socket),
276 error_callback);
279 void BluetoothAdapterChromeOS::CreateL2capService(
280 const BluetoothUUID& uuid,
281 const ServiceOptions& options,
282 const CreateServiceCallback& callback,
283 const CreateServiceErrorCallback& error_callback) {
284 DCHECK(!dbus_is_shutdown_);
285 VLOG(1) << object_path_.value() << ": Creating L2CAP service: "
286 << uuid.canonical_value();
287 scoped_refptr<BluetoothSocketChromeOS> socket =
288 BluetoothSocketChromeOS::CreateBluetoothSocket(
289 ui_task_runner_, socket_thread_);
290 socket->Listen(this,
291 BluetoothSocketChromeOS::kL2cap,
292 uuid,
293 options,
294 base::Bind(callback, socket),
295 error_callback);
298 void BluetoothAdapterChromeOS::RegisterAudioSink(
299 const BluetoothAudioSink::Options& options,
300 const device::BluetoothAdapter::AcquiredCallback& callback,
301 const BluetoothAudioSink::ErrorCallback& error_callback) {
302 VLOG(1) << "Registering audio sink";
303 if (!this->IsPresent()) {
304 error_callback.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER);
305 return;
307 scoped_refptr<BluetoothAudioSinkChromeOS> audio_sink(
308 new BluetoothAudioSinkChromeOS(this));
309 audio_sink->Register(
310 options, base::Bind(&BluetoothAdapterChromeOS::OnRegisterAudioSink,
311 weak_ptr_factory_.GetWeakPtr(), callback,
312 error_callback, audio_sink),
313 error_callback);
316 void BluetoothAdapterChromeOS::RegisterAdvertisement(
317 scoped_ptr<device::BluetoothAdvertisement::Data> advertisement_data,
318 const CreateAdvertisementCallback& callback,
319 const CreateAdvertisementErrorCallback& error_callback) {
320 scoped_refptr<BluetoothAdvertisementChromeOS> advertisement(
321 new BluetoothAdvertisementChromeOS(advertisement_data.Pass(), this));
322 advertisement->Register(base::Bind(callback, advertisement), error_callback);
325 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
326 BluetoothDevice::PairingDelegate* pairing_delegate) {
327 // Check if any device is using the pairing delegate.
328 // If so, clear the pairing context which will make any responses no-ops.
329 for (DevicesMap::iterator iter = devices_.begin();
330 iter != devices_.end(); ++iter) {
331 BluetoothDeviceChromeOS* device_chromeos =
332 static_cast<BluetoothDeviceChromeOS*>(iter->second);
334 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
335 if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
336 device_chromeos->EndPairing();
340 void BluetoothAdapterChromeOS::AdapterAdded(
341 const dbus::ObjectPath& object_path) {
342 // Set the adapter to the newly added adapter only if no adapter is present.
343 if (!IsPresent())
344 SetAdapter(object_path);
347 void BluetoothAdapterChromeOS::AdapterRemoved(
348 const dbus::ObjectPath& object_path) {
349 if (object_path == object_path_)
350 RemoveAdapter();
353 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
354 const dbus::ObjectPath& object_path,
355 const std::string& property_name) {
356 if (object_path != object_path_)
357 return;
358 DCHECK(IsPresent());
360 BluetoothAdapterClient::Properties* properties =
361 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
362 GetProperties(object_path_);
364 if (property_name == properties->powered.name()) {
365 PoweredChanged(properties->powered.value());
366 } else if (property_name == properties->discoverable.name()) {
367 DiscoverableChanged(properties->discoverable.value());
368 } else if (property_name == properties->discovering.name()) {
369 DiscoveringChanged(properties->discovering.value());
373 void BluetoothAdapterChromeOS::DeviceAdded(
374 const dbus::ObjectPath& object_path) {
375 DCHECK(DBusThreadManager::Get());
376 BluetoothDeviceClient::Properties* properties =
377 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
378 GetProperties(object_path);
379 if (!properties || properties->adapter.value() != object_path_)
380 return;
381 DCHECK(IsPresent());
383 BluetoothDeviceChromeOS* device_chromeos =
384 new BluetoothDeviceChromeOS(this,
385 object_path,
386 ui_task_runner_,
387 socket_thread_);
388 DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
390 devices_[device_chromeos->GetAddress()] = device_chromeos;
392 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
393 DeviceAdded(this, device_chromeos));
396 void BluetoothAdapterChromeOS::DeviceRemoved(
397 const dbus::ObjectPath& object_path) {
398 for (DevicesMap::iterator iter = devices_.begin();
399 iter != devices_.end(); ++iter) {
400 BluetoothDeviceChromeOS* device_chromeos =
401 static_cast<BluetoothDeviceChromeOS*>(iter->second);
402 if (device_chromeos->object_path() == object_path) {
403 devices_.erase(iter);
405 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
406 DeviceRemoved(this, device_chromeos));
407 delete device_chromeos;
408 return;
413 void BluetoothAdapterChromeOS::DevicePropertyChanged(
414 const dbus::ObjectPath& object_path,
415 const std::string& property_name) {
416 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
417 if (!device_chromeos)
418 return;
420 BluetoothDeviceClient::Properties* properties =
421 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
422 GetProperties(object_path);
424 if (property_name == properties->bluetooth_class.name() ||
425 property_name == properties->address.name() ||
426 property_name == properties->alias.name() ||
427 property_name == properties->paired.name() ||
428 property_name == properties->trusted.name() ||
429 property_name == properties->connected.name() ||
430 property_name == properties->uuids.name() ||
431 property_name == properties->rssi.name() ||
432 property_name == properties->tx_power.name()) {
433 NotifyDeviceChanged(device_chromeos);
436 // When a device becomes paired, mark it as trusted so that the user does
437 // not need to approve every incoming connection
438 if (property_name == properties->paired.name() &&
439 properties->paired.value() && !properties->trusted.value()) {
440 device_chromeos->SetTrusted();
443 // UMA connection counting
444 if (property_name == properties->connected.name()) {
445 // PlayStation joystick tries to reconnect after disconnection from USB.
446 // If it is still not trusted, set it, so it becomes available on the
447 // list of known devices.
448 if (properties->connected.value() && device_chromeos->IsTrustable() &&
449 !properties->trusted.value())
450 device_chromeos->SetTrusted();
452 int count = 0;
454 for (DevicesMap::iterator iter = devices_.begin();
455 iter != devices_.end(); ++iter) {
456 if (iter->second->IsPaired() && iter->second->IsConnected())
457 ++count;
460 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
464 void BluetoothAdapterChromeOS::InputPropertyChanged(
465 const dbus::ObjectPath& object_path,
466 const std::string& property_name) {
467 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
468 if (!device_chromeos)
469 return;
471 BluetoothInputClient::Properties* properties =
472 DBusThreadManager::Get()->GetBluetoothInputClient()->
473 GetProperties(object_path);
475 // Properties structure can be removed, which triggers a change in the
476 // BluetoothDevice::IsConnectable() property, as does a change in the
477 // actual reconnect_mode property.
478 if (!properties || property_name == properties->reconnect_mode.name()) {
479 NotifyDeviceChanged(device_chromeos);
483 void BluetoothAdapterChromeOS::Released() {
484 VLOG(1) << "Release";
485 if (!IsPresent())
486 return;
487 DCHECK(agent_.get());
489 // Called after we unregister the pairing agent, e.g. when changing I/O
490 // capabilities. Nothing much to be done right now.
493 void BluetoothAdapterChromeOS::RequestPinCode(
494 const dbus::ObjectPath& device_path,
495 const PinCodeCallback& callback) {
496 DCHECK(IsPresent());
497 DCHECK(agent_.get());
498 VLOG(1) << device_path.value() << ": RequestPinCode";
500 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
501 if (!pairing) {
502 callback.Run(REJECTED, "");
503 return;
506 pairing->RequestPinCode(callback);
509 void BluetoothAdapterChromeOS::DisplayPinCode(
510 const dbus::ObjectPath& device_path,
511 const std::string& pincode) {
512 DCHECK(IsPresent());
513 DCHECK(agent_.get());
514 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
516 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
517 if (!pairing)
518 return;
520 pairing->DisplayPinCode(pincode);
523 void BluetoothAdapterChromeOS::RequestPasskey(
524 const dbus::ObjectPath& device_path,
525 const PasskeyCallback& callback) {
526 DCHECK(IsPresent());
527 DCHECK(agent_.get());
528 VLOG(1) << device_path.value() << ": RequestPasskey";
530 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
531 if (!pairing) {
532 callback.Run(REJECTED, 0);
533 return;
536 pairing->RequestPasskey(callback);
539 void BluetoothAdapterChromeOS::DisplayPasskey(
540 const dbus::ObjectPath& device_path,
541 uint32 passkey,
542 uint16 entered) {
543 DCHECK(IsPresent());
544 DCHECK(agent_.get());
545 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
546 << " (" << entered << " entered)";
548 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
549 if (!pairing)
550 return;
552 if (entered == 0)
553 pairing->DisplayPasskey(passkey);
555 pairing->KeysEntered(entered);
558 void BluetoothAdapterChromeOS::RequestConfirmation(
559 const dbus::ObjectPath& device_path,
560 uint32 passkey,
561 const ConfirmationCallback& callback) {
562 DCHECK(IsPresent());
563 DCHECK(agent_.get());
564 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
566 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
567 if (!pairing) {
568 callback.Run(REJECTED);
569 return;
572 pairing->RequestConfirmation(passkey, callback);
575 void BluetoothAdapterChromeOS::RequestAuthorization(
576 const dbus::ObjectPath& device_path,
577 const ConfirmationCallback& callback) {
578 DCHECK(IsPresent());
579 DCHECK(agent_.get());
580 VLOG(1) << device_path.value() << ": RequestAuthorization";
582 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
583 if (!pairing) {
584 callback.Run(REJECTED);
585 return;
588 pairing->RequestAuthorization(callback);
591 void BluetoothAdapterChromeOS::AuthorizeService(
592 const dbus::ObjectPath& device_path,
593 const std::string& uuid,
594 const ConfirmationCallback& callback) {
595 DCHECK(IsPresent());
596 DCHECK(agent_.get());
597 VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
599 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(device_path);
600 if (!device_chromeos) {
601 callback.Run(CANCELLED);
602 return;
605 // We always set paired devices to Trusted, so the only reason that this
606 // method call would ever be called is in the case of a race condition where
607 // our "Set('Trusted', true)" method call is still pending in the Bluetooth
608 // daemon because it's busy handling the incoming connection.
609 if (device_chromeos->IsPaired()) {
610 callback.Run(SUCCESS);
611 return;
614 // TODO(keybuk): reject service authorizations when not paired, determine
615 // whether this is acceptable long-term.
616 LOG(WARNING) << "Rejecting service connection from unpaired device "
617 << device_chromeos->GetAddress() << " for UUID " << uuid;
618 callback.Run(REJECTED);
621 void BluetoothAdapterChromeOS::Cancel() {
622 DCHECK(IsPresent());
623 DCHECK(agent_.get());
624 VLOG(1) << "Cancel";
627 void BluetoothAdapterChromeOS::OnRegisterAgent() {
628 VLOG(1) << "Pairing agent registered, requesting to be made default";
630 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
631 RequestDefaultAgent(
632 dbus::ObjectPath(kAgentPath),
633 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
634 weak_ptr_factory_.GetWeakPtr()),
635 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
636 weak_ptr_factory_.GetWeakPtr()));
639 void BluetoothAdapterChromeOS::OnRegisterAgentError(
640 const std::string& error_name,
641 const std::string& error_message) {
642 // Our agent being already registered isn't an error.
643 if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
644 return;
646 LOG(WARNING) << ": Failed to register pairing agent: "
647 << error_name << ": " << error_message;
650 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
651 VLOG(1) << "Pairing agent now default";
654 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
655 const std::string& error_name,
656 const std::string& error_message) {
657 LOG(WARNING) << ": Failed to make pairing agent default: "
658 << error_name << ": " << error_message;
661 void BluetoothAdapterChromeOS::OnRegisterAudioSink(
662 const device::BluetoothAdapter::AcquiredCallback& callback,
663 const device::BluetoothAudioSink::ErrorCallback& error_callback,
664 scoped_refptr<BluetoothAudioSink> audio_sink) {
665 if (!IsPresent()) {
666 VLOG(1) << "Failed to register audio sink, adapter not present";
667 error_callback.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER);
668 return;
670 DCHECK(audio_sink.get());
671 callback.Run(audio_sink);
674 BluetoothDeviceChromeOS*
675 BluetoothAdapterChromeOS::GetDeviceWithPath(
676 const dbus::ObjectPath& object_path) {
677 if (!IsPresent())
678 return nullptr;
680 for (DevicesMap::iterator iter = devices_.begin(); iter != devices_.end();
681 ++iter) {
682 BluetoothDeviceChromeOS* device_chromeos =
683 static_cast<BluetoothDeviceChromeOS*>(iter->second);
684 if (device_chromeos->object_path() == object_path)
685 return device_chromeos;
688 return nullptr;
691 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
692 const dbus::ObjectPath& object_path) {
693 DCHECK(IsPresent());
694 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
695 if (!device_chromeos) {
696 LOG(WARNING) << "Pairing Agent request for unknown device: "
697 << object_path.value();
698 return nullptr;
701 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
702 if (pairing)
703 return pairing;
705 // The device doesn't have its own pairing context, so this is an incoming
706 // pairing request that should use our best default delegate (if we have one).
707 BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
708 if (!pairing_delegate)
709 return nullptr;
711 return device_chromeos->BeginPairing(pairing_delegate);
714 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
715 DCHECK(!IsPresent());
716 DCHECK(!dbus_is_shutdown_);
717 object_path_ = object_path;
719 VLOG(1) << object_path_.value() << ": using adapter.";
721 VLOG(1) << "Registering pairing agent";
722 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
723 RegisterAgent(
724 dbus::ObjectPath(kAgentPath),
725 bluetooth_agent_manager::kKeyboardDisplayCapability,
726 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
727 weak_ptr_factory_.GetWeakPtr()),
728 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
729 weak_ptr_factory_.GetWeakPtr()));
731 SetDefaultAdapterName();
733 BluetoothAdapterClient::Properties* properties =
734 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
735 GetProperties(object_path_);
737 PresentChanged(true);
739 if (properties->powered.value())
740 PoweredChanged(true);
741 if (properties->discoverable.value())
742 DiscoverableChanged(true);
743 if (properties->discovering.value())
744 DiscoveringChanged(true);
746 std::vector<dbus::ObjectPath> device_paths =
747 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
748 GetDevicesForAdapter(object_path_);
750 for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
751 iter != device_paths.end(); ++iter) {
752 DeviceAdded(*iter);
756 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
757 DCHECK(IsPresent());
758 std::string board = base::SysInfo::GetLsbReleaseBoard();
759 std::string alias;
760 if (board.substr(0, 6) == "stumpy") {
761 alias = "Chromebox";
762 } else if (board.substr(0, 4) == "link") {
763 alias = "Chromebook Pixel";
764 } else {
765 alias = "Chromebook";
768 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
771 void BluetoothAdapterChromeOS::RemoveAdapter() {
772 DCHECK(IsPresent());
773 VLOG(1) << object_path_.value() << ": adapter removed.";
775 BluetoothAdapterClient::Properties* properties =
776 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
777 GetProperties(object_path_);
779 object_path_ = dbus::ObjectPath("");
781 if (properties->powered.value())
782 PoweredChanged(false);
783 if (properties->discoverable.value())
784 DiscoverableChanged(false);
785 if (properties->discovering.value())
786 DiscoveringChanged(false);
788 // Copy the devices list here and clear the original so that when we
789 // send DeviceRemoved(), GetDevices() returns no devices.
790 DevicesMap devices = devices_;
791 devices_.clear();
793 for (DevicesMap::iterator iter = devices.begin();
794 iter != devices.end(); ++iter) {
795 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
796 DeviceRemoved(this, iter->second));
797 delete iter->second;
800 PresentChanged(false);
803 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
804 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
805 AdapterPoweredChanged(this, powered));
808 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
809 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
810 AdapterDiscoverableChanged(this, discoverable));
813 void BluetoothAdapterChromeOS::DiscoveringChanged(
814 bool discovering) {
815 // If the adapter stopped discovery due to a reason other than a request by
816 // us, reset the count to 0.
817 VLOG(1) << "Discovering changed: " << discovering;
818 if (!discovering && !discovery_request_pending_ &&
819 num_discovery_sessions_ > 0) {
820 VLOG(1) << "Marking sessions as inactive.";
821 num_discovery_sessions_ = 0;
822 MarkDiscoverySessionsAsInactive();
824 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
825 AdapterDiscoveringChanged(this, discovering));
828 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
829 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
830 AdapterPresentChanged(this, present));
833 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
834 BluetoothDeviceChromeOS* device) {
835 DCHECK(device);
836 DCHECK(device->adapter_ == this);
838 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
839 DeviceChanged(this, device));
842 void BluetoothAdapterChromeOS::NotifyGattServiceAdded(
843 BluetoothRemoteGattServiceChromeOS* service) {
844 DCHECK_EQ(service->GetAdapter(), this);
845 DCHECK_EQ(
846 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
847 this);
849 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
850 observers_,
851 GattServiceAdded(this, service->GetDevice(), service));
854 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
855 BluetoothRemoteGattServiceChromeOS* service) {
856 DCHECK_EQ(service->GetAdapter(), this);
857 DCHECK_EQ(
858 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
859 this);
861 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
862 observers_,
863 GattServiceRemoved(this, service->GetDevice(), service));
866 void BluetoothAdapterChromeOS::NotifyGattServiceChanged(
867 BluetoothRemoteGattServiceChromeOS* service) {
868 DCHECK_EQ(service->GetAdapter(), this);
870 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
871 observers_,
872 GattServiceChanged(this, service));
875 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
876 BluetoothRemoteGattServiceChromeOS* service) {
877 DCHECK_EQ(service->GetAdapter(), this);
879 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
880 observers_,
881 GattDiscoveryCompleteForService(this, service));
884 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
885 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
886 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
887 characteristic->GetService())->GetAdapter(),
888 this);
890 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
891 observers_,
892 GattCharacteristicAdded(this, characteristic));
895 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
896 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
897 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
898 characteristic->GetService())->GetAdapter(),
899 this);
901 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
902 observers_,
903 GattCharacteristicRemoved(this, characteristic));
906 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
907 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
908 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
909 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
910 this);
912 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
913 observers_,
914 GattDescriptorAdded(this, descriptor));
917 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
918 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
919 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
920 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
921 this);
923 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
924 observers_,
925 GattDescriptorRemoved(this, descriptor));
928 void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged(
929 BluetoothRemoteGattCharacteristicChromeOS* characteristic,
930 const std::vector<uint8>& value) {
931 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
932 characteristic->GetService())->GetAdapter(),
933 this);
935 FOR_EACH_OBSERVER(
936 BluetoothAdapter::Observer,
937 observers_,
938 GattCharacteristicValueChanged(this, characteristic, value));
941 void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
942 BluetoothRemoteGattDescriptorChromeOS* descriptor,
943 const std::vector<uint8>& value) {
944 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
945 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
946 this);
948 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
949 observers_,
950 GattDescriptorValueChanged(this, descriptor, value));
953 void BluetoothAdapterChromeOS::UseProfile(
954 const BluetoothUUID& uuid,
955 const dbus::ObjectPath& device_path,
956 const BluetoothProfileManagerClient::Options& options,
957 BluetoothProfileServiceProvider::Delegate* delegate,
958 const ProfileRegisteredCallback& success_callback,
959 const ErrorCompletionCallback& error_callback) {
960 DCHECK(delegate);
962 if (!IsPresent()) {
963 VLOG(2) << "Adapter not present, erroring out";
964 error_callback.Run("Adapter not present");
965 return;
968 if (profiles_.find(uuid) != profiles_.end()) {
969 // TODO(jamuraa) check that the options are the same and error when they are
970 // not.
971 SetProfileDelegate(uuid, device_path, delegate, success_callback,
972 error_callback);
973 return;
976 if (profile_queues_.find(uuid) == profile_queues_.end()) {
977 BluetoothAdapterProfileChromeOS::Register(
978 uuid, options,
979 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfile, this, uuid),
980 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfileError, this,
981 uuid));
983 profile_queues_[uuid] = new std::vector<RegisterProfileCompletionPair>();
986 profile_queues_[uuid]->push_back(std::make_pair(
987 base::Bind(&BluetoothAdapterChromeOS::SetProfileDelegate, this, uuid,
988 device_path, delegate, success_callback, error_callback),
989 error_callback));
992 void BluetoothAdapterChromeOS::ReleaseProfile(
993 const dbus::ObjectPath& device_path,
994 BluetoothAdapterProfileChromeOS* profile) {
995 VLOG(2) << "Releasing Profile: " << profile->uuid().canonical_value()
996 << " from " << device_path.value();
997 profile->RemoveDelegate(
998 device_path, base::Bind(&BluetoothAdapterChromeOS::RemoveProfile,
999 weak_ptr_factory_.GetWeakPtr(), profile->uuid()));
1002 void BluetoothAdapterChromeOS::RemoveProfile(const BluetoothUUID& uuid) {
1003 VLOG(2) << "Remove Profile: " << uuid.canonical_value();
1005 if (profiles_.find(uuid) != profiles_.end()) {
1006 delete profiles_[uuid];
1007 profiles_.erase(uuid);
1011 void BluetoothAdapterChromeOS::OnRegisterProfile(
1012 const BluetoothUUID& uuid,
1013 scoped_ptr<BluetoothAdapterProfileChromeOS> profile) {
1014 profiles_[uuid] = profile.release();
1016 if (profile_queues_.find(uuid) == profile_queues_.end())
1017 return;
1019 for (auto& it : *profile_queues_[uuid])
1020 it.first.Run();
1021 delete profile_queues_[uuid];
1022 profile_queues_.erase(uuid);
1025 void BluetoothAdapterChromeOS::SetProfileDelegate(
1026 const BluetoothUUID& uuid,
1027 const dbus::ObjectPath& device_path,
1028 BluetoothProfileServiceProvider::Delegate* delegate,
1029 const ProfileRegisteredCallback& success_callback,
1030 const ErrorCompletionCallback& error_callback) {
1031 if (profiles_.find(uuid) == profiles_.end()) {
1032 error_callback.Run("Cannot find profile!");
1033 return;
1036 if (profiles_[uuid]->SetDelegate(device_path, delegate)) {
1037 success_callback.Run(profiles_[uuid]);
1038 return;
1040 // Already set
1041 error_callback.Run(bluetooth_agent_manager::kErrorAlreadyExists);
1044 void BluetoothAdapterChromeOS::OnRegisterProfileError(
1045 const BluetoothUUID& uuid,
1046 const std::string& error_name,
1047 const std::string& error_message) {
1048 VLOG(2) << object_path_.value() << ": Failed to register profile: "
1049 << error_name << ": " << error_message;
1050 if (profile_queues_.find(uuid) == profile_queues_.end())
1051 return;
1053 for (auto& it : *profile_queues_[uuid])
1054 it.second.Run(error_message);
1056 delete profile_queues_[uuid];
1057 profile_queues_.erase(uuid);
1060 void BluetoothAdapterChromeOS::OnSetDiscoverable(
1061 const base::Closure& callback,
1062 const ErrorCallback& error_callback,
1063 bool success) {
1064 if (!IsPresent()) {
1065 error_callback.Run();
1066 return;
1069 // Set the discoverable_timeout property to zero so the adapter remains
1070 // discoverable forever.
1071 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1072 GetProperties(object_path_)->discoverable_timeout.Set(
1074 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
1075 weak_ptr_factory_.GetWeakPtr(),
1076 callback,
1077 error_callback));
1080 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
1081 const base::Closure& callback,
1082 const ErrorCallback& error_callback,
1083 bool success) {
1084 if (IsPresent() && success) {
1085 callback.Run();
1086 } else {
1087 error_callback.Run();
1091 void BluetoothAdapterChromeOS::AddDiscoverySession(
1092 BluetoothDiscoveryFilter* discovery_filter,
1093 const base::Closure& callback,
1094 const ErrorCallback& error_callback) {
1095 if (!IsPresent()) {
1096 error_callback.Run();
1097 return;
1099 VLOG(1) << __func__;
1100 if (discovery_request_pending_) {
1101 // The pending request is either to stop a previous session or to start a
1102 // new one. Either way, queue this one.
1103 DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
1104 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1105 << "request to start a new discovery session.";
1106 discovery_request_queue_.push(
1107 std::make_tuple(discovery_filter, callback, error_callback));
1108 return;
1111 // The adapter is already discovering.
1112 if (num_discovery_sessions_ > 0) {
1113 DCHECK(IsDiscovering());
1114 DCHECK(!discovery_request_pending_);
1115 num_discovery_sessions_++;
1116 SetDiscoveryFilter(BluetoothDiscoveryFilter::Merge(
1117 GetMergedDiscoveryFilter().get(), discovery_filter),
1118 callback, error_callback);
1119 return;
1122 // There are no active discovery sessions.
1123 DCHECK_EQ(num_discovery_sessions_, 0);
1125 if (discovery_filter) {
1126 discovery_request_pending_ = true;
1128 scoped_ptr<BluetoothDiscoveryFilter> df(new BluetoothDiscoveryFilter(
1129 BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL));
1130 df->CopyFrom(*discovery_filter);
1131 SetDiscoveryFilter(
1132 df.Pass(),
1133 base::Bind(&BluetoothAdapterChromeOS::OnPreSetDiscoveryFilter,
1134 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1135 base::Bind(&BluetoothAdapterChromeOS::OnPreSetDiscoveryFilterError,
1136 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1137 return;
1138 } else {
1139 current_filter_.reset();
1142 // This is the first request to start device discovery.
1143 discovery_request_pending_ = true;
1144 DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
1145 object_path_,
1146 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
1147 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1148 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
1149 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1152 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
1153 BluetoothDiscoveryFilter* discovery_filter,
1154 const base::Closure& callback,
1155 const ErrorCallback& error_callback) {
1156 if (!IsPresent()) {
1157 error_callback.Run();
1158 return;
1161 VLOG(1) << __func__;
1162 // There are active sessions other than the one currently being removed.
1163 if (num_discovery_sessions_ > 1) {
1164 DCHECK(IsDiscovering());
1165 DCHECK(!discovery_request_pending_);
1166 num_discovery_sessions_--;
1168 SetDiscoveryFilter(GetMergedDiscoveryFilterMasked(discovery_filter),
1169 callback, error_callback);
1170 return;
1173 // If there is a pending request to BlueZ, then queue this request.
1174 if (discovery_request_pending_) {
1175 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1176 << "request to stop discovery session.";
1177 error_callback.Run();
1178 return;
1181 // There are no active sessions. Return error.
1182 if (num_discovery_sessions_ == 0) {
1183 // TODO(armansito): This should never happen once we have the
1184 // DiscoverySession API. Replace this case with an assert once it's
1185 // the deprecated methods have been removed. (See crbug.com/3445008).
1186 VLOG(1) << "No active discovery sessions. Returning error.";
1187 error_callback.Run();
1188 return;
1191 // There is exactly one active discovery session. Request BlueZ to stop
1192 // discovery.
1193 DCHECK_EQ(num_discovery_sessions_, 1);
1194 discovery_request_pending_ = true;
1195 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1196 StopDiscovery(
1197 object_path_,
1198 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
1199 weak_ptr_factory_.GetWeakPtr(),
1200 callback),
1201 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
1202 weak_ptr_factory_.GetWeakPtr(),
1203 error_callback));
1206 void BluetoothAdapterChromeOS::SetDiscoveryFilter(
1207 scoped_ptr<BluetoothDiscoveryFilter> discovery_filter,
1208 const base::Closure& callback,
1209 const ErrorCallback& error_callback) {
1210 if (!IsPresent()) {
1211 error_callback.Run();
1212 return;
1215 // If old and new filter are equal (null) then don't make request, just call
1216 // succes callback
1217 if (!current_filter_ && !discovery_filter.get()) {
1218 callback.Run();
1219 return;
1222 // If old and new filter are not null and equal then don't make request, just
1223 // call succes callback
1224 if (current_filter_ && discovery_filter &&
1225 current_filter_->Equals(*discovery_filter)) {
1226 callback.Run();
1227 return;
1230 current_filter_.reset(discovery_filter.release());
1232 chromeos::BluetoothAdapterClient::DiscoveryFilter dbus_discovery_filter;
1234 if (current_filter_.get()) {
1235 uint16_t pathloss;
1236 int16_t rssi;
1237 uint8_t transport;
1238 std::set<device::BluetoothUUID> uuids;
1240 if (current_filter_->GetPathloss(&pathloss))
1241 dbus_discovery_filter.pathloss.reset(new uint16_t(pathloss));
1243 if (current_filter_->GetRSSI(&rssi))
1244 dbus_discovery_filter.rssi.reset(new int16_t(rssi));
1246 transport = current_filter_->GetTransport();
1247 if (transport == BluetoothDiscoveryFilter::Transport::TRANSPORT_LE) {
1248 dbus_discovery_filter.transport.reset(new std::string("le"));
1249 } else if (transport ==
1250 BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC) {
1251 dbus_discovery_filter.transport.reset(new std::string("bredr"));
1252 } else if (transport ==
1253 BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL) {
1254 dbus_discovery_filter.transport.reset(new std::string("auto"));
1257 current_filter_->GetUUIDs(uuids);
1258 if (uuids.size()) {
1259 dbus_discovery_filter.uuids =
1260 scoped_ptr<std::vector<std::string>>(new std::vector<std::string>);
1262 for (const auto& it : uuids)
1263 dbus_discovery_filter.uuids.get()->push_back(it.value());
1267 DBusThreadManager::Get()->GetBluetoothAdapterClient()->SetDiscoveryFilter(
1268 object_path_, dbus_discovery_filter,
1269 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoveryFilter,
1270 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1271 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoveryFilterError,
1272 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1275 void BluetoothAdapterChromeOS::OnStartDiscovery(
1276 const base::Closure& callback,
1277 const ErrorCallback& error_callback) {
1278 // Report success on the original request and increment the count.
1279 VLOG(1) << __func__;
1280 DCHECK(discovery_request_pending_);
1281 DCHECK_EQ(num_discovery_sessions_, 0);
1282 discovery_request_pending_ = false;
1283 num_discovery_sessions_++;
1284 if (IsPresent()) {
1285 callback.Run();
1286 } else {
1287 error_callback.Run();
1290 // Try to add a new discovery session for each queued request.
1291 ProcessQueuedDiscoveryRequests();
1294 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
1295 const base::Closure& callback,
1296 const ErrorCallback& error_callback,
1297 const std::string& error_name,
1298 const std::string& error_message) {
1299 LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
1300 << error_name << ": " << error_message;
1302 // Failed to start discovery. This can only happen if the count is at 0.
1303 DCHECK_EQ(num_discovery_sessions_, 0);
1304 DCHECK(discovery_request_pending_);
1305 discovery_request_pending_ = false;
1307 // Discovery request may fail if discovery was previously initiated by Chrome,
1308 // but the session were invalidated due to the discovery state unexpectedly
1309 // changing to false and then back to true. In this case, report success.
1310 if (IsPresent() && error_name == bluetooth_device::kErrorInProgress &&
1311 IsDiscovering()) {
1312 VLOG(1) << "Discovery previously initiated. Reporting success.";
1313 num_discovery_sessions_++;
1314 callback.Run();
1315 } else {
1316 error_callback.Run();
1319 // Try to add a new discovery session for each queued request.
1320 ProcessQueuedDiscoveryRequests();
1323 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
1324 // Report success on the original request and decrement the count.
1325 VLOG(1) << __func__;
1326 DCHECK(discovery_request_pending_);
1327 DCHECK_EQ(num_discovery_sessions_, 1);
1328 discovery_request_pending_ = false;
1329 num_discovery_sessions_--;
1330 callback.Run();
1332 current_filter_.reset();
1334 // Try to add a new discovery session for each queued request.
1335 ProcessQueuedDiscoveryRequests();
1338 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
1339 const ErrorCallback& error_callback,
1340 const std::string& error_name,
1341 const std::string& error_message) {
1342 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
1343 << error_name << ": " << error_message;
1345 // Failed to stop discovery. This can only happen if the count is at 1.
1346 DCHECK(discovery_request_pending_);
1347 DCHECK_EQ(num_discovery_sessions_, 1);
1348 discovery_request_pending_ = false;
1349 error_callback.Run();
1351 // Try to add a new discovery session for each queued request.
1352 ProcessQueuedDiscoveryRequests();
1355 void BluetoothAdapterChromeOS::OnPreSetDiscoveryFilter(
1356 const base::Closure& callback,
1357 const ErrorCallback& error_callback) {
1358 // This is the first request to start device discovery.
1359 DCHECK(discovery_request_pending_);
1360 DCHECK_EQ(num_discovery_sessions_, 0);
1362 DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
1363 object_path_,
1364 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
1365 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1366 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
1367 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1370 void BluetoothAdapterChromeOS::OnPreSetDiscoveryFilterError(
1371 const base::Closure& callback,
1372 const ErrorCallback& error_callback) {
1373 LOG(WARNING) << object_path_.value()
1374 << ": Failed to pre set discovery filter.";
1376 // Failed to start discovery. This can only happen if the count is at 0.
1377 DCHECK_EQ(num_discovery_sessions_, 0);
1378 DCHECK(discovery_request_pending_);
1379 discovery_request_pending_ = false;
1381 error_callback.Run();
1383 // Try to add a new discovery session for each queued request.
1384 ProcessQueuedDiscoveryRequests();
1387 void BluetoothAdapterChromeOS::OnSetDiscoveryFilter(
1388 const base::Closure& callback,
1389 const ErrorCallback& error_callback) {
1390 // Report success on the original request and increment the count.
1391 VLOG(1) << __func__;
1392 if (IsPresent()) {
1393 callback.Run();
1394 } else {
1395 error_callback.Run();
1399 void BluetoothAdapterChromeOS::OnSetDiscoveryFilterError(
1400 const base::Closure& callback,
1401 const ErrorCallback& error_callback,
1402 const std::string& error_name,
1403 const std::string& error_message) {
1404 LOG(WARNING) << object_path_.value()
1405 << ": Failed to set discovery filter: " << error_name << ": "
1406 << error_message;
1408 error_callback.Run();
1410 // Try to add a new discovery session for each queued request.
1411 ProcessQueuedDiscoveryRequests();
1414 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
1415 while (!discovery_request_queue_.empty()) {
1416 VLOG(1) << "Process queued discovery request.";
1417 DiscoveryParamTuple params = discovery_request_queue_.front();
1418 discovery_request_queue_.pop();
1419 AddDiscoverySession(std::get<0>(params), std::get<1>(params),
1420 std::get<2>(params));
1422 // If the queued request resulted in a pending call, then let it
1423 // asynchonously process the remaining queued requests once the pending
1424 // call returns.
1425 if (discovery_request_pending_)
1426 return;
1430 } // namespace chromeos