Remove 'RemoveTrailingSeparators' function from SimpleMenuModel
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_chromeos.cc
blobfce8f8b42cc40fc7ea6a22ec0c9b1da7fa83f468
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::BluetoothDiscoveryFilter;
40 using device::BluetoothSocket;
41 using device::BluetoothUUID;
43 namespace {
45 // The agent path is relatively meaningless since BlueZ only permits one to
46 // exist per D-Bus connection, it just has to be unique within Chromium.
47 const char kAgentPath[] = "/org/chromium/bluetooth_agent";
49 void OnUnregisterAgentError(const std::string& error_name,
50 const std::string& error_message) {
51 // It's okay if the agent didn't exist, it means we never saw an adapter.
52 if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
53 return;
55 LOG(WARNING) << "Failed to unregister pairing agent: "
56 << error_name << ": " << error_message;
59 } // namespace
61 namespace device {
63 // static
64 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
65 const InitCallback& init_callback) {
66 return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
71 namespace chromeos {
73 // static
74 base::WeakPtr<BluetoothAdapter> BluetoothAdapterChromeOS::CreateAdapter() {
75 BluetoothAdapterChromeOS* adapter = new BluetoothAdapterChromeOS();
76 return adapter->weak_ptr_factory_.GetWeakPtr();
79 void BluetoothAdapterChromeOS::Shutdown() {
80 if (dbus_is_shutdown_)
81 return;
82 DCHECK(DBusThreadManager::IsInitialized())
83 << "Call BluetoothAdapterFactory::Shutdown() before "
84 "DBusThreadManager::Shutdown().";
86 if (IsPresent())
87 RemoveAdapter(); // Also deletes devices_.
88 DCHECK(devices_.empty());
89 // profiles_ should be empty because all BluetoothSockets have been signaled
90 // that this adapter is disappearing.
91 DCHECK(profiles_.empty());
93 for (auto& it : profile_queues_)
94 delete it.second;
95 profile_queues_.clear();
97 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
98 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
99 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
101 VLOG(1) << "Unregistering pairing agent";
102 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->UnregisterAgent(
103 dbus::ObjectPath(kAgentPath), base::Bind(&base::DoNothing),
104 base::Bind(&OnUnregisterAgentError));
106 agent_.reset();
107 dbus_is_shutdown_ = true;
110 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
111 : dbus_is_shutdown_(false),
112 num_discovery_sessions_(0),
113 discovery_request_pending_(false),
114 weak_ptr_factory_(this) {
115 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
116 socket_thread_ = device::BluetoothSocketThread::Get();
118 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
119 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
120 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
122 // Register the pairing agent.
123 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
124 agent_.reset(BluetoothAgentServiceProvider::Create(
125 system_bus, dbus::ObjectPath(kAgentPath), this));
126 DCHECK(agent_.get());
128 std::vector<dbus::ObjectPath> object_paths =
129 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
131 if (!object_paths.empty()) {
132 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
133 SetAdapter(object_paths[0]);
137 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
138 Shutdown();
141 void BluetoothAdapterChromeOS::DeleteOnCorrectThread() const {
142 if (ui_task_runner_->RunsTasksOnCurrentThread() ||
143 !ui_task_runner_->DeleteSoon(FROM_HERE, this))
144 delete this;
147 void BluetoothAdapterChromeOS::AddObserver(
148 BluetoothAdapter::Observer* observer) {
149 DCHECK(observer);
150 observers_.AddObserver(observer);
153 void BluetoothAdapterChromeOS::RemoveObserver(
154 BluetoothAdapter::Observer* observer) {
155 DCHECK(observer);
156 observers_.RemoveObserver(observer);
159 std::string BluetoothAdapterChromeOS::GetAddress() const {
160 if (!IsPresent())
161 return std::string();
163 BluetoothAdapterClient::Properties* properties =
164 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
165 GetProperties(object_path_);
166 DCHECK(properties);
168 return BluetoothDevice::CanonicalizeAddress(properties->address.value());
171 std::string BluetoothAdapterChromeOS::GetName() const {
172 if (!IsPresent())
173 return std::string();
175 BluetoothAdapterClient::Properties* properties =
176 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
177 GetProperties(object_path_);
178 DCHECK(properties);
180 return properties->alias.value();
183 void BluetoothAdapterChromeOS::SetName(const std::string& name,
184 const base::Closure& callback,
185 const ErrorCallback& error_callback) {
186 if (!IsPresent()) {
187 error_callback.Run();
188 return;
191 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
192 GetProperties(object_path_)->alias.Set(
193 name,
194 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
195 weak_ptr_factory_.GetWeakPtr(),
196 callback,
197 error_callback));
200 bool BluetoothAdapterChromeOS::IsInitialized() const {
201 return true;
204 bool BluetoothAdapterChromeOS::IsPresent() const {
205 return !dbus_is_shutdown_ && !object_path_.value().empty();
208 bool BluetoothAdapterChromeOS::IsPowered() const {
209 if (!IsPresent())
210 return false;
212 BluetoothAdapterClient::Properties* properties =
213 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
214 GetProperties(object_path_);
216 return properties->powered.value();
219 void BluetoothAdapterChromeOS::SetPowered(
220 bool powered,
221 const base::Closure& callback,
222 const ErrorCallback& error_callback) {
223 if (!IsPresent()) {
224 error_callback.Run();
225 return;
228 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
229 GetProperties(object_path_)->powered.Set(
230 powered,
231 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
232 weak_ptr_factory_.GetWeakPtr(),
233 callback,
234 error_callback));
237 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
238 if (!IsPresent())
239 return false;
241 BluetoothAdapterClient::Properties* properties =
242 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
243 GetProperties(object_path_);
245 return properties->discoverable.value();
248 void BluetoothAdapterChromeOS::SetDiscoverable(
249 bool discoverable,
250 const base::Closure& callback,
251 const ErrorCallback& error_callback) {
252 if (!IsPresent()) {
253 error_callback.Run();
254 return;
257 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
258 GetProperties(object_path_)->discoverable.Set(
259 discoverable,
260 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
261 weak_ptr_factory_.GetWeakPtr(),
262 callback,
263 error_callback));
266 bool BluetoothAdapterChromeOS::IsDiscovering() const {
267 if (!IsPresent())
268 return false;
270 BluetoothAdapterClient::Properties* properties =
271 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
272 GetProperties(object_path_);
274 return properties->discovering.value();
277 void BluetoothAdapterChromeOS::CreateRfcommService(
278 const BluetoothUUID& uuid,
279 const ServiceOptions& options,
280 const CreateServiceCallback& callback,
281 const CreateServiceErrorCallback& error_callback) {
282 DCHECK(!dbus_is_shutdown_);
283 VLOG(1) << object_path_.value() << ": Creating RFCOMM service: "
284 << uuid.canonical_value();
285 scoped_refptr<BluetoothSocketChromeOS> socket =
286 BluetoothSocketChromeOS::CreateBluetoothSocket(
287 ui_task_runner_, socket_thread_);
288 socket->Listen(this,
289 BluetoothSocketChromeOS::kRfcomm,
290 uuid,
291 options,
292 base::Bind(callback, socket),
293 error_callback);
296 void BluetoothAdapterChromeOS::CreateL2capService(
297 const BluetoothUUID& uuid,
298 const ServiceOptions& options,
299 const CreateServiceCallback& callback,
300 const CreateServiceErrorCallback& error_callback) {
301 DCHECK(!dbus_is_shutdown_);
302 VLOG(1) << object_path_.value() << ": Creating L2CAP service: "
303 << uuid.canonical_value();
304 scoped_refptr<BluetoothSocketChromeOS> socket =
305 BluetoothSocketChromeOS::CreateBluetoothSocket(
306 ui_task_runner_, socket_thread_);
307 socket->Listen(this,
308 BluetoothSocketChromeOS::kL2cap,
309 uuid,
310 options,
311 base::Bind(callback, socket),
312 error_callback);
315 void BluetoothAdapterChromeOS::RegisterAudioSink(
316 const BluetoothAudioSink::Options& options,
317 const device::BluetoothAdapter::AcquiredCallback& callback,
318 const BluetoothAudioSink::ErrorCallback& error_callback) {
319 VLOG(1) << "Registering audio sink";
320 if (!this->IsPresent()) {
321 error_callback.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER);
322 return;
324 scoped_refptr<BluetoothAudioSinkChromeOS> audio_sink(
325 new BluetoothAudioSinkChromeOS(this));
326 audio_sink->Register(
327 options, base::Bind(&BluetoothAdapterChromeOS::OnRegisterAudioSink,
328 weak_ptr_factory_.GetWeakPtr(), callback,
329 error_callback, audio_sink),
330 error_callback);
333 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
334 BluetoothDevice::PairingDelegate* pairing_delegate) {
335 // Before removing a pairing delegate make sure that there aren't any devices
336 // currently using it; if there are, clear the pairing context which will
337 // make any responses no-ops.
338 for (DevicesMap::iterator iter = devices_.begin();
339 iter != devices_.end(); ++iter) {
340 BluetoothDeviceChromeOS* device_chromeos =
341 static_cast<BluetoothDeviceChromeOS*>(iter->second);
343 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
344 if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
345 device_chromeos->EndPairing();
349 void BluetoothAdapterChromeOS::AdapterAdded(
350 const dbus::ObjectPath& object_path) {
351 // Set the adapter to the newly added adapter only if no adapter is present.
352 if (!IsPresent())
353 SetAdapter(object_path);
356 void BluetoothAdapterChromeOS::AdapterRemoved(
357 const dbus::ObjectPath& object_path) {
358 if (object_path == object_path_)
359 RemoveAdapter();
362 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
363 const dbus::ObjectPath& object_path,
364 const std::string& property_name) {
365 if (object_path != object_path_)
366 return;
367 DCHECK(IsPresent());
369 BluetoothAdapterClient::Properties* properties =
370 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
371 GetProperties(object_path_);
373 if (property_name == properties->powered.name())
374 PoweredChanged(properties->powered.value());
375 else if (property_name == properties->discoverable.name())
376 DiscoverableChanged(properties->discoverable.value());
377 else if (property_name == properties->discovering.name())
378 DiscoveringChanged(properties->discovering.value());
381 void BluetoothAdapterChromeOS::DeviceAdded(
382 const dbus::ObjectPath& object_path) {
383 DCHECK(DBusThreadManager::Get());
384 BluetoothDeviceClient::Properties* properties =
385 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
386 GetProperties(object_path);
387 if (!properties || properties->adapter.value() != object_path_)
388 return;
389 DCHECK(IsPresent());
391 BluetoothDeviceChromeOS* device_chromeos =
392 new BluetoothDeviceChromeOS(this,
393 object_path,
394 ui_task_runner_,
395 socket_thread_);
396 DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
398 devices_[device_chromeos->GetAddress()] = device_chromeos;
400 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
401 DeviceAdded(this, device_chromeos));
404 void BluetoothAdapterChromeOS::DeviceRemoved(
405 const dbus::ObjectPath& object_path) {
406 for (DevicesMap::iterator iter = devices_.begin();
407 iter != devices_.end(); ++iter) {
408 BluetoothDeviceChromeOS* device_chromeos =
409 static_cast<BluetoothDeviceChromeOS*>(iter->second);
410 if (device_chromeos->object_path() == object_path) {
411 devices_.erase(iter);
413 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
414 DeviceRemoved(this, device_chromeos));
415 delete device_chromeos;
416 return;
421 void BluetoothAdapterChromeOS::DevicePropertyChanged(
422 const dbus::ObjectPath& object_path,
423 const std::string& property_name) {
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 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
473 if (!device_chromeos)
474 return;
476 BluetoothInputClient::Properties* properties =
477 DBusThreadManager::Get()->GetBluetoothInputClient()->
478 GetProperties(object_path);
480 // Properties structure can be removed, which triggers a change in the
481 // BluetoothDevice::IsConnectable() property, as does a change in the
482 // actual reconnect_mode property.
483 if (!properties ||
484 property_name == properties->reconnect_mode.name())
485 NotifyDeviceChanged(device_chromeos);
488 void BluetoothAdapterChromeOS::Released() {
489 VLOG(1) << "Release";
490 if (!IsPresent())
491 return;
492 DCHECK(agent_.get());
494 // Called after we unregister the pairing agent, e.g. when changing I/O
495 // capabilities. Nothing much to be done right now.
498 void BluetoothAdapterChromeOS::RequestPinCode(
499 const dbus::ObjectPath& device_path,
500 const PinCodeCallback& callback) {
501 DCHECK(IsPresent());
502 DCHECK(agent_.get());
503 VLOG(1) << device_path.value() << ": RequestPinCode";
505 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
506 if (!pairing) {
507 callback.Run(REJECTED, "");
508 return;
511 pairing->RequestPinCode(callback);
514 void BluetoothAdapterChromeOS::DisplayPinCode(
515 const dbus::ObjectPath& device_path,
516 const std::string& pincode) {
517 DCHECK(IsPresent());
518 DCHECK(agent_.get());
519 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
521 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
522 if (!pairing)
523 return;
525 pairing->DisplayPinCode(pincode);
528 void BluetoothAdapterChromeOS::RequestPasskey(
529 const dbus::ObjectPath& device_path,
530 const PasskeyCallback& callback) {
531 DCHECK(IsPresent());
532 DCHECK(agent_.get());
533 VLOG(1) << device_path.value() << ": RequestPasskey";
535 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
536 if (!pairing) {
537 callback.Run(REJECTED, 0);
538 return;
541 pairing->RequestPasskey(callback);
544 void BluetoothAdapterChromeOS::DisplayPasskey(
545 const dbus::ObjectPath& device_path,
546 uint32 passkey,
547 uint16 entered) {
548 DCHECK(IsPresent());
549 DCHECK(agent_.get());
550 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
551 << " (" << entered << " entered)";
553 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
554 if (!pairing)
555 return;
557 if (entered == 0)
558 pairing->DisplayPasskey(passkey);
560 pairing->KeysEntered(entered);
563 void BluetoothAdapterChromeOS::RequestConfirmation(
564 const dbus::ObjectPath& device_path,
565 uint32 passkey,
566 const ConfirmationCallback& callback) {
567 DCHECK(IsPresent());
568 DCHECK(agent_.get());
569 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
571 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
572 if (!pairing) {
573 callback.Run(REJECTED);
574 return;
577 pairing->RequestConfirmation(passkey, callback);
580 void BluetoothAdapterChromeOS::RequestAuthorization(
581 const dbus::ObjectPath& device_path,
582 const ConfirmationCallback& callback) {
583 DCHECK(IsPresent());
584 DCHECK(agent_.get());
585 VLOG(1) << device_path.value() << ": RequestAuthorization";
587 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
588 if (!pairing) {
589 callback.Run(REJECTED);
590 return;
593 pairing->RequestAuthorization(callback);
596 void BluetoothAdapterChromeOS::AuthorizeService(
597 const dbus::ObjectPath& device_path,
598 const std::string& uuid,
599 const ConfirmationCallback& callback) {
600 DCHECK(IsPresent());
601 DCHECK(agent_.get());
602 VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
604 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(device_path);
605 if (!device_chromeos) {
606 callback.Run(CANCELLED);
607 return;
610 // We always set paired devices to Trusted, so the only reason that this
611 // method call would ever be called is in the case of a race condition where
612 // our "Set('Trusted', true)" method call is still pending in the Bluetooth
613 // daemon because it's busy handling the incoming connection.
614 if (device_chromeos->IsPaired()) {
615 callback.Run(SUCCESS);
616 return;
619 // TODO(keybuk): reject service authorizations when not paired, determine
620 // whether this is acceptable long-term.
621 LOG(WARNING) << "Rejecting service connection from unpaired device "
622 << device_chromeos->GetAddress() << " for UUID " << uuid;
623 callback.Run(REJECTED);
626 void BluetoothAdapterChromeOS::Cancel() {
627 DCHECK(IsPresent());
628 DCHECK(agent_.get());
629 VLOG(1) << "Cancel";
632 void BluetoothAdapterChromeOS::OnRegisterAgent() {
633 VLOG(1) << "Pairing agent registered, requesting to be made default";
635 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
636 RequestDefaultAgent(
637 dbus::ObjectPath(kAgentPath),
638 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
639 weak_ptr_factory_.GetWeakPtr()),
640 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
641 weak_ptr_factory_.GetWeakPtr()));
644 void BluetoothAdapterChromeOS::OnRegisterAgentError(
645 const std::string& error_name,
646 const std::string& error_message) {
647 // Our agent being already registered isn't an error.
648 if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
649 return;
651 LOG(WARNING) << ": Failed to register pairing agent: "
652 << error_name << ": " << error_message;
655 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
656 VLOG(1) << "Pairing agent now default";
659 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
660 const std::string& error_name,
661 const std::string& error_message) {
662 LOG(WARNING) << ": Failed to make pairing agent default: "
663 << error_name << ": " << error_message;
666 void BluetoothAdapterChromeOS::OnRegisterAudioSink(
667 const device::BluetoothAdapter::AcquiredCallback& callback,
668 const device::BluetoothAudioSink::ErrorCallback& error_callback,
669 scoped_refptr<BluetoothAudioSink> audio_sink) {
670 if (!IsPresent()) {
671 VLOG(1) << "Failed to register audio sink, adapter not present";
672 error_callback.Run(BluetoothAudioSink::ERROR_INVALID_ADAPTER);
673 return;
675 DCHECK(audio_sink.get());
676 callback.Run(audio_sink);
679 BluetoothDeviceChromeOS*
680 BluetoothAdapterChromeOS::GetDeviceWithPath(
681 const dbus::ObjectPath& object_path) {
682 if (!IsPresent())
683 return NULL;
685 for (DevicesMap::iterator iter = devices_.begin(); iter != devices_.end();
686 ++iter) {
687 BluetoothDeviceChromeOS* device_chromeos =
688 static_cast<BluetoothDeviceChromeOS*>(iter->second);
689 if (device_chromeos->object_path() == object_path)
690 return device_chromeos;
693 return NULL;
696 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
697 const dbus::ObjectPath& object_path) {
698 DCHECK(IsPresent());
699 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
700 if (!device_chromeos) {
701 LOG(WARNING) << "Pairing Agent request for unknown device: "
702 << object_path.value();
703 return NULL;
706 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
707 if (pairing)
708 return pairing;
710 // The device doesn't have its own pairing context, so this is an incoming
711 // pairing request that should use our best default delegate (if we have one).
712 BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
713 if (!pairing_delegate)
714 return NULL;
716 return device_chromeos->BeginPairing(pairing_delegate);
719 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
720 DCHECK(!IsPresent());
721 DCHECK(!dbus_is_shutdown_);
722 object_path_ = object_path;
724 VLOG(1) << object_path_.value() << ": using adapter.";
726 VLOG(1) << "Registering pairing agent";
727 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
728 RegisterAgent(
729 dbus::ObjectPath(kAgentPath),
730 bluetooth_agent_manager::kKeyboardDisplayCapability,
731 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
732 weak_ptr_factory_.GetWeakPtr()),
733 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
734 weak_ptr_factory_.GetWeakPtr()));
736 SetDefaultAdapterName();
738 BluetoothAdapterClient::Properties* properties =
739 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
740 GetProperties(object_path_);
742 PresentChanged(true);
744 if (properties->powered.value())
745 PoweredChanged(true);
746 if (properties->discoverable.value())
747 DiscoverableChanged(true);
748 if (properties->discovering.value())
749 DiscoveringChanged(true);
751 std::vector<dbus::ObjectPath> device_paths =
752 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
753 GetDevicesForAdapter(object_path_);
755 for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
756 iter != device_paths.end(); ++iter) {
757 DeviceAdded(*iter);
761 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
762 DCHECK(IsPresent());
763 std::string board = base::SysInfo::GetLsbReleaseBoard();
764 std::string alias;
765 if (board.substr(0, 6) == "stumpy") {
766 alias = "Chromebox";
767 } else if (board.substr(0, 4) == "link") {
768 alias = "Chromebook Pixel";
769 } else {
770 alias = "Chromebook";
773 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
776 void BluetoothAdapterChromeOS::RemoveAdapter() {
777 DCHECK(IsPresent());
778 VLOG(1) << object_path_.value() << ": adapter removed.";
780 BluetoothAdapterClient::Properties* properties =
781 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
782 GetProperties(object_path_);
784 object_path_ = dbus::ObjectPath("");
786 if (properties->powered.value())
787 PoweredChanged(false);
788 if (properties->discoverable.value())
789 DiscoverableChanged(false);
790 if (properties->discovering.value())
791 DiscoveringChanged(false);
793 // Copy the devices list here and clear the original so that when we
794 // send DeviceRemoved(), GetDevices() returns no devices.
795 DevicesMap devices = devices_;
796 devices_.clear();
798 for (DevicesMap::iterator iter = devices.begin();
799 iter != devices.end(); ++iter) {
800 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
801 DeviceRemoved(this, iter->second));
802 delete iter->second;
805 PresentChanged(false);
808 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
809 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
810 AdapterPoweredChanged(this, powered));
813 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
814 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
815 AdapterDiscoverableChanged(this, discoverable));
818 void BluetoothAdapterChromeOS::DiscoveringChanged(
819 bool discovering) {
820 // If the adapter stopped discovery due to a reason other than a request by
821 // us, reset the count to 0.
822 VLOG(1) << "Discovering changed: " << discovering;
823 if (!discovering && !discovery_request_pending_
824 && num_discovery_sessions_ > 0) {
825 VLOG(1) << "Marking sessions as inactive.";
826 num_discovery_sessions_ = 0;
827 MarkDiscoverySessionsAsInactive();
829 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
830 AdapterDiscoveringChanged(this, discovering));
833 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
834 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
835 AdapterPresentChanged(this, present));
838 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
839 BluetoothDeviceChromeOS* device) {
840 DCHECK(device->adapter_ == this);
842 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
843 DeviceChanged(this, device));
846 void BluetoothAdapterChromeOS::NotifyGattServiceAdded(
847 BluetoothRemoteGattServiceChromeOS* service) {
848 DCHECK_EQ(service->GetAdapter(), this);
849 DCHECK_EQ(
850 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
851 this);
853 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
854 observers_,
855 GattServiceAdded(this, service->GetDevice(), service));
858 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
859 BluetoothRemoteGattServiceChromeOS* service) {
860 DCHECK_EQ(service->GetAdapter(), this);
861 DCHECK_EQ(
862 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
863 this);
865 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
866 observers_,
867 GattServiceRemoved(this, service->GetDevice(), service));
870 void BluetoothAdapterChromeOS::NotifyGattServiceChanged(
871 BluetoothRemoteGattServiceChromeOS* service) {
872 DCHECK_EQ(service->GetAdapter(), this);
874 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
875 observers_,
876 GattServiceChanged(this, service));
879 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
880 BluetoothRemoteGattServiceChromeOS* service) {
881 DCHECK_EQ(service->GetAdapter(), this);
883 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
884 observers_,
885 GattDiscoveryCompleteForService(this, service));
888 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
889 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
890 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
891 characteristic->GetService())->GetAdapter(),
892 this);
894 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
895 observers_,
896 GattCharacteristicAdded(this, characteristic));
899 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
900 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
901 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
902 characteristic->GetService())->GetAdapter(),
903 this);
905 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
906 observers_,
907 GattCharacteristicRemoved(this, characteristic));
910 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
911 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
912 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
913 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
914 this);
916 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
917 observers_,
918 GattDescriptorAdded(this, descriptor));
921 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
922 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
923 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
924 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
925 this);
927 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
928 observers_,
929 GattDescriptorRemoved(this, descriptor));
932 void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged(
933 BluetoothRemoteGattCharacteristicChromeOS* characteristic,
934 const std::vector<uint8>& value) {
935 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
936 characteristic->GetService())->GetAdapter(),
937 this);
939 FOR_EACH_OBSERVER(
940 BluetoothAdapter::Observer,
941 observers_,
942 GattCharacteristicValueChanged(this, characteristic, value));
945 void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
946 BluetoothRemoteGattDescriptorChromeOS* descriptor,
947 const std::vector<uint8>& value) {
948 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
949 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
950 this);
952 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
953 observers_,
954 GattDescriptorValueChanged(this, descriptor, value));
957 void BluetoothAdapterChromeOS::UseProfile(
958 const BluetoothUUID& uuid,
959 const dbus::ObjectPath& device_path,
960 const BluetoothProfileManagerClient::Options& options,
961 BluetoothProfileServiceProvider::Delegate* delegate,
962 const ProfileRegisteredCallback& success_callback,
963 const ErrorCompletionCallback& error_callback) {
964 DCHECK(delegate);
966 if (!IsPresent()) {
967 VLOG(2) << "Adapter not present, erroring out";
968 error_callback.Run("Adapter not present");
969 return;
972 if (profiles_.find(uuid) != profiles_.end()) {
973 // TODO(jamuraa) check that the options are the same and error when they are
974 // not.
975 SetProfileDelegate(uuid, device_path, delegate, success_callback,
976 error_callback);
977 return;
980 if (profile_queues_.find(uuid) == profile_queues_.end()) {
981 BluetoothAdapterProfileChromeOS::Register(
982 uuid, options,
983 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfile, this, uuid),
984 base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfileError, this,
985 uuid));
987 profile_queues_[uuid] = new std::vector<RegisterProfileCompletionPair>();
990 profile_queues_[uuid]->push_back(std::make_pair(
991 base::Bind(&BluetoothAdapterChromeOS::SetProfileDelegate, this, uuid,
992 device_path, delegate, success_callback, error_callback),
993 error_callback));
996 void BluetoothAdapterChromeOS::ReleaseProfile(
997 const dbus::ObjectPath& device_path,
998 BluetoothAdapterProfileChromeOS* profile) {
999 VLOG(2) << "Releasing Profile: " << profile->uuid().canonical_value()
1000 << " from " << device_path.value();
1001 profile->RemoveDelegate(
1002 device_path, base::Bind(&BluetoothAdapterChromeOS::RemoveProfile,
1003 weak_ptr_factory_.GetWeakPtr(), profile->uuid()));
1006 void BluetoothAdapterChromeOS::RemoveProfile(const BluetoothUUID& uuid) {
1007 VLOG(2) << "Remove Profile: " << uuid.canonical_value();
1009 if (profiles_.find(uuid) != profiles_.end()) {
1010 delete profiles_[uuid];
1011 profiles_.erase(uuid);
1015 void BluetoothAdapterChromeOS::OnRegisterProfile(
1016 const BluetoothUUID& uuid,
1017 scoped_ptr<BluetoothAdapterProfileChromeOS> profile) {
1018 profiles_[uuid] = profile.release();
1020 if (profile_queues_.find(uuid) == profile_queues_.end())
1021 return;
1023 for (auto& it : *profile_queues_[uuid])
1024 it.first.Run();
1025 delete profile_queues_[uuid];
1026 profile_queues_.erase(uuid);
1029 void BluetoothAdapterChromeOS::SetProfileDelegate(
1030 const BluetoothUUID& uuid,
1031 const dbus::ObjectPath& device_path,
1032 BluetoothProfileServiceProvider::Delegate* delegate,
1033 const ProfileRegisteredCallback& success_callback,
1034 const ErrorCompletionCallback& error_callback) {
1035 if (profiles_.find(uuid) == profiles_.end()) {
1036 error_callback.Run("Cannot find profile!");
1037 return;
1040 if (profiles_[uuid]->SetDelegate(device_path, delegate)) {
1041 success_callback.Run(profiles_[uuid]);
1042 return;
1044 // Already set
1045 error_callback.Run(bluetooth_agent_manager::kErrorAlreadyExists);
1048 void BluetoothAdapterChromeOS::OnRegisterProfileError(
1049 const BluetoothUUID& uuid,
1050 const std::string& error_name,
1051 const std::string& error_message) {
1052 VLOG(2) << object_path_.value() << ": Failed to register profile: "
1053 << error_name << ": " << error_message;
1054 if (profile_queues_.find(uuid) == profile_queues_.end())
1055 return;
1057 for (auto& it : *profile_queues_[uuid])
1058 it.second.Run(error_message);
1060 delete profile_queues_[uuid];
1061 profile_queues_.erase(uuid);
1064 void BluetoothAdapterChromeOS::OnSetDiscoverable(
1065 const base::Closure& callback,
1066 const ErrorCallback& error_callback,
1067 bool success) {
1068 if (!IsPresent()) {
1069 error_callback.Run();
1070 return;
1073 // Set the discoverable_timeout property to zero so the adapter remains
1074 // discoverable forever.
1075 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1076 GetProperties(object_path_)->discoverable_timeout.Set(
1078 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
1079 weak_ptr_factory_.GetWeakPtr(),
1080 callback,
1081 error_callback));
1084 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
1085 const base::Closure& callback,
1086 const ErrorCallback& error_callback,
1087 bool success) {
1088 if (IsPresent() && success)
1089 callback.Run();
1090 else
1091 error_callback.Run();
1094 void BluetoothAdapterChromeOS::AddDiscoverySession(
1095 BluetoothDiscoveryFilter* discovery_filter,
1096 const base::Closure& callback,
1097 const ErrorCallback& error_callback) {
1098 if (!IsPresent()) {
1099 error_callback.Run();
1100 return;
1102 VLOG(1) << __func__;
1103 if (discovery_request_pending_) {
1104 // The pending request is either to stop a previous session or to start a
1105 // new one. Either way, queue this one.
1106 DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
1107 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
1108 << "request to start a new discovery session.";
1109 discovery_request_queue_.push(std::make_pair(callback, error_callback));
1110 return;
1113 // The adapter is already discovering.
1114 if (num_discovery_sessions_ > 0) {
1115 DCHECK(IsDiscovering());
1116 DCHECK(!discovery_request_pending_);
1117 num_discovery_sessions_++;
1118 callback.Run();
1119 return;
1122 // There are no active discovery sessions.
1123 DCHECK_EQ(num_discovery_sessions_, 0);
1125 // This is the first request to start device discovery.
1126 discovery_request_pending_ = true;
1127 DBusThreadManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
1128 object_path_,
1129 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
1130 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
1131 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
1132 weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
1135 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
1136 BluetoothDiscoveryFilter* discovery_filter,
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::SetDiscoveryFilter(
1188 scoped_ptr<BluetoothDiscoveryFilter> discovery_filter,
1189 const base::Closure& callback,
1190 const ErrorCallback& error_callback) {
1191 // TODO(jpawlowski): Implement
1194 void BluetoothAdapterChromeOS::OnStartDiscovery(
1195 const base::Closure& callback,
1196 const ErrorCallback& error_callback) {
1197 // Report success on the original request and increment the count.
1198 VLOG(1) << __func__;
1199 DCHECK(discovery_request_pending_);
1200 DCHECK_EQ(num_discovery_sessions_, 0);
1201 discovery_request_pending_ = false;
1202 num_discovery_sessions_++;
1203 if (IsPresent())
1204 callback.Run();
1205 else
1206 error_callback.Run();
1208 // Try to add a new discovery session for each queued request.
1209 ProcessQueuedDiscoveryRequests();
1212 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
1213 const base::Closure& callback,
1214 const ErrorCallback& error_callback,
1215 const std::string& error_name,
1216 const std::string& error_message) {
1217 LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
1218 << error_name << ": " << error_message;
1220 // Failed to start discovery. This can only happen if the count is at 0.
1221 DCHECK_EQ(num_discovery_sessions_, 0);
1222 DCHECK(discovery_request_pending_);
1223 discovery_request_pending_ = false;
1225 // Discovery request may fail if discovery was previously initiated by Chrome,
1226 // but the session were invalidated due to the discovery state unexpectedly
1227 // changing to false and then back to true. In this case, report success.
1228 if (IsPresent() && error_name == bluetooth_device::kErrorInProgress &&
1229 IsDiscovering()) {
1230 VLOG(1) << "Discovery previously initiated. Reporting success.";
1231 num_discovery_sessions_++;
1232 callback.Run();
1233 } else {
1234 error_callback.Run();
1237 // Try to add a new discovery session for each queued request.
1238 ProcessQueuedDiscoveryRequests();
1241 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
1242 // Report success on the original request and decrement the count.
1243 VLOG(1) << __func__;
1244 DCHECK(discovery_request_pending_);
1245 DCHECK_EQ(num_discovery_sessions_, 1);
1246 discovery_request_pending_ = false;
1247 num_discovery_sessions_--;
1248 callback.Run();
1250 // Try to add a new discovery session for each queued request.
1251 ProcessQueuedDiscoveryRequests();
1254 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
1255 const ErrorCallback& error_callback,
1256 const std::string& error_name,
1257 const std::string& error_message) {
1258 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
1259 << error_name << ": " << error_message;
1261 // Failed to stop discovery. This can only happen if the count is at 1.
1262 DCHECK(discovery_request_pending_);
1263 DCHECK_EQ(num_discovery_sessions_, 1);
1264 discovery_request_pending_ = false;
1265 error_callback.Run();
1267 // Try to add a new discovery session for each queued request.
1268 ProcessQueuedDiscoveryRequests();
1271 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
1272 while (!discovery_request_queue_.empty()) {
1273 VLOG(1) << "Process queued discovery request.";
1274 DiscoveryCallbackPair callbacks = discovery_request_queue_.front();
1275 discovery_request_queue_.pop();
1276 AddDiscoverySession(nullptr, callbacks.first, callbacks.second);
1278 // If the queued request resulted in a pending call, then let it
1279 // asynchonously process the remaining queued requests once the pending
1280 // call returns.
1281 if (discovery_request_pending_)
1282 return;
1286 } // namespace chromeos