QUIC - cleanup changes to sync chromium tree with internal source.
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_chromeos.cc
blob597eb6dcbcb12d11085ec22f016e086b3b3f219e
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/thread_task_runner_handle.h"
16 #include "chromeos/dbus/bluetooth_adapter_client.h"
17 #include "chromeos/dbus/bluetooth_agent_manager_client.h"
18 #include "chromeos/dbus/bluetooth_agent_service_provider.h"
19 #include "chromeos/dbus/bluetooth_device_client.h"
20 #include "chromeos/dbus/bluetooth_input_client.h"
21 #include "chromeos/dbus/dbus_thread_manager.h"
22 #include "chromeos/system/devicetype.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_discovery_session_outcome.h"
29 #include "device/bluetooth/bluetooth_pairing_chromeos.h"
30 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
31 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
32 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
33 #include "device/bluetooth/bluetooth_socket_chromeos.h"
34 #include "device/bluetooth/bluetooth_socket_thread.h"
35 #include "device/bluetooth/bluetooth_uuid.h"
36 #include "third_party/cros_system_api/dbus/service_constants.h"
38 using device::BluetoothAdapter;
39 using device::BluetoothAudioSink;
40 using device::BluetoothDevice;
41 using device::BluetoothDiscoveryFilter;
42 using device::BluetoothSocket;
43 using device::BluetoothUUID;
44 using device::UMABluetoothDiscoverySessionOutcome;
46 namespace {
48 // The agent path is relatively meaningless since BlueZ only permits one to
49 // exist per D-Bus connection, it just has to be unique within Chromium.
50 const char kAgentPath[] = "/org/chromium/bluetooth_agent";
52 void OnUnregisterAgentError(const std::string& error_name,
53 const std::string& error_message) {
54 // It's okay if the agent didn't exist, it means we never saw an adapter.
55 if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
56 return;
58 LOG(WARNING) << "Failed to unregister pairing agent: "
59 << error_name << ": " << error_message;
62 UMABluetoothDiscoverySessionOutcome TranslateDiscoveryErrorToUMA(
63 const std::string& error_name) {
64 if (error_name == chromeos::BluetoothAdapterClient::kUnknownAdapterError) {
65 return UMABluetoothDiscoverySessionOutcome::CHROMEOS_DBUS_UNKNOWN_ADAPTER;
66 } else if (error_name == chromeos::BluetoothAdapterClient::kNoResponseError) {
67 return UMABluetoothDiscoverySessionOutcome::CHROMEOS_DBUS_NO_RESPONSE;
68 } else if (error_name == bluetooth_device::kErrorInProgress) {
69 return UMABluetoothDiscoverySessionOutcome::CHROMEOS_DBUS_IN_PROGRESS;
70 } else if (error_name == bluetooth_device::kErrorNotReady) {
71 return UMABluetoothDiscoverySessionOutcome::CHROMEOS_DBUS_NOT_READY;
72 } else if (error_name == bluetooth_device::kErrorFailed) {
73 return UMABluetoothDiscoverySessionOutcome::FAILED;
74 } else {
75 LOG(WARNING) << "Can't histogram DBus error " << error_name;
76 return UMABluetoothDiscoverySessionOutcome::UNKNOWN;
80 } // namespace
82 namespace device {
84 // static
85 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
86 const InitCallback& init_callback) {
87 return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
90 } // namespace device
92 namespace chromeos {
94 // static
95 base::WeakPtr<BluetoothAdapter> BluetoothAdapterChromeOS::CreateAdapter() {
96 BluetoothAdapterChromeOS* adapter = new BluetoothAdapterChromeOS();
97 return adapter->weak_ptr_factory_.GetWeakPtr();
100 void BluetoothAdapterChromeOS::Shutdown() {
101 if (dbus_is_shutdown_)
102 return;
103 DCHECK(DBusThreadManager::IsInitialized())
104 << "Call BluetoothAdapterFactory::Shutdown() before "
105 "DBusThreadManager::Shutdown().";
107 if (IsPresent())
108 RemoveAdapter(); // Also deletes devices_.
109 DCHECK(devices_.empty());
110 // profiles_ is empty because all BluetoothSockets have been notified
111 // that this adapter is disappearing.
112 DCHECK(profiles_.empty());
114 for (auto& it : profile_queues_)
115 delete it.second;
116 profile_queues_.clear();
118 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
119 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
120 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
122 VLOG(1) << "Unregistering pairing agent";
123 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->UnregisterAgent(
124 dbus::ObjectPath(kAgentPath), base::Bind(&base::DoNothing),
125 base::Bind(&OnUnregisterAgentError));
127 agent_.reset();
128 dbus_is_shutdown_ = true;
131 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
132 : dbus_is_shutdown_(false),
133 num_discovery_sessions_(0),
134 discovery_request_pending_(false),
135 weak_ptr_factory_(this) {
136 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
137 socket_thread_ = device::BluetoothSocketThread::Get();
139 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
140 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
141 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
143 // Register the pairing agent.
144 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
145 agent_.reset(BluetoothAgentServiceProvider::Create(
146 system_bus, dbus::ObjectPath(kAgentPath), this));
147 DCHECK(agent_.get());
149 std::vector<dbus::ObjectPath> object_paths =
150 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
152 if (!object_paths.empty()) {
153 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
154 SetAdapter(object_paths[0]);
158 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
159 Shutdown();
162 std::string BluetoothAdapterChromeOS::GetAddress() const {
163 if (!IsPresent())
164 return std::string();
166 BluetoothAdapterClient::Properties* properties =
167 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
168 GetProperties(object_path_);
169 DCHECK(properties);
171 return BluetoothDevice::CanonicalizeAddress(properties->address.value());
174 std::string BluetoothAdapterChromeOS::GetName() const {
175 if (!IsPresent())
176 return std::string();
178 BluetoothAdapterClient::Properties* properties =
179 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
180 GetProperties(object_path_);
181 DCHECK(properties);
183 return properties->alias.value();
186 void BluetoothAdapterChromeOS::SetName(const std::string& name,
187 const base::Closure& callback,
188 const ErrorCallback& error_callback) {
189 if (!IsPresent()) {
190 error_callback.Run();
191 return;
194 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
195 GetProperties(object_path_)->alias.Set(
196 name,
197 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
198 weak_ptr_factory_.GetWeakPtr(),
199 callback,
200 error_callback));
203 bool BluetoothAdapterChromeOS::IsInitialized() const {
204 return true;
207 bool BluetoothAdapterChromeOS::IsPresent() const {
208 return !dbus_is_shutdown_ && !object_path_.value().empty();
211 bool BluetoothAdapterChromeOS::IsPowered() const {
212 if (!IsPresent())
213 return false;
215 BluetoothAdapterClient::Properties* properties =
216 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
217 GetProperties(object_path_);
219 return properties->powered.value();
222 void BluetoothAdapterChromeOS::SetPowered(
223 bool powered,
224 const base::Closure& callback,
225 const ErrorCallback& error_callback) {
226 if (!IsPresent()) {
227 error_callback.Run();
228 return;
231 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
232 GetProperties(object_path_)->powered.Set(
233 powered,
234 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
235 weak_ptr_factory_.GetWeakPtr(),
236 callback,
237 error_callback));
240 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
241 if (!IsPresent())
242 return false;
244 BluetoothAdapterClient::Properties* properties =
245 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
246 GetProperties(object_path_);
248 return properties->discoverable.value();
251 void BluetoothAdapterChromeOS::SetDiscoverable(
252 bool discoverable,
253 const base::Closure& callback,
254 const ErrorCallback& error_callback) {
255 if (!IsPresent()) {
256 error_callback.Run();
257 return;
260 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
261 GetProperties(object_path_)->discoverable.Set(
262 discoverable,
263 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
264 weak_ptr_factory_.GetWeakPtr(),
265 callback,
266 error_callback));
269 bool BluetoothAdapterChromeOS::IsDiscovering() const {
270 if (!IsPresent())
271 return false;
273 BluetoothAdapterClient::Properties* properties =
274 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
275 GetProperties(object_path_);
277 return properties->discovering.value();
280 void BluetoothAdapterChromeOS::CreateRfcommService(
281 const BluetoothUUID& uuid,
282 const ServiceOptions& options,
283 const CreateServiceCallback& callback,
284 const CreateServiceErrorCallback& error_callback) {
285 DCHECK(!dbus_is_shutdown_);
286 VLOG(1) << object_path_.value() << ": Creating RFCOMM service: "
287 << uuid.canonical_value();
288 scoped_refptr<BluetoothSocketChromeOS> socket =
289 BluetoothSocketChromeOS::CreateBluetoothSocket(
290 ui_task_runner_, socket_thread_);
291 socket->Listen(this,
292 BluetoothSocketChromeOS::kRfcomm,
293 uuid,
294 options,
295 base::Bind(callback, socket),
296 error_callback);
299 void BluetoothAdapterChromeOS::CreateL2capService(
300 const BluetoothUUID& uuid,
301 const ServiceOptions& options,
302 const CreateServiceCallback& callback,
303 const CreateServiceErrorCallback& error_callback) {
304 DCHECK(!dbus_is_shutdown_);
305 VLOG(1) << object_path_.value() << ": Creating L2CAP service: "
306 << uuid.canonical_value();
307 scoped_refptr<BluetoothSocketChromeOS> socket =
308 BluetoothSocketChromeOS::CreateBluetoothSocket(
309 ui_task_runner_, socket_thread_);
310 socket->Listen(this,
311 BluetoothSocketChromeOS::kL2cap,
312 uuid,
313 options,
314 base::Bind(callback, socket),
315 error_callback);
318 void BluetoothAdapterChromeOS::RegisterAudioSink(
319 const BluetoothAudioSink::Options& options,
320 const device::BluetoothAdapter::AcquiredCallback& callback,
321 const BluetoothAudioSink::ErrorCallback& error_callback) {
322 VLOG(1) << "Registering audio sink";
323 if (!this->IsPresent()) {
324 error_callback.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER);
325 return;
327 scoped_refptr<BluetoothAudioSinkChromeOS> audio_sink(
328 new BluetoothAudioSinkChromeOS(this));
329 audio_sink->Register(
330 options, base::Bind(&BluetoothAdapterChromeOS::OnRegisterAudioSink,
331 weak_ptr_factory_.GetWeakPtr(), callback,
332 error_callback, audio_sink),
333 error_callback);
336 void BluetoothAdapterChromeOS::RegisterAdvertisement(
337 scoped_ptr<device::BluetoothAdvertisement::Data> advertisement_data,
338 const CreateAdvertisementCallback& callback,
339 const CreateAdvertisementErrorCallback& error_callback) {
340 scoped_refptr<BluetoothAdvertisementChromeOS> advertisement(
341 new BluetoothAdvertisementChromeOS(advertisement_data.Pass(), this));
342 advertisement->Register(base::Bind(callback, advertisement), error_callback);
345 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
346 BluetoothDevice::PairingDelegate* pairing_delegate) {
347 // Check if any device is using the pairing delegate.
348 // If so, clear the pairing context which will make any responses no-ops.
349 for (DevicesMap::iterator iter = devices_.begin();
350 iter != devices_.end(); ++iter) {
351 BluetoothDeviceChromeOS* device_chromeos =
352 static_cast<BluetoothDeviceChromeOS*>(iter->second);
354 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
355 if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
356 device_chromeos->EndPairing();
360 void BluetoothAdapterChromeOS::AdapterAdded(
361 const dbus::ObjectPath& object_path) {
362 // Set the adapter to the newly added adapter only if no adapter is present.
363 if (!IsPresent())
364 SetAdapter(object_path);
367 void BluetoothAdapterChromeOS::AdapterRemoved(
368 const dbus::ObjectPath& object_path) {
369 if (object_path == object_path_)
370 RemoveAdapter();
373 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
374 const dbus::ObjectPath& object_path,
375 const std::string& property_name) {
376 if (object_path != object_path_)
377 return;
378 DCHECK(IsPresent());
380 BluetoothAdapterClient::Properties* properties =
381 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
382 GetProperties(object_path_);
384 if (property_name == properties->powered.name()) {
385 PoweredChanged(properties->powered.value());
386 } else if (property_name == properties->discoverable.name()) {
387 DiscoverableChanged(properties->discoverable.value());
388 } else if (property_name == properties->discovering.name()) {
389 DiscoveringChanged(properties->discovering.value());
393 void BluetoothAdapterChromeOS::DeviceAdded(
394 const dbus::ObjectPath& object_path) {
395 DCHECK(DBusThreadManager::Get());
396 BluetoothDeviceClient::Properties* properties =
397 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
398 GetProperties(object_path);
399 if (!properties || properties->adapter.value() != object_path_)
400 return;
401 DCHECK(IsPresent());
403 BluetoothDeviceChromeOS* device_chromeos =
404 new BluetoothDeviceChromeOS(this,
405 object_path,
406 ui_task_runner_,
407 socket_thread_);
408 DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
410 devices_[device_chromeos->GetAddress()] = device_chromeos;
412 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
413 DeviceAdded(this, device_chromeos));
416 void BluetoothAdapterChromeOS::DeviceRemoved(
417 const dbus::ObjectPath& object_path) {
418 for (DevicesMap::iterator iter = devices_.begin();
419 iter != devices_.end(); ++iter) {
420 BluetoothDeviceChromeOS* device_chromeos =
421 static_cast<BluetoothDeviceChromeOS*>(iter->second);
422 if (device_chromeos->object_path() == object_path) {
423 devices_.erase(iter);
425 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
426 DeviceRemoved(this, device_chromeos));
427 delete device_chromeos;
428 return;
433 void BluetoothAdapterChromeOS::DevicePropertyChanged(
434 const dbus::ObjectPath& object_path,
435 const std::string& property_name) {
436 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
437 if (!device_chromeos)
438 return;
440 BluetoothDeviceClient::Properties* properties =
441 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
442 GetProperties(object_path);
444 if (property_name == properties->bluetooth_class.name() ||
445 property_name == properties->address.name() ||
446 property_name == properties->alias.name() ||
447 property_name == properties->paired.name() ||
448 property_name == properties->trusted.name() ||
449 property_name == properties->connected.name() ||
450 property_name == properties->uuids.name() ||
451 property_name == properties->rssi.name() ||
452 property_name == properties->tx_power.name()) {
453 NotifyDeviceChanged(device_chromeos);
456 // When a device becomes paired, mark it as trusted so that the user does
457 // not need to approve every incoming connection
458 if (property_name == properties->paired.name() &&
459 properties->paired.value() && !properties->trusted.value()) {
460 device_chromeos->SetTrusted();
463 // UMA connection counting
464 if (property_name == properties->connected.name()) {
465 // PlayStation joystick tries to reconnect after disconnection from USB.
466 // If it is still not trusted, set it, so it becomes available on the
467 // list of known devices.
468 if (properties->connected.value() && device_chromeos->IsTrustable() &&
469 !properties->trusted.value())
470 device_chromeos->SetTrusted();
472 int count = 0;
474 for (DevicesMap::iterator iter = devices_.begin();
475 iter != devices_.end(); ++iter) {
476 if (iter->second->IsPaired() && iter->second->IsConnected())
477 ++count;
480 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
484 void BluetoothAdapterChromeOS::InputPropertyChanged(
485 const dbus::ObjectPath& object_path,
486 const std::string& property_name) {
487 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
488 if (!device_chromeos)
489 return;
491 BluetoothInputClient::Properties* properties =
492 DBusThreadManager::Get()->GetBluetoothInputClient()->
493 GetProperties(object_path);
495 // Properties structure can be removed, which triggers a change in the
496 // BluetoothDevice::IsConnectable() property, as does a change in the
497 // actual reconnect_mode property.
498 if (!properties || property_name == properties->reconnect_mode.name()) {
499 NotifyDeviceChanged(device_chromeos);
503 void BluetoothAdapterChromeOS::Released() {
504 VLOG(1) << "Release";
505 if (!IsPresent())
506 return;
507 DCHECK(agent_.get());
509 // Called after we unregister the pairing agent, e.g. when changing I/O
510 // capabilities. Nothing much to be done right now.
513 void BluetoothAdapterChromeOS::RequestPinCode(
514 const dbus::ObjectPath& device_path,
515 const PinCodeCallback& callback) {
516 DCHECK(IsPresent());
517 DCHECK(agent_.get());
518 VLOG(1) << device_path.value() << ": RequestPinCode";
520 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
521 if (!pairing) {
522 callback.Run(REJECTED, "");
523 return;
526 pairing->RequestPinCode(callback);
529 void BluetoothAdapterChromeOS::DisplayPinCode(
530 const dbus::ObjectPath& device_path,
531 const std::string& pincode) {
532 DCHECK(IsPresent());
533 DCHECK(agent_.get());
534 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
536 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
537 if (!pairing)
538 return;
540 pairing->DisplayPinCode(pincode);
543 void BluetoothAdapterChromeOS::RequestPasskey(
544 const dbus::ObjectPath& device_path,
545 const PasskeyCallback& callback) {
546 DCHECK(IsPresent());
547 DCHECK(agent_.get());
548 VLOG(1) << device_path.value() << ": RequestPasskey";
550 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
551 if (!pairing) {
552 callback.Run(REJECTED, 0);
553 return;
556 pairing->RequestPasskey(callback);
559 void BluetoothAdapterChromeOS::DisplayPasskey(
560 const dbus::ObjectPath& device_path,
561 uint32 passkey,
562 uint16 entered) {
563 DCHECK(IsPresent());
564 DCHECK(agent_.get());
565 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
566 << " (" << entered << " entered)";
568 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
569 if (!pairing)
570 return;
572 if (entered == 0)
573 pairing->DisplayPasskey(passkey);
575 pairing->KeysEntered(entered);
578 void BluetoothAdapterChromeOS::RequestConfirmation(
579 const dbus::ObjectPath& device_path,
580 uint32 passkey,
581 const ConfirmationCallback& callback) {
582 DCHECK(IsPresent());
583 DCHECK(agent_.get());
584 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
586 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
587 if (!pairing) {
588 callback.Run(REJECTED);
589 return;
592 pairing->RequestConfirmation(passkey, callback);
595 void BluetoothAdapterChromeOS::RequestAuthorization(
596 const dbus::ObjectPath& device_path,
597 const ConfirmationCallback& callback) {
598 DCHECK(IsPresent());
599 DCHECK(agent_.get());
600 VLOG(1) << device_path.value() << ": RequestAuthorization";
602 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
603 if (!pairing) {
604 callback.Run(REJECTED);
605 return;
608 pairing->RequestAuthorization(callback);
611 void BluetoothAdapterChromeOS::AuthorizeService(
612 const dbus::ObjectPath& device_path,
613 const std::string& uuid,
614 const ConfirmationCallback& callback) {
615 DCHECK(IsPresent());
616 DCHECK(agent_.get());
617 VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
619 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(device_path);
620 if (!device_chromeos) {
621 callback.Run(CANCELLED);
622 return;
625 // We always set paired devices to Trusted, so the only reason that this
626 // method call would ever be called is in the case of a race condition where
627 // our "Set('Trusted', true)" method call is still pending in the Bluetooth
628 // daemon because it's busy handling the incoming connection.
629 if (device_chromeos->IsPaired()) {
630 callback.Run(SUCCESS);
631 return;
634 // TODO(keybuk): reject service authorizations when not paired, determine
635 // whether this is acceptable long-term.
636 LOG(WARNING) << "Rejecting service connection from unpaired device "
637 << device_chromeos->GetAddress() << " for UUID " << uuid;
638 callback.Run(REJECTED);
641 void BluetoothAdapterChromeOS::Cancel() {
642 DCHECK(IsPresent());
643 DCHECK(agent_.get());
644 VLOG(1) << "Cancel";
647 void BluetoothAdapterChromeOS::OnRegisterAgent() {
648 VLOG(1) << "Pairing agent registered, requesting to be made default";
650 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
651 RequestDefaultAgent(
652 dbus::ObjectPath(kAgentPath),
653 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
654 weak_ptr_factory_.GetWeakPtr()),
655 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
656 weak_ptr_factory_.GetWeakPtr()));
659 void BluetoothAdapterChromeOS::OnRegisterAgentError(
660 const std::string& error_name,
661 const std::string& error_message) {
662 // Our agent being already registered isn't an error.
663 if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
664 return;
666 LOG(WARNING) << ": Failed to register pairing agent: "
667 << error_name << ": " << error_message;
670 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
671 VLOG(1) << "Pairing agent now default";
674 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
675 const std::string& error_name,
676 const std::string& error_message) {
677 LOG(WARNING) << ": Failed to make pairing agent default: "
678 << error_name << ": " << error_message;
681 void BluetoothAdapterChromeOS::OnRegisterAudioSink(
682 const device::BluetoothAdapter::AcquiredCallback& callback,
683 const device::BluetoothAudioSink::ErrorCallback& error_callback,
684 scoped_refptr<BluetoothAudioSink> audio_sink) {
685 if (!IsPresent()) {
686 VLOG(1) << "Failed to register audio sink, adapter not present";
687 error_callback.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER);
688 return;
690 DCHECK(audio_sink.get());
691 callback.Run(audio_sink);
694 BluetoothDeviceChromeOS*
695 BluetoothAdapterChromeOS::GetDeviceWithPath(
696 const dbus::ObjectPath& object_path) {
697 if (!IsPresent())
698 return nullptr;
700 for (DevicesMap::iterator iter = devices_.begin(); iter != devices_.end();
701 ++iter) {
702 BluetoothDeviceChromeOS* device_chromeos =
703 static_cast<BluetoothDeviceChromeOS*>(iter->second);
704 if (device_chromeos->object_path() == object_path)
705 return device_chromeos;
708 return nullptr;
711 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
712 const dbus::ObjectPath& object_path) {
713 DCHECK(IsPresent());
714 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
715 if (!device_chromeos) {
716 LOG(WARNING) << "Pairing Agent request for unknown device: "
717 << object_path.value();
718 return nullptr;
721 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
722 if (pairing)
723 return pairing;
725 // The device doesn't have its own pairing context, so this is an incoming
726 // pairing request that should use our best default delegate (if we have one).
727 BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
728 if (!pairing_delegate)
729 return nullptr;
731 return device_chromeos->BeginPairing(pairing_delegate);
734 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
735 DCHECK(!IsPresent());
736 DCHECK(!dbus_is_shutdown_);
737 object_path_ = object_path;
739 VLOG(1) << object_path_.value() << ": using adapter.";
741 VLOG(1) << "Registering pairing agent";
742 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
743 RegisterAgent(
744 dbus::ObjectPath(kAgentPath),
745 bluetooth_agent_manager::kKeyboardDisplayCapability,
746 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
747 weak_ptr_factory_.GetWeakPtr()),
748 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
749 weak_ptr_factory_.GetWeakPtr()));
751 SetDefaultAdapterName();
753 BluetoothAdapterClient::Properties* properties =
754 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
755 GetProperties(object_path_);
757 PresentChanged(true);
759 if (properties->powered.value())
760 PoweredChanged(true);
761 if (properties->discoverable.value())
762 DiscoverableChanged(true);
763 if (properties->discovering.value())
764 DiscoveringChanged(true);
766 std::vector<dbus::ObjectPath> device_paths =
767 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
768 GetDevicesForAdapter(object_path_);
770 for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
771 iter != device_paths.end(); ++iter) {
772 DeviceAdded(*iter);
776 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
777 DCHECK(IsPresent());
779 std::string alias;
780 switch (chromeos::GetDeviceType()) {
781 case DeviceType::kChromebase:
782 alias = "Chromebase";
783 break;
784 case DeviceType::kChromebit:
785 alias = "Chromebit";
786 break;
787 case DeviceType::kChromebook:
788 alias = "Chromebook";
789 break;
790 case DeviceType::kChromebox:
791 alias = "Chromebox";
792 break;
793 case DeviceType::kUnknown:
794 alias = "Chromebook";
795 break;
798 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
801 void BluetoothAdapterChromeOS::RemoveAdapter() {
802 DCHECK(IsPresent());
803 VLOG(1) << object_path_.value() << ": adapter removed.";
805 BluetoothAdapterClient::Properties* properties =
806 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
807 GetProperties(object_path_);
809 object_path_ = dbus::ObjectPath("");
811 if (properties->powered.value())
812 PoweredChanged(false);
813 if (properties->discoverable.value())
814 DiscoverableChanged(false);
815 if (properties->discovering.value())
816 DiscoveringChanged(false);
818 // Copy the devices list here and clear the original so that when we
819 // send DeviceRemoved(), GetDevices() returns no devices.
820 DevicesMap devices = devices_;
821 devices_.clear();
823 for (DevicesMap::iterator iter = devices.begin();
824 iter != devices.end(); ++iter) {
825 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
826 DeviceRemoved(this, iter->second));
827 delete iter->second;
830 PresentChanged(false);
833 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
834 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
835 AdapterPoweredChanged(this, powered));
838 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
839 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
840 AdapterDiscoverableChanged(this, discoverable));
843 void BluetoothAdapterChromeOS::DiscoveringChanged(
844 bool discovering) {
845 // If the adapter stopped discovery due to a reason other than a request by
846 // us, reset the count to 0.
847 VLOG(1) << "Discovering changed: " << discovering;
848 if (!discovering && !discovery_request_pending_ &&
849 num_discovery_sessions_ > 0) {
850 VLOG(1) << "Marking sessions as inactive.";
851 num_discovery_sessions_ = 0;
852 MarkDiscoverySessionsAsInactive();
854 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
855 AdapterDiscoveringChanged(this, discovering));
858 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
859 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
860 AdapterPresentChanged(this, present));
863 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
864 BluetoothDeviceChromeOS* device) {
865 DCHECK(device);
866 DCHECK(device->adapter_ == this);
868 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
869 DeviceChanged(this, device));
872 void BluetoothAdapterChromeOS::NotifyGattServiceAdded(
873 BluetoothRemoteGattServiceChromeOS* service) {
874 DCHECK_EQ(service->GetAdapter(), this);
875 DCHECK_EQ(
876 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
877 this);
879 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
880 observers_,
881 GattServiceAdded(this, service->GetDevice(), service));
884 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
885 BluetoothRemoteGattServiceChromeOS* service) {
886 DCHECK_EQ(service->GetAdapter(), this);
887 DCHECK_EQ(
888 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
889 this);
891 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
892 observers_,
893 GattServiceRemoved(this, service->GetDevice(), service));
896 void BluetoothAdapterChromeOS::NotifyGattServiceChanged(
897 BluetoothRemoteGattServiceChromeOS* service) {
898 DCHECK_EQ(service->GetAdapter(), this);
900 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
901 observers_,
902 GattServiceChanged(this, service));
905 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
906 BluetoothRemoteGattServiceChromeOS* service) {
907 DCHECK_EQ(service->GetAdapter(), this);
909 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
910 observers_,
911 GattDiscoveryCompleteForService(this, service));
914 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
915 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
916 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
917 characteristic->GetService())->GetAdapter(),
918 this);
920 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
921 observers_,
922 GattCharacteristicAdded(this, characteristic));
925 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
926 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
927 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
928 characteristic->GetService())->GetAdapter(),
929 this);
931 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
932 observers_,
933 GattCharacteristicRemoved(this, characteristic));
936 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
937 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
938 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
939 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
940 this);
942 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
943 observers_,
944 GattDescriptorAdded(this, descriptor));
947 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
948 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
949 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
950 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
951 this);
953 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
954 observers_,
955 GattDescriptorRemoved(this, descriptor));
958 void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged(
959 BluetoothRemoteGattCharacteristicChromeOS* characteristic,
960 const std::vector<uint8>& value) {
961 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
962 characteristic->GetService())->GetAdapter(),
963 this);
965 FOR_EACH_OBSERVER(
966 BluetoothAdapter::Observer,
967 observers_,
968 GattCharacteristicValueChanged(this, characteristic, value));
971 void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
972 BluetoothRemoteGattDescriptorChromeOS* descriptor,
973 const std::vector<uint8>& value) {
974 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
975 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
976 this);
978 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
979 observers_,
980 GattDescriptorValueChanged(this, descriptor, value));
983 void BluetoothAdapterChromeOS::UseProfile(
984 const BluetoothUUID& uuid,
985 const dbus::ObjectPath& device_path,
986 const BluetoothProfileManagerClient::Options& options,
987 BluetoothProfileServiceProvider::Delegate* delegate,
988 const ProfileRegisteredCallback& success_callback,
989 const ErrorCompletionCallback& error_callback) {
990 DCHECK(delegate);
992 if (!IsPresent()) {
993 VLOG(2) << "Adapter not present, erroring out";
994 error_callback.Run("Adapter not present");
995 return;
998 if (profiles_.find(uuid) != profiles_.end()) {
999 // TODO(jamuraa) check that the options are the same and error when they are
1000 // not.
1001 SetProfileDelegate(uuid, device_path, delegate, success_callback,
1002 error_callback);
1003 return;
1006 if (profile_queues_.find(uuid) == profile_queues_.end()) {
1007 BluetoothAdapterProfileChromeOS::Register(
1008 uuid, options,
1009 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfile, this, uuid),
1010 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfileError, this,
1011 uuid));
1013 profile_queues_[uuid] = new std::vector<RegisterProfileCompletionPair>();
1016 profile_queues_[uuid]->push_back(std::make_pair(
1017 base::Bind(&BluetoothAdapterChromeOS::SetProfileDelegate, this, uuid,
1018 device_path, delegate, success_callback, error_callback),
1019 error_callback));
1022 void BluetoothAdapterChromeOS::ReleaseProfile(
1023 const dbus::ObjectPath& device_path,
1024 BluetoothAdapterProfileChromeOS* profile) {
1025 VLOG(2) << "Releasing Profile: " << profile->uuid().canonical_value()
1026 << " from " << device_path.value();
1027 profile->RemoveDelegate(
1028 device_path, base::Bind(&BluetoothAdapterChromeOS::RemoveProfile,
1029 weak_ptr_factory_.GetWeakPtr(), profile->uuid()));
1032 void BluetoothAdapterChromeOS::RemoveProfile(const BluetoothUUID& uuid) {
1033 VLOG(2) << "Remove Profile: " << uuid.canonical_value();
1035 if (profiles_.find(uuid) != profiles_.end()) {
1036 delete profiles_[uuid];
1037 profiles_.erase(uuid);
1041 void BluetoothAdapterChromeOS::OnRegisterProfile(
1042 const BluetoothUUID& uuid,
1043 scoped_ptr<BluetoothAdapterProfileChromeOS> profile) {
1044 profiles_[uuid] = profile.release();
1046 if (profile_queues_.find(uuid) == profile_queues_.end())
1047 return;
1049 for (auto& it : *profile_queues_[uuid])
1050 it.first.Run();
1051 delete profile_queues_[uuid];
1052 profile_queues_.erase(uuid);
1055 void BluetoothAdapterChromeOS::SetProfileDelegate(
1056 const BluetoothUUID& uuid,
1057 const dbus::ObjectPath& device_path,
1058 BluetoothProfileServiceProvider::Delegate* delegate,
1059 const ProfileRegisteredCallback& success_callback,
1060 const ErrorCompletionCallback& error_callback) {
1061 if (profiles_.find(uuid) == profiles_.end()) {
1062 error_callback.Run("Cannot find profile!");
1063 return;
1066 if (profiles_[uuid]->SetDelegate(device_path, delegate)) {
1067 success_callback.Run(profiles_[uuid]);
1068 return;
1070 // Already set
1071 error_callback.Run(bluetooth_agent_manager::kErrorAlreadyExists);
1074 void BluetoothAdapterChromeOS::OnRegisterProfileError(
1075 const BluetoothUUID& uuid,
1076 const std::string& error_name,
1077 const std::string& error_message) {
1078 VLOG(2) << object_path_.value() << ": Failed to register profile: "
1079 << error_name << ": " << error_message;
1080 if (profile_queues_.find(uuid) == profile_queues_.end())
1081 return;
1083 for (auto& it : *profile_queues_[uuid])
1084 it.second.Run(error_message);
1086 delete profile_queues_[uuid];
1087 profile_queues_.erase(uuid);
1090 void BluetoothAdapterChromeOS::OnSetDiscoverable(
1091 const base::Closure& callback,
1092 const ErrorCallback& error_callback,
1093 bool success) {
1094 if (!IsPresent()) {
1095 error_callback.Run();
1096 return;
1099 // Set the discoverable_timeout property to zero so the adapter remains
1100 // discoverable forever.
1101 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1102 GetProperties(object_path_)->discoverable_timeout.Set(
1104 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
1105 weak_ptr_factory_.GetWeakPtr(),
1106 callback,
1107 error_callback));
1110 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
1111 const base::Closure& callback,
1112 const ErrorCallback& error_callback,
1113 bool success) {
1114 if (IsPresent() && success) {
1115 callback.Run();
1116 } else {
1117 error_callback.Run();
1121 void BluetoothAdapterChromeOS::AddDiscoverySession(
1122 BluetoothDiscoveryFilter* discovery_filter,
1123 const base::Closure& callback,
1124 const DiscoverySessionErrorCallback& error_callback) {
1125 if (!IsPresent()) {
1126 error_callback.Run(
1127 UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT);
1128 return;
1130 VLOG(1) << __func__;
1131 if (discovery_request_pending_) {
1132 // The pending request is either to stop a previous session or to start a
1133 // new one. Either way, queue this one.
1134 DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
1135 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1136 << "request to start a new discovery session.";
1137 discovery_request_queue_.push(
1138 std::make_tuple(discovery_filter, callback, error_callback));
1139 return;
1142 // The adapter is already discovering.
1143 if (num_discovery_sessions_ > 0) {
1144 DCHECK(IsDiscovering());
1145 DCHECK(!discovery_request_pending_);
1146 num_discovery_sessions_++;
1147 SetDiscoveryFilter(BluetoothDiscoveryFilter::Merge(
1148 GetMergedDiscoveryFilter().get(), discovery_filter),
1149 callback, error_callback);
1150 return;
1153 // There are no active discovery sessions.
1154 DCHECK_EQ(num_discovery_sessions_, 0);
1156 if (discovery_filter) {
1157 discovery_request_pending_ = true;
1159 scoped_ptr<BluetoothDiscoveryFilter> df(new BluetoothDiscoveryFilter(
1160 BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL));
1161 df->CopyFrom(*discovery_filter);
1162 SetDiscoveryFilter(
1163 df.Pass(),
1164 base::Bind(&BluetoothAdapterChromeOS::OnPreSetDiscoveryFilter,
1165 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1166 base::Bind(&BluetoothAdapterChromeOS::OnPreSetDiscoveryFilterError,
1167 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1168 return;
1169 } else {
1170 current_filter_.reset();
1173 // This is the first request to start device discovery.
1174 discovery_request_pending_ = true;
1175 DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
1176 object_path_,
1177 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
1178 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1179 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
1180 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1183 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
1184 BluetoothDiscoveryFilter* discovery_filter,
1185 const base::Closure& callback,
1186 const DiscoverySessionErrorCallback& error_callback) {
1187 if (!IsPresent()) {
1188 error_callback.Run(
1189 UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT);
1190 return;
1193 VLOG(1) << __func__;
1194 // There are active sessions other than the one currently being removed.
1195 if (num_discovery_sessions_ > 1) {
1196 DCHECK(IsDiscovering());
1197 DCHECK(!discovery_request_pending_);
1198 num_discovery_sessions_--;
1200 SetDiscoveryFilter(GetMergedDiscoveryFilterMasked(discovery_filter),
1201 callback, error_callback);
1202 return;
1205 // If there is a pending request to BlueZ, then queue this request.
1206 if (discovery_request_pending_) {
1207 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1208 << "request to stop discovery session.";
1209 error_callback.Run(
1210 UMABluetoothDiscoverySessionOutcome::REMOVE_WITH_PENDING_REQUEST);
1211 return;
1214 // There are no active sessions. Return error.
1215 if (num_discovery_sessions_ == 0) {
1216 // TODO(armansito): This should never happen once we have the
1217 // DiscoverySession API. Replace this case with an assert once it's
1218 // the deprecated methods have been removed. (See crbug.com/3445008).
1219 VLOG(1) << "No active discovery sessions. Returning error.";
1220 error_callback.Run(
1221 UMABluetoothDiscoverySessionOutcome::ACTIVE_SESSION_NOT_IN_ADAPTER);
1222 return;
1225 // There is exactly one active discovery session. Request BlueZ to stop
1226 // discovery.
1227 DCHECK_EQ(num_discovery_sessions_, 1);
1228 discovery_request_pending_ = true;
1229 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1230 StopDiscovery(
1231 object_path_,
1232 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
1233 weak_ptr_factory_.GetWeakPtr(),
1234 callback),
1235 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
1236 weak_ptr_factory_.GetWeakPtr(),
1237 error_callback));
1240 void BluetoothAdapterChromeOS::SetDiscoveryFilter(
1241 scoped_ptr<BluetoothDiscoveryFilter> discovery_filter,
1242 const base::Closure& callback,
1243 const DiscoverySessionErrorCallback& error_callback) {
1244 if (!IsPresent()) {
1245 error_callback.Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
1246 return;
1249 // If old and new filter are equal (null) then don't make request, just call
1250 // succes callback
1251 if (!current_filter_ && !discovery_filter.get()) {
1252 callback.Run();
1253 return;
1256 // If old and new filter are not null and equal then don't make request, just
1257 // call succes callback
1258 if (current_filter_ && discovery_filter &&
1259 current_filter_->Equals(*discovery_filter)) {
1260 callback.Run();
1261 return;
1264 current_filter_.reset(discovery_filter.release());
1266 chromeos::BluetoothAdapterClient::DiscoveryFilter dbus_discovery_filter;
1268 if (current_filter_.get()) {
1269 uint16_t pathloss;
1270 int16_t rssi;
1271 uint8_t transport;
1272 std::set<device::BluetoothUUID> uuids;
1274 if (current_filter_->GetPathloss(&pathloss))
1275 dbus_discovery_filter.pathloss.reset(new uint16_t(pathloss));
1277 if (current_filter_->GetRSSI(&rssi))
1278 dbus_discovery_filter.rssi.reset(new int16_t(rssi));
1280 transport = current_filter_->GetTransport();
1281 if (transport == BluetoothDiscoveryFilter::Transport::TRANSPORT_LE) {
1282 dbus_discovery_filter.transport.reset(new std::string("le"));
1283 } else if (transport ==
1284 BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC) {
1285 dbus_discovery_filter.transport.reset(new std::string("bredr"));
1286 } else if (transport ==
1287 BluetoothDiscoveryFilter::Transport::TRANSPORT_DUAL) {
1288 dbus_discovery_filter.transport.reset(new std::string("auto"));
1291 current_filter_->GetUUIDs(uuids);
1292 if (uuids.size()) {
1293 dbus_discovery_filter.uuids =
1294 scoped_ptr<std::vector<std::string>>(new std::vector<std::string>);
1296 for (const auto& it : uuids)
1297 dbus_discovery_filter.uuids.get()->push_back(it.value());
1301 DBusThreadManager::Get()->GetBluetoothAdapterClient()->SetDiscoveryFilter(
1302 object_path_, dbus_discovery_filter,
1303 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoveryFilter,
1304 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1305 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoveryFilterError,
1306 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1309 void BluetoothAdapterChromeOS::OnStartDiscovery(
1310 const base::Closure& callback,
1311 const DiscoverySessionErrorCallback& error_callback) {
1312 // Report success on the original request and increment the count.
1313 VLOG(1) << __func__;
1314 DCHECK(discovery_request_pending_);
1315 DCHECK_EQ(num_discovery_sessions_, 0);
1316 discovery_request_pending_ = false;
1317 num_discovery_sessions_++;
1318 if (IsPresent()) {
1319 callback.Run();
1320 } else {
1321 error_callback.Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
1324 // Try to add a new discovery session for each queued request.
1325 ProcessQueuedDiscoveryRequests();
1328 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
1329 const base::Closure& callback,
1330 const DiscoverySessionErrorCallback& error_callback,
1331 const std::string& error_name,
1332 const std::string& error_message) {
1333 LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
1334 << error_name << ": " << error_message;
1336 // Failed to start discovery. This can only happen if the count is at 0.
1337 DCHECK_EQ(num_discovery_sessions_, 0);
1338 DCHECK(discovery_request_pending_);
1339 discovery_request_pending_ = false;
1341 // Discovery request may fail if discovery was previously initiated by Chrome,
1342 // but the session were invalidated due to the discovery state unexpectedly
1343 // changing to false and then back to true. In this case, report success.
1344 if (IsPresent() && error_name == bluetooth_device::kErrorInProgress &&
1345 IsDiscovering()) {
1346 VLOG(1) << "Discovery previously initiated. Reporting success.";
1347 num_discovery_sessions_++;
1348 callback.Run();
1349 } else {
1350 error_callback.Run(TranslateDiscoveryErrorToUMA(error_name));
1353 // Try to add a new discovery session for each queued request.
1354 ProcessQueuedDiscoveryRequests();
1357 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
1358 // Report success on the original request and decrement the count.
1359 VLOG(1) << __func__;
1360 DCHECK(discovery_request_pending_);
1361 DCHECK_EQ(num_discovery_sessions_, 1);
1362 discovery_request_pending_ = false;
1363 num_discovery_sessions_--;
1364 callback.Run();
1366 current_filter_.reset();
1368 // Try to add a new discovery session for each queued request.
1369 ProcessQueuedDiscoveryRequests();
1372 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
1373 const DiscoverySessionErrorCallback& error_callback,
1374 const std::string& error_name,
1375 const std::string& error_message) {
1376 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
1377 << error_name << ": " << error_message;
1379 // Failed to stop discovery. This can only happen if the count is at 1.
1380 DCHECK(discovery_request_pending_);
1381 DCHECK_EQ(num_discovery_sessions_, 1);
1382 discovery_request_pending_ = false;
1383 error_callback.Run(TranslateDiscoveryErrorToUMA(error_name));
1385 // Try to add a new discovery session for each queued request.
1386 ProcessQueuedDiscoveryRequests();
1389 void BluetoothAdapterChromeOS::OnPreSetDiscoveryFilter(
1390 const base::Closure& callback,
1391 const DiscoverySessionErrorCallback& error_callback) {
1392 // This is the first request to start device discovery.
1393 DCHECK(discovery_request_pending_);
1394 DCHECK_EQ(num_discovery_sessions_, 0);
1396 DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
1397 object_path_,
1398 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
1399 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1400 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
1401 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1404 void BluetoothAdapterChromeOS::OnPreSetDiscoveryFilterError(
1405 const base::Closure& callback,
1406 const DiscoverySessionErrorCallback& error_callback,
1407 UMABluetoothDiscoverySessionOutcome outcome) {
1408 LOG(WARNING) << object_path_.value()
1409 << ": Failed to pre set discovery filter.";
1411 // Failed to start discovery. This can only happen if the count is at 0.
1412 DCHECK_EQ(num_discovery_sessions_, 0);
1413 DCHECK(discovery_request_pending_);
1414 discovery_request_pending_ = false;
1416 error_callback.Run(outcome);
1418 // Try to add a new discovery session for each queued request.
1419 ProcessQueuedDiscoveryRequests();
1422 void BluetoothAdapterChromeOS::OnSetDiscoveryFilter(
1423 const base::Closure& callback,
1424 const DiscoverySessionErrorCallback& error_callback) {
1425 // Report success on the original request and increment the count.
1426 VLOG(1) << __func__;
1427 if (IsPresent()) {
1428 callback.Run();
1429 } else {
1430 error_callback.Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
1434 void BluetoothAdapterChromeOS::OnSetDiscoveryFilterError(
1435 const base::Closure& callback,
1436 const DiscoverySessionErrorCallback& error_callback,
1437 const std::string& error_name,
1438 const std::string& error_message) {
1439 LOG(WARNING) << object_path_.value()
1440 << ": Failed to set discovery filter: " << error_name << ": "
1441 << error_message;
1443 UMABluetoothDiscoverySessionOutcome outcome =
1444 TranslateDiscoveryErrorToUMA(error_name);
1445 if (outcome == UMABluetoothDiscoverySessionOutcome::FAILED) {
1446 // bluez/doc/adapter-api.txt says "Failed" is returned from
1447 // SetDiscoveryFilter when the controller doesn't support the requested
1448 // transport.
1449 outcome = UMABluetoothDiscoverySessionOutcome::
1450 CHROMEOS_DBUS_FAILED_MAYBE_UNSUPPORTED_TRANSPORT;
1452 error_callback.Run(outcome);
1454 // Try to add a new discovery session for each queued request.
1455 ProcessQueuedDiscoveryRequests();
1458 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
1459 while (!discovery_request_queue_.empty()) {
1460 VLOG(1) << "Process queued discovery request.";
1461 DiscoveryParamTuple params = discovery_request_queue_.front();
1462 discovery_request_queue_.pop();
1463 AddDiscoverySession(std::get<0>(params), std::get<1>(params),
1464 std::get<2>(params));
1466 // If the queued request resulted in a pending call, then let it
1467 // asynchonously process the remaining queued requests once the pending
1468 // call returns.
1469 if (discovery_request_pending_)
1470 return;
1474 } // namespace chromeos