ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_chromeos.cc
blobdb9cb9089f3c3bf67b7e4334632cb1bfced00070
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_audio_sink_chromeos.h"
25 #include "device/bluetooth/bluetooth_device.h"
26 #include "device/bluetooth/bluetooth_device_chromeos.h"
27 #include "device/bluetooth/bluetooth_pairing_chromeos.h"
28 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
29 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
30 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
31 #include "device/bluetooth/bluetooth_socket_chromeos.h"
32 #include "device/bluetooth/bluetooth_socket_thread.h"
33 #include "device/bluetooth/bluetooth_uuid.h"
34 #include "third_party/cros_system_api/dbus/service_constants.h"
36 using device::BluetoothAdapter;
37 using device::BluetoothAudioSink;
38 using device::BluetoothDevice;
39 using device::BluetoothSocket;
40 using device::BluetoothUUID;
42 namespace {
44 // The agent path is relatively meaningless since BlueZ only permits one to
45 // exist per D-Bus connection, it just has to be unique within Chromium.
46 const char kAgentPath[] = "/org/chromium/bluetooth_agent";
48 void OnUnregisterAgentError(const std::string& error_name,
49 const std::string& error_message) {
50 // It's okay if the agent didn't exist, it means we never saw an adapter.
51 if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
52 return;
54 LOG(WARNING) << "Failed to unregister pairing agent: "
55 << error_name << ": " << error_message;
58 } // namespace
60 namespace device {
62 // static
63 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
64 const InitCallback& init_callback) {
65 return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
70 namespace chromeos {
72 // static
73 base::WeakPtr<BluetoothAdapter> BluetoothAdapterChromeOS::CreateAdapter() {
74 BluetoothAdapterChromeOS* adapter = new BluetoothAdapterChromeOS();
75 return adapter->weak_ptr_factory_.GetWeakPtr();
78 void BluetoothAdapterChromeOS::Shutdown() {
79 if (dbus_is_shutdown_)
80 return;
81 DCHECK(DBusThreadManager::IsInitialized())
82 << "Call BluetoothAdapterFactory::Shutdown() before "
83 "DBusThreadManager::Shutdown().";
85 if (IsPresent())
86 RemoveAdapter(); // Also deletes devices_.
87 DCHECK(devices_.empty());
88 // profiles_ should be empty because all BluetoothSockets have been signaled
89 // that this adapter is disappearing.
90 DCHECK(profiles_.empty());
92 for (auto& it : profile_queues_)
93 delete it.second;
94 profile_queues_.clear();
96 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
97 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
98 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
100 VLOG(1) << "Unregistering pairing agent";
101 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->UnregisterAgent(
102 dbus::ObjectPath(kAgentPath), base::Bind(&base::DoNothing),
103 base::Bind(&OnUnregisterAgentError));
105 agent_.reset();
106 dbus_is_shutdown_ = true;
109 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
110 : dbus_is_shutdown_(false),
111 num_discovery_sessions_(0),
112 discovery_request_pending_(false),
113 weak_ptr_factory_(this) {
114 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
115 socket_thread_ = device::BluetoothSocketThread::Get();
117 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
118 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
119 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
121 // Register the pairing agent.
122 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
123 agent_.reset(BluetoothAgentServiceProvider::Create(
124 system_bus, dbus::ObjectPath(kAgentPath), this));
125 DCHECK(agent_.get());
127 std::vector<dbus::ObjectPath> object_paths =
128 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
130 if (!object_paths.empty()) {
131 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
132 SetAdapter(object_paths[0]);
136 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
137 Shutdown();
140 void BluetoothAdapterChromeOS::DeleteOnCorrectThread() const {
141 if (ui_task_runner_->RunsTasksOnCurrentThread() ||
142 !ui_task_runner_->DeleteSoon(FROM_HERE, this))
143 delete this;
146 void BluetoothAdapterChromeOS::AddObserver(
147 BluetoothAdapter::Observer* observer) {
148 DCHECK(observer);
149 observers_.AddObserver(observer);
152 void BluetoothAdapterChromeOS::RemoveObserver(
153 BluetoothAdapter::Observer* observer) {
154 DCHECK(observer);
155 observers_.RemoveObserver(observer);
158 std::string BluetoothAdapterChromeOS::GetAddress() const {
159 if (!IsPresent())
160 return std::string();
162 BluetoothAdapterClient::Properties* properties =
163 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
164 GetProperties(object_path_);
165 DCHECK(properties);
167 return BluetoothDevice::CanonicalizeAddress(properties->address.value());
170 std::string BluetoothAdapterChromeOS::GetName() const {
171 if (!IsPresent())
172 return std::string();
174 BluetoothAdapterClient::Properties* properties =
175 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
176 GetProperties(object_path_);
177 DCHECK(properties);
179 return properties->alias.value();
182 void BluetoothAdapterChromeOS::SetName(const std::string& name,
183 const base::Closure& callback,
184 const ErrorCallback& error_callback) {
185 if (!IsPresent()) {
186 error_callback.Run();
187 return;
190 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
191 GetProperties(object_path_)->alias.Set(
192 name,
193 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
194 weak_ptr_factory_.GetWeakPtr(),
195 callback,
196 error_callback));
199 bool BluetoothAdapterChromeOS::IsInitialized() const {
200 return true;
203 bool BluetoothAdapterChromeOS::IsPresent() const {
204 return !dbus_is_shutdown_ && !object_path_.value().empty();
207 bool BluetoothAdapterChromeOS::IsPowered() const {
208 if (!IsPresent())
209 return false;
211 BluetoothAdapterClient::Properties* properties =
212 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
213 GetProperties(object_path_);
215 return properties->powered.value();
218 void BluetoothAdapterChromeOS::SetPowered(
219 bool powered,
220 const base::Closure& callback,
221 const ErrorCallback& error_callback) {
222 if (!IsPresent()) {
223 error_callback.Run();
224 return;
227 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
228 GetProperties(object_path_)->powered.Set(
229 powered,
230 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
231 weak_ptr_factory_.GetWeakPtr(),
232 callback,
233 error_callback));
236 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
237 if (!IsPresent())
238 return false;
240 BluetoothAdapterClient::Properties* properties =
241 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
242 GetProperties(object_path_);
244 return properties->discoverable.value();
247 void BluetoothAdapterChromeOS::SetDiscoverable(
248 bool discoverable,
249 const base::Closure& callback,
250 const ErrorCallback& error_callback) {
251 if (!IsPresent()) {
252 error_callback.Run();
253 return;
256 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
257 GetProperties(object_path_)->discoverable.Set(
258 discoverable,
259 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
260 weak_ptr_factory_.GetWeakPtr(),
261 callback,
262 error_callback));
265 bool BluetoothAdapterChromeOS::IsDiscovering() const {
266 if (!IsPresent())
267 return false;
269 BluetoothAdapterClient::Properties* properties =
270 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
271 GetProperties(object_path_);
273 return properties->discovering.value();
276 void BluetoothAdapterChromeOS::CreateRfcommService(
277 const BluetoothUUID& uuid,
278 const ServiceOptions& options,
279 const CreateServiceCallback& callback,
280 const CreateServiceErrorCallback& error_callback) {
281 DCHECK(!dbus_is_shutdown_);
282 VLOG(1) << object_path_.value() << ": Creating RFCOMM service: "
283 << uuid.canonical_value();
284 scoped_refptr<BluetoothSocketChromeOS> socket =
285 BluetoothSocketChromeOS::CreateBluetoothSocket(
286 ui_task_runner_, socket_thread_);
287 socket->Listen(this,
288 BluetoothSocketChromeOS::kRfcomm,
289 uuid,
290 options,
291 base::Bind(callback, socket),
292 error_callback);
295 void BluetoothAdapterChromeOS::CreateL2capService(
296 const BluetoothUUID& uuid,
297 const ServiceOptions& options,
298 const CreateServiceCallback& callback,
299 const CreateServiceErrorCallback& error_callback) {
300 DCHECK(!dbus_is_shutdown_);
301 VLOG(1) << object_path_.value() << ": Creating L2CAP service: "
302 << uuid.canonical_value();
303 scoped_refptr<BluetoothSocketChromeOS> socket =
304 BluetoothSocketChromeOS::CreateBluetoothSocket(
305 ui_task_runner_, socket_thread_);
306 socket->Listen(this,
307 BluetoothSocketChromeOS::kL2cap,
308 uuid,
309 options,
310 base::Bind(callback, socket),
311 error_callback);
314 void BluetoothAdapterChromeOS::RegisterAudioSink(
315 const BluetoothAudioSink::Options& options,
316 const device::BluetoothAdapter::AcquiredCallback& callback,
317 const BluetoothAudioSink::ErrorCallback& error_callback) {
318 VLOG(1) << "Registering audio sink";
319 if (!this->IsPresent()) {
320 error_callback.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER);
321 return;
323 scoped_refptr<BluetoothAudioSinkChromeOS> audio_sink(
324 new BluetoothAudioSinkChromeOS(this));
325 audio_sink->Register(
326 options, base::Bind(&BluetoothAdapterChromeOS::OnRegisterAudioSink,
327 weak_ptr_factory_.GetWeakPtr(), callback,
328 error_callback, audio_sink),
329 error_callback);
332 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
333 BluetoothDevice::PairingDelegate* pairing_delegate) {
334 // Before removing a pairing delegate make sure that there aren't any devices
335 // currently using it; if there are, clear the pairing context which will
336 // make any responses no-ops.
337 for (DevicesMap::iterator iter = devices_.begin();
338 iter != devices_.end(); ++iter) {
339 BluetoothDeviceChromeOS* device_chromeos =
340 static_cast<BluetoothDeviceChromeOS*>(iter->second);
342 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
343 if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
344 device_chromeos->EndPairing();
348 void BluetoothAdapterChromeOS::AdapterAdded(
349 const dbus::ObjectPath& object_path) {
350 // Set the adapter to the newly added adapter only if no adapter is present.
351 if (!IsPresent())
352 SetAdapter(object_path);
355 void BluetoothAdapterChromeOS::AdapterRemoved(
356 const dbus::ObjectPath& object_path) {
357 if (object_path == object_path_)
358 RemoveAdapter();
361 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
362 const dbus::ObjectPath& object_path,
363 const std::string& property_name) {
364 DCHECK(IsPresent());
365 if (object_path != object_path_)
366 return;
368 BluetoothAdapterClient::Properties* properties =
369 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
370 GetProperties(object_path_);
372 if (property_name == properties->powered.name())
373 PoweredChanged(properties->powered.value());
374 else if (property_name == properties->discoverable.name())
375 DiscoverableChanged(properties->discoverable.value());
376 else if (property_name == properties->discovering.name())
377 DiscoveringChanged(properties->discovering.value());
380 void BluetoothAdapterChromeOS::DeviceAdded(
381 const dbus::ObjectPath& object_path) {
382 DCHECK(IsPresent());
383 BluetoothDeviceClient::Properties* properties =
384 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
385 GetProperties(object_path);
386 if (properties->adapter.value() != object_path_)
387 return;
389 BluetoothDeviceChromeOS* device_chromeos =
390 new BluetoothDeviceChromeOS(this,
391 object_path,
392 ui_task_runner_,
393 socket_thread_);
394 DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
396 devices_[device_chromeos->GetAddress()] = device_chromeos;
398 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
399 DeviceAdded(this, device_chromeos));
402 void BluetoothAdapterChromeOS::DeviceRemoved(
403 const dbus::ObjectPath& object_path) {
404 DCHECK(IsPresent());
405 for (DevicesMap::iterator iter = devices_.begin();
406 iter != devices_.end(); ++iter) {
407 BluetoothDeviceChromeOS* device_chromeos =
408 static_cast<BluetoothDeviceChromeOS*>(iter->second);
409 if (device_chromeos->object_path() == object_path) {
410 devices_.erase(iter);
412 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
413 DeviceRemoved(this, device_chromeos));
414 delete device_chromeos;
415 return;
420 void BluetoothAdapterChromeOS::DevicePropertyChanged(
421 const dbus::ObjectPath& object_path,
422 const std::string& property_name) {
423 DCHECK(IsPresent());
424 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
425 if (!device_chromeos)
426 return;
428 BluetoothDeviceClient::Properties* properties =
429 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
430 GetProperties(object_path);
432 if (property_name == properties->bluetooth_class.name() ||
433 property_name == properties->address.name() ||
434 property_name == properties->alias.name() ||
435 property_name == properties->paired.name() ||
436 property_name == properties->trusted.name() ||
437 property_name == properties->connected.name() ||
438 property_name == properties->uuids.name() ||
439 property_name == properties->rssi.name())
440 NotifyDeviceChanged(device_chromeos);
442 // When a device becomes paired, mark it as trusted so that the user does
443 // not need to approve every incoming connection
444 if (property_name == properties->paired.name() &&
445 properties->paired.value() && !properties->trusted.value())
446 device_chromeos->SetTrusted();
448 // UMA connection counting
449 if (property_name == properties->connected.name()) {
450 // PlayStation joystick tries to reconnect after disconnection from USB.
451 // If it is still not trusted, set it, so it becomes available on the
452 // list of known devices.
453 if (properties->connected.value() && device_chromeos->IsTrustable() &&
454 !properties->trusted.value())
455 device_chromeos->SetTrusted();
457 int count = 0;
459 for (DevicesMap::iterator iter = devices_.begin();
460 iter != devices_.end(); ++iter) {
461 if (iter->second->IsPaired() && iter->second->IsConnected())
462 ++count;
465 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
469 void BluetoothAdapterChromeOS::InputPropertyChanged(
470 const dbus::ObjectPath& object_path,
471 const std::string& property_name) {
472 DCHECK(IsPresent());
473 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
474 if (!device_chromeos)
475 return;
477 BluetoothInputClient::Properties* properties =
478 DBusThreadManager::Get()->GetBluetoothInputClient()->
479 GetProperties(object_path);
481 // Properties structure can be removed, which triggers a change in the
482 // BluetoothDevice::IsConnectable() property, as does a change in the
483 // actual reconnect_mode property.
484 if (!properties ||
485 property_name == properties->reconnect_mode.name())
486 NotifyDeviceChanged(device_chromeos);
489 void BluetoothAdapterChromeOS::Released() {
490 VLOG(1) << "Release";
491 if (!IsPresent())
492 return;
493 DCHECK(agent_.get());
495 // Called after we unregister the pairing agent, e.g. when changing I/O
496 // capabilities. Nothing much to be done right now.
499 void BluetoothAdapterChromeOS::RequestPinCode(
500 const dbus::ObjectPath& device_path,
501 const PinCodeCallback& callback) {
502 DCHECK(IsPresent());
503 DCHECK(agent_.get());
504 VLOG(1) << device_path.value() << ": RequestPinCode";
506 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
507 if (!pairing) {
508 callback.Run(REJECTED, "");
509 return;
512 pairing->RequestPinCode(callback);
515 void BluetoothAdapterChromeOS::DisplayPinCode(
516 const dbus::ObjectPath& device_path,
517 const std::string& pincode) {
518 DCHECK(IsPresent());
519 DCHECK(agent_.get());
520 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
522 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
523 if (!pairing)
524 return;
526 pairing->DisplayPinCode(pincode);
529 void BluetoothAdapterChromeOS::RequestPasskey(
530 const dbus::ObjectPath& device_path,
531 const PasskeyCallback& callback) {
532 DCHECK(IsPresent());
533 DCHECK(agent_.get());
534 VLOG(1) << device_path.value() << ": RequestPasskey";
536 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
537 if (!pairing) {
538 callback.Run(REJECTED, 0);
539 return;
542 pairing->RequestPasskey(callback);
545 void BluetoothAdapterChromeOS::DisplayPasskey(
546 const dbus::ObjectPath& device_path,
547 uint32 passkey,
548 uint16 entered) {
549 DCHECK(IsPresent());
550 DCHECK(agent_.get());
551 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
552 << " (" << entered << " entered)";
554 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
555 if (!pairing)
556 return;
558 if (entered == 0)
559 pairing->DisplayPasskey(passkey);
561 pairing->KeysEntered(entered);
564 void BluetoothAdapterChromeOS::RequestConfirmation(
565 const dbus::ObjectPath& device_path,
566 uint32 passkey,
567 const ConfirmationCallback& callback) {
568 DCHECK(IsPresent());
569 DCHECK(agent_.get());
570 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
572 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
573 if (!pairing) {
574 callback.Run(REJECTED);
575 return;
578 pairing->RequestConfirmation(passkey, callback);
581 void BluetoothAdapterChromeOS::RequestAuthorization(
582 const dbus::ObjectPath& device_path,
583 const ConfirmationCallback& callback) {
584 DCHECK(IsPresent());
585 DCHECK(agent_.get());
586 VLOG(1) << device_path.value() << ": RequestAuthorization";
588 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
589 if (!pairing) {
590 callback.Run(REJECTED);
591 return;
594 pairing->RequestAuthorization(callback);
597 void BluetoothAdapterChromeOS::AuthorizeService(
598 const dbus::ObjectPath& device_path,
599 const std::string& uuid,
600 const ConfirmationCallback& callback) {
601 DCHECK(IsPresent());
602 DCHECK(agent_.get());
603 VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
605 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(device_path);
606 if (!device_chromeos) {
607 callback.Run(CANCELLED);
608 return;
611 // We always set paired devices to Trusted, so the only reason that this
612 // method call would ever be called is in the case of a race condition where
613 // our "Set('Trusted', true)" method call is still pending in the Bluetooth
614 // daemon because it's busy handling the incoming connection.
615 if (device_chromeos->IsPaired()) {
616 callback.Run(SUCCESS);
617 return;
620 // TODO(keybuk): reject service authorizations when not paired, determine
621 // whether this is acceptable long-term.
622 LOG(WARNING) << "Rejecting service connection from unpaired device "
623 << device_chromeos->GetAddress() << " for UUID " << uuid;
624 callback.Run(REJECTED);
627 void BluetoothAdapterChromeOS::Cancel() {
628 DCHECK(IsPresent());
629 DCHECK(agent_.get());
630 VLOG(1) << "Cancel";
633 void BluetoothAdapterChromeOS::OnRegisterAgent() {
634 VLOG(1) << "Pairing agent registered, requesting to be made default";
636 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
637 RequestDefaultAgent(
638 dbus::ObjectPath(kAgentPath),
639 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
640 weak_ptr_factory_.GetWeakPtr()),
641 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
642 weak_ptr_factory_.GetWeakPtr()));
645 void BluetoothAdapterChromeOS::OnRegisterAgentError(
646 const std::string& error_name,
647 const std::string& error_message) {
648 // Our agent being already registered isn't an error.
649 if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
650 return;
652 LOG(WARNING) << ": Failed to register pairing agent: "
653 << error_name << ": " << error_message;
656 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
657 VLOG(1) << "Pairing agent now default";
660 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
661 const std::string& error_name,
662 const std::string& error_message) {
663 LOG(WARNING) << ": Failed to make pairing agent default: "
664 << error_name << ": " << error_message;
667 void BluetoothAdapterChromeOS::OnRegisterAudioSink(
668 const device::BluetoothAdapter::AcquiredCallback& callback,
669 const device::BluetoothAudioSink::ErrorCallback& error_callback,
670 scoped_refptr<BluetoothAudioSink> audio_sink) {
671 if (!IsPresent()) {
672 VLOG(1) << "Failed to register audio sink, adapter not present";
673 error_callback.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER);
674 return;
676 DCHECK(audio_sink.get());
677 callback.Run(audio_sink);
680 BluetoothDeviceChromeOS*
681 BluetoothAdapterChromeOS::GetDeviceWithPath(
682 const dbus::ObjectPath& object_path) {
683 if (!IsPresent())
684 return NULL;
686 for (DevicesMap::iterator iter = devices_.begin(); iter != devices_.end();
687 ++iter) {
688 BluetoothDeviceChromeOS* device_chromeos =
689 static_cast<BluetoothDeviceChromeOS*>(iter->second);
690 if (device_chromeos->object_path() == object_path)
691 return device_chromeos;
694 return NULL;
697 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
698 const dbus::ObjectPath& object_path) {
699 DCHECK(IsPresent());
700 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
701 if (!device_chromeos) {
702 LOG(WARNING) << "Pairing Agent request for unknown device: "
703 << object_path.value();
704 return NULL;
707 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
708 if (pairing)
709 return pairing;
711 // The device doesn't have its own pairing context, so this is an incoming
712 // pairing request that should use our best default delegate (if we have one).
713 BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
714 if (!pairing_delegate)
715 return NULL;
717 return device_chromeos->BeginPairing(pairing_delegate);
720 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
721 DCHECK(!IsPresent());
722 DCHECK(!dbus_is_shutdown_);
723 object_path_ = object_path;
725 VLOG(1) << object_path_.value() << ": using adapter.";
727 VLOG(1) << "Registering pairing agent";
728 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
729 RegisterAgent(
730 dbus::ObjectPath(kAgentPath),
731 bluetooth_agent_manager::kKeyboardDisplayCapability,
732 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
733 weak_ptr_factory_.GetWeakPtr()),
734 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
735 weak_ptr_factory_.GetWeakPtr()));
737 SetDefaultAdapterName();
739 BluetoothAdapterClient::Properties* properties =
740 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
741 GetProperties(object_path_);
743 PresentChanged(true);
745 if (properties->powered.value())
746 PoweredChanged(true);
747 if (properties->discoverable.value())
748 DiscoverableChanged(true);
749 if (properties->discovering.value())
750 DiscoveringChanged(true);
752 std::vector<dbus::ObjectPath> device_paths =
753 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
754 GetDevicesForAdapter(object_path_);
756 for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
757 iter != device_paths.end(); ++iter) {
758 DeviceAdded(*iter);
762 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
763 DCHECK(IsPresent());
764 std::string board = base::SysInfo::GetLsbReleaseBoard();
765 std::string alias;
766 if (board.substr(0, 6) == "stumpy") {
767 alias = "Chromebox";
768 } else if (board.substr(0, 4) == "link") {
769 alias = "Chromebook Pixel";
770 } else {
771 alias = "Chromebook";
774 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
777 void BluetoothAdapterChromeOS::RemoveAdapter() {
778 DCHECK(IsPresent());
779 VLOG(1) << object_path_.value() << ": adapter removed.";
781 BluetoothAdapterClient::Properties* properties =
782 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
783 GetProperties(object_path_);
785 object_path_ = dbus::ObjectPath("");
787 if (properties->powered.value())
788 PoweredChanged(false);
789 if (properties->discoverable.value())
790 DiscoverableChanged(false);
791 if (properties->discovering.value())
792 DiscoveringChanged(false);
794 // Copy the devices list here and clear the original so that when we
795 // send DeviceRemoved(), GetDevices() returns no devices.
796 DevicesMap devices = devices_;
797 devices_.clear();
799 for (DevicesMap::iterator iter = devices.begin();
800 iter != devices.end(); ++iter) {
801 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
802 DeviceRemoved(this, iter->second));
803 delete iter->second;
806 PresentChanged(false);
809 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
810 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
811 AdapterPoweredChanged(this, powered));
814 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
815 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
816 AdapterDiscoverableChanged(this, discoverable));
819 void BluetoothAdapterChromeOS::DiscoveringChanged(
820 bool discovering) {
821 // If the adapter stopped discovery due to a reason other than a request by
822 // us, reset the count to 0.
823 VLOG(1) << "Discovering changed: " << discovering;
824 if (!discovering && !discovery_request_pending_
825 && num_discovery_sessions_ > 0) {
826 VLOG(1) << "Marking sessions as inactive.";
827 num_discovery_sessions_ = 0;
828 MarkDiscoverySessionsAsInactive();
830 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
831 AdapterDiscoveringChanged(this, discovering));
834 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
835 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
836 AdapterPresentChanged(this, present));
839 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
840 BluetoothDeviceChromeOS* device) {
841 DCHECK(device->adapter_ == this);
843 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
844 DeviceChanged(this, device));
847 void BluetoothAdapterChromeOS::NotifyGattServiceAdded(
848 BluetoothRemoteGattServiceChromeOS* service) {
849 DCHECK_EQ(service->GetAdapter(), this);
850 DCHECK_EQ(
851 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
852 this);
854 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
855 observers_,
856 GattServiceAdded(this, service->GetDevice(), service));
859 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
860 BluetoothRemoteGattServiceChromeOS* service) {
861 DCHECK_EQ(service->GetAdapter(), this);
862 DCHECK_EQ(
863 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
864 this);
866 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
867 observers_,
868 GattServiceRemoved(this, service->GetDevice(), service));
871 void BluetoothAdapterChromeOS::NotifyGattServiceChanged(
872 BluetoothRemoteGattServiceChromeOS* service) {
873 DCHECK_EQ(service->GetAdapter(), this);
875 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
876 observers_,
877 GattServiceChanged(this, service));
880 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
881 BluetoothRemoteGattServiceChromeOS* service) {
882 DCHECK_EQ(service->GetAdapter(), this);
884 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
885 observers_,
886 GattDiscoveryCompleteForService(this, service));
889 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
890 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
891 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
892 characteristic->GetService())->GetAdapter(),
893 this);
895 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
896 observers_,
897 GattCharacteristicAdded(this, characteristic));
900 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
901 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
902 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
903 characteristic->GetService())->GetAdapter(),
904 this);
906 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
907 observers_,
908 GattCharacteristicRemoved(this, characteristic));
911 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
912 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
913 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
914 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
915 this);
917 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
918 observers_,
919 GattDescriptorAdded(this, descriptor));
922 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
923 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
924 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
925 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
926 this);
928 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
929 observers_,
930 GattDescriptorRemoved(this, descriptor));
933 void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged(
934 BluetoothRemoteGattCharacteristicChromeOS* characteristic,
935 const std::vector<uint8>& value) {
936 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
937 characteristic->GetService())->GetAdapter(),
938 this);
940 FOR_EACH_OBSERVER(
941 BluetoothAdapter::Observer,
942 observers_,
943 GattCharacteristicValueChanged(this, characteristic, value));
946 void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
947 BluetoothRemoteGattDescriptorChromeOS* descriptor,
948 const std::vector<uint8>& value) {
949 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
950 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
951 this);
953 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
954 observers_,
955 GattDescriptorValueChanged(this, descriptor, value));
958 void BluetoothAdapterChromeOS::UseProfile(
959 const BluetoothUUID& uuid,
960 const dbus::ObjectPath& device_path,
961 const BluetoothProfileManagerClient::Options& options,
962 BluetoothProfileServiceProvider::Delegate* delegate,
963 const ProfileRegisteredCallback& success_callback,
964 const ErrorCompletionCallback& error_callback) {
965 DCHECK(delegate);
967 if (!IsPresent()) {
968 VLOG(2) << "Adapter not present, erroring out";
969 error_callback.Run("Adapter not present");
970 return;
973 if (profiles_.find(uuid) != profiles_.end()) {
974 // TODO(jamuraa) check that the options are the same and error when they are
975 // not.
976 SetProfileDelegate(uuid, device_path, delegate, success_callback,
977 error_callback);
978 return;
981 if (profile_queues_.find(uuid) == profile_queues_.end()) {
982 BluetoothAdapterProfileChromeOS::Register(
983 uuid, options,
984 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfile, this, uuid),
985 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfileError, this,
986 uuid));
988 profile_queues_[uuid] = new std::vector<RegisterProfileCompletionPair>();
991 profile_queues_[uuid]->push_back(std::make_pair(
992 base::Bind(&BluetoothAdapterChromeOS::SetProfileDelegate, this, uuid,
993 device_path, delegate, success_callback, error_callback),
994 error_callback));
997 void BluetoothAdapterChromeOS::ReleaseProfile(
998 const dbus::ObjectPath& device_path,
999 BluetoothAdapterProfileChromeOS* profile) {
1000 VLOG(2) << "Releasing Profile: " << profile->uuid().canonical_value()
1001 << " from " << device_path.value();
1002 profile->RemoveDelegate(
1003 device_path, base::Bind(&BluetoothAdapterChromeOS::RemoveProfile,
1004 weak_ptr_factory_.GetWeakPtr(), profile->uuid()));
1007 void BluetoothAdapterChromeOS::RemoveProfile(const BluetoothUUID& uuid) {
1008 VLOG(2) << "Remove Profile: " << uuid.canonical_value();
1010 if (profiles_.find(uuid) != profiles_.end()) {
1011 delete profiles_[uuid];
1012 profiles_.erase(uuid);
1016 void BluetoothAdapterChromeOS::OnRegisterProfile(
1017 const BluetoothUUID& uuid,
1018 BluetoothAdapterProfileChromeOS* profile) {
1019 profiles_[uuid] = profile;
1021 if (profile_queues_.find(uuid) == profile_queues_.end())
1022 return;
1024 for (auto& it : *profile_queues_[uuid])
1025 it.first.Run();
1026 delete profile_queues_[uuid];
1027 profile_queues_.erase(uuid);
1030 void BluetoothAdapterChromeOS::SetProfileDelegate(
1031 const BluetoothUUID& uuid,
1032 const dbus::ObjectPath& device_path,
1033 BluetoothProfileServiceProvider::Delegate* delegate,
1034 const ProfileRegisteredCallback& success_callback,
1035 const ErrorCompletionCallback& error_callback) {
1037 if (profiles_.find(uuid) == profiles_.end()) {
1038 error_callback.Run("Cannot find profile!");
1039 return;
1042 if (profiles_[uuid]->SetDelegate(device_path, delegate)) {
1043 success_callback.Run(profiles_[uuid]);
1044 return;
1046 // Already set
1047 error_callback.Run(bluetooth_agent_manager::kErrorAlreadyExists);
1050 void BluetoothAdapterChromeOS::OnRegisterProfileError(
1051 const BluetoothUUID& uuid,
1052 const std::string& error_name,
1053 const std::string& error_message) {
1054 VLOG(2) << object_path_.value() << ": Failed to register profile: "
1055 << error_name << ": " << error_message;
1056 if (profile_queues_.find(uuid) == profile_queues_.end())
1057 return;
1059 for (auto& it : *profile_queues_[uuid])
1060 it.second.Run(error_message);
1062 delete profile_queues_[uuid];
1063 profile_queues_.erase(uuid);
1066 void BluetoothAdapterChromeOS::OnSetDiscoverable(
1067 const base::Closure& callback,
1068 const ErrorCallback& error_callback,
1069 bool success) {
1070 if (!IsPresent()) {
1071 error_callback.Run();
1072 return;
1075 // Set the discoverable_timeout property to zero so the adapter remains
1076 // discoverable forever.
1077 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1078 GetProperties(object_path_)->discoverable_timeout.Set(
1080 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
1081 weak_ptr_factory_.GetWeakPtr(),
1082 callback,
1083 error_callback));
1086 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
1087 const base::Closure& callback,
1088 const ErrorCallback& error_callback,
1089 bool success) {
1090 if (IsPresent() && success)
1091 callback.Run();
1092 else
1093 error_callback.Run();
1096 void BluetoothAdapterChromeOS::AddDiscoverySession(
1097 const base::Closure& callback,
1098 const ErrorCallback& error_callback) {
1099 if (!IsPresent()) {
1100 error_callback.Run();
1101 return;
1103 VLOG(1) << __func__;
1104 if (discovery_request_pending_) {
1105 // The pending request is either to stop a previous session or to start a
1106 // new one. Either way, queue this one.
1107 DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
1108 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1109 << "request to start a new discovery session.";
1110 discovery_request_queue_.push(std::make_pair(callback, error_callback));
1111 return;
1114 // The adapter is already discovering.
1115 if (num_discovery_sessions_ > 0) {
1116 DCHECK(IsDiscovering());
1117 DCHECK(!discovery_request_pending_);
1118 num_discovery_sessions_++;
1119 callback.Run();
1120 return;
1123 // There are no active discovery sessions.
1124 DCHECK_EQ(num_discovery_sessions_, 0);
1126 // This is the first request to start device discovery.
1127 discovery_request_pending_ = true;
1128 DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
1129 object_path_,
1130 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
1131 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1132 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
1133 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1136 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
1137 const base::Closure& callback,
1138 const ErrorCallback& error_callback) {
1139 if (!IsPresent()) {
1140 error_callback.Run();
1141 return;
1144 VLOG(1) << __func__;
1145 // There are active sessions other than the one currently being removed.
1146 if (num_discovery_sessions_ > 1) {
1147 DCHECK(IsDiscovering());
1148 DCHECK(!discovery_request_pending_);
1149 num_discovery_sessions_--;
1150 callback.Run();
1151 return;
1154 // If there is a pending request to BlueZ, then queue this request.
1155 if (discovery_request_pending_) {
1156 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1157 << "request to stop discovery session.";
1158 error_callback.Run();
1159 return;
1162 // There are no active sessions. Return error.
1163 if (num_discovery_sessions_ == 0) {
1164 // TODO(armansito): This should never happen once we have the
1165 // DiscoverySession API. Replace this case with an assert once it's
1166 // the deprecated methods have been removed. (See crbug.com/3445008).
1167 VLOG(1) << "No active discovery sessions. Returning error.";
1168 error_callback.Run();
1169 return;
1172 // There is exactly one active discovery session. Request BlueZ to stop
1173 // discovery.
1174 DCHECK_EQ(num_discovery_sessions_, 1);
1175 discovery_request_pending_ = true;
1176 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1177 StopDiscovery(
1178 object_path_,
1179 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
1180 weak_ptr_factory_.GetWeakPtr(),
1181 callback),
1182 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
1183 weak_ptr_factory_.GetWeakPtr(),
1184 error_callback));
1187 void BluetoothAdapterChromeOS::OnStartDiscovery(
1188 const base::Closure& callback,
1189 const ErrorCallback& error_callback) {
1190 // Report success on the original request and increment the count.
1191 VLOG(1) << __func__;
1192 DCHECK(discovery_request_pending_);
1193 DCHECK_EQ(num_discovery_sessions_, 0);
1194 discovery_request_pending_ = false;
1195 num_discovery_sessions_++;
1196 if (IsPresent())
1197 callback.Run();
1198 else
1199 error_callback.Run();
1201 // Try to add a new discovery session for each queued request.
1202 ProcessQueuedDiscoveryRequests();
1205 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
1206 const base::Closure& callback,
1207 const ErrorCallback& error_callback,
1208 const std::string& error_name,
1209 const std::string& error_message) {
1210 LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
1211 << error_name << ": " << error_message;
1213 // Failed to start discovery. This can only happen if the count is at 0.
1214 DCHECK_EQ(num_discovery_sessions_, 0);
1215 DCHECK(discovery_request_pending_);
1216 discovery_request_pending_ = false;
1218 // Discovery request may fail if discovery was previously initiated by Chrome,
1219 // but the session were invalidated due to the discovery state unexpectedly
1220 // changing to false and then back to true. In this case, report success.
1221 if (IsPresent() && error_name == bluetooth_device::kErrorInProgress &&
1222 IsDiscovering()) {
1223 VLOG(1) << "Discovery previously initiated. Reporting success.";
1224 num_discovery_sessions_++;
1225 callback.Run();
1226 } else {
1227 error_callback.Run();
1230 // Try to add a new discovery session for each queued request.
1231 ProcessQueuedDiscoveryRequests();
1234 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
1235 // Report success on the original request and decrement the count.
1236 VLOG(1) << __func__;
1237 DCHECK(discovery_request_pending_);
1238 DCHECK_EQ(num_discovery_sessions_, 1);
1239 discovery_request_pending_ = false;
1240 num_discovery_sessions_--;
1241 callback.Run();
1243 // Try to add a new discovery session for each queued request.
1244 ProcessQueuedDiscoveryRequests();
1247 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
1248 const ErrorCallback& error_callback,
1249 const std::string& error_name,
1250 const std::string& error_message) {
1251 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
1252 << error_name << ": " << error_message;
1254 // Failed to stop discovery. This can only happen if the count is at 1.
1255 DCHECK(discovery_request_pending_);
1256 DCHECK_EQ(num_discovery_sessions_, 1);
1257 discovery_request_pending_ = false;
1258 error_callback.Run();
1260 // Try to add a new discovery session for each queued request.
1261 ProcessQueuedDiscoveryRequests();
1264 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
1265 while (!discovery_request_queue_.empty()) {
1266 VLOG(1) << "Process queued discovery request.";
1267 DiscoveryCallbackPair callbacks = discovery_request_queue_.front();
1268 discovery_request_queue_.pop();
1269 AddDiscoverySession(callbacks.first, callbacks.second);
1271 // If the queued request resulted in a pending call, then let it
1272 // asynchonously process the remaining queued requests once the pending
1273 // call returns.
1274 if (discovery_request_pending_)
1275 return;
1279 } // namespace chromeos