Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_chromeos.cc
bloba5f1a98e6e62ff015621560292779f3f78896f86
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/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/sys_info.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 "device/bluetooth/bluetooth_device.h"
23 #include "device/bluetooth/bluetooth_device_chromeos.h"
24 #include "device/bluetooth/bluetooth_pairing_chromeos.h"
25 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
26 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
27 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
28 #include "device/bluetooth/bluetooth_socket_chromeos.h"
29 #include "device/bluetooth/bluetooth_socket_thread.h"
30 #include "device/bluetooth/bluetooth_uuid.h"
31 #include "third_party/cros_system_api/dbus/service_constants.h"
33 using device::BluetoothAdapter;
34 using device::BluetoothDevice;
35 using device::BluetoothSocket;
36 using device::BluetoothUUID;
38 namespace {
40 // The agent path is relatively meaningless since BlueZ only permits one to
41 // exist per D-Bus connection, it just has to be unique within Chromium.
42 const char kAgentPath[] = "/org/chromium/bluetooth_agent";
44 void OnUnregisterAgentError(const std::string& error_name,
45 const std::string& error_message) {
46 // It's okay if the agent didn't exist, it means we never saw an adapter.
47 if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
48 return;
50 LOG(WARNING) << "Failed to unregister pairing agent: "
51 << error_name << ": " << error_message;
54 } // namespace
56 namespace device {
58 // static
59 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
60 const InitCallback& init_callback) {
61 return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
66 namespace chromeos {
68 // static
69 base::WeakPtr<BluetoothAdapter> BluetoothAdapterChromeOS::CreateAdapter() {
70 BluetoothAdapterChromeOS* adapter = new BluetoothAdapterChromeOS();
71 return adapter->weak_ptr_factory_.GetWeakPtr();
74 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
75 : num_discovery_sessions_(0),
76 discovery_request_pending_(false),
77 weak_ptr_factory_(this) {
78 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
79 socket_thread_ = device::BluetoothSocketThread::Get();
81 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
82 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
83 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
85 // Register the pairing agent.
86 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
87 agent_.reset(BluetoothAgentServiceProvider::Create(
88 system_bus, dbus::ObjectPath(kAgentPath), this));
89 DCHECK(agent_.get());
91 std::vector<dbus::ObjectPath> object_paths =
92 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
94 if (!object_paths.empty()) {
95 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
96 SetAdapter(object_paths[0]);
100 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
101 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
102 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
103 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
105 VLOG(1) << "Unregistering pairing agent";
106 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
107 UnregisterAgent(
108 dbus::ObjectPath(kAgentPath),
109 base::Bind(&base::DoNothing),
110 base::Bind(&OnUnregisterAgentError));
113 void BluetoothAdapterChromeOS::AddObserver(
114 BluetoothAdapter::Observer* observer) {
115 DCHECK(observer);
116 observers_.AddObserver(observer);
119 void BluetoothAdapterChromeOS::RemoveObserver(
120 BluetoothAdapter::Observer* observer) {
121 DCHECK(observer);
122 observers_.RemoveObserver(observer);
125 std::string BluetoothAdapterChromeOS::GetAddress() const {
126 if (!IsPresent())
127 return std::string();
129 BluetoothAdapterClient::Properties* properties =
130 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
131 GetProperties(object_path_);
132 DCHECK(properties);
134 return BluetoothDevice::CanonicalizeAddress(properties->address.value());
137 std::string BluetoothAdapterChromeOS::GetName() const {
138 if (!IsPresent())
139 return std::string();
141 BluetoothAdapterClient::Properties* properties =
142 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
143 GetProperties(object_path_);
144 DCHECK(properties);
146 return properties->alias.value();
149 void BluetoothAdapterChromeOS::SetName(const std::string& name,
150 const base::Closure& callback,
151 const ErrorCallback& error_callback) {
152 if (!IsPresent())
153 error_callback.Run();
155 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
156 GetProperties(object_path_)->alias.Set(
157 name,
158 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
159 weak_ptr_factory_.GetWeakPtr(),
160 callback,
161 error_callback));
164 bool BluetoothAdapterChromeOS::IsInitialized() const {
165 return true;
168 bool BluetoothAdapterChromeOS::IsPresent() const {
169 return !object_path_.value().empty();
172 bool BluetoothAdapterChromeOS::IsPowered() const {
173 if (!IsPresent())
174 return false;
176 BluetoothAdapterClient::Properties* properties =
177 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
178 GetProperties(object_path_);
180 return properties->powered.value();
183 void BluetoothAdapterChromeOS::SetPowered(
184 bool powered,
185 const base::Closure& callback,
186 const ErrorCallback& error_callback) {
187 if (!IsPresent())
188 error_callback.Run();
190 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
191 GetProperties(object_path_)->powered.Set(
192 powered,
193 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
194 weak_ptr_factory_.GetWeakPtr(),
195 callback,
196 error_callback));
199 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
200 if (!IsPresent())
201 return false;
203 BluetoothAdapterClient::Properties* properties =
204 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
205 GetProperties(object_path_);
207 return properties->discoverable.value();
210 void BluetoothAdapterChromeOS::SetDiscoverable(
211 bool discoverable,
212 const base::Closure& callback,
213 const ErrorCallback& error_callback) {
214 if (!IsPresent())
215 error_callback.Run();
217 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
218 GetProperties(object_path_)->discoverable.Set(
219 discoverable,
220 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
221 weak_ptr_factory_.GetWeakPtr(),
222 callback,
223 error_callback));
226 bool BluetoothAdapterChromeOS::IsDiscovering() const {
227 if (!IsPresent())
228 return false;
230 BluetoothAdapterClient::Properties* properties =
231 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
232 GetProperties(object_path_);
234 return properties->discovering.value();
237 void BluetoothAdapterChromeOS::CreateRfcommService(
238 const BluetoothUUID& uuid,
239 const ServiceOptions& options,
240 const CreateServiceCallback& callback,
241 const CreateServiceErrorCallback& error_callback) {
242 VLOG(1) << object_path_.value() << ": Creating RFCOMM service: "
243 << uuid.canonical_value();
244 scoped_refptr<BluetoothSocketChromeOS> socket =
245 BluetoothSocketChromeOS::CreateBluetoothSocket(
246 ui_task_runner_, socket_thread_);
247 socket->Listen(this,
248 BluetoothSocketChromeOS::kRfcomm,
249 uuid,
250 options,
251 base::Bind(callback, socket),
252 error_callback);
255 void BluetoothAdapterChromeOS::CreateL2capService(
256 const BluetoothUUID& uuid,
257 const ServiceOptions& options,
258 const CreateServiceCallback& callback,
259 const CreateServiceErrorCallback& error_callback) {
260 VLOG(1) << object_path_.value() << ": Creating L2CAP service: "
261 << uuid.canonical_value();
262 scoped_refptr<BluetoothSocketChromeOS> socket =
263 BluetoothSocketChromeOS::CreateBluetoothSocket(
264 ui_task_runner_, socket_thread_);
265 socket->Listen(this,
266 BluetoothSocketChromeOS::kL2cap,
267 uuid,
268 options,
269 base::Bind(callback, socket),
270 error_callback);
273 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
274 BluetoothDevice::PairingDelegate* pairing_delegate) {
275 // Before removing a pairing delegate make sure that there aren't any devices
276 // currently using it; if there are, clear the pairing context which will
277 // make any responses no-ops.
278 for (DevicesMap::iterator iter = devices_.begin();
279 iter != devices_.end(); ++iter) {
280 BluetoothDeviceChromeOS* device_chromeos =
281 static_cast<BluetoothDeviceChromeOS*>(iter->second);
283 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
284 if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
285 device_chromeos->EndPairing();
289 void BluetoothAdapterChromeOS::AdapterAdded(
290 const dbus::ObjectPath& object_path) {
291 // Set the adapter to the newly added adapter only if no adapter is present.
292 if (!IsPresent())
293 SetAdapter(object_path);
296 void BluetoothAdapterChromeOS::AdapterRemoved(
297 const dbus::ObjectPath& object_path) {
298 if (object_path == object_path_)
299 RemoveAdapter();
302 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
303 const dbus::ObjectPath& object_path,
304 const std::string& property_name) {
305 if (object_path != object_path_)
306 return;
308 BluetoothAdapterClient::Properties* properties =
309 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
310 GetProperties(object_path_);
312 if (property_name == properties->powered.name())
313 PoweredChanged(properties->powered.value());
314 else if (property_name == properties->discoverable.name())
315 DiscoverableChanged(properties->discoverable.value());
316 else if (property_name == properties->discovering.name())
317 DiscoveringChanged(properties->discovering.value());
320 void BluetoothAdapterChromeOS::DeviceAdded(
321 const dbus::ObjectPath& object_path) {
322 BluetoothDeviceClient::Properties* properties =
323 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
324 GetProperties(object_path);
325 if (properties->adapter.value() != object_path_)
326 return;
328 BluetoothDeviceChromeOS* device_chromeos =
329 new BluetoothDeviceChromeOS(this,
330 object_path,
331 ui_task_runner_,
332 socket_thread_);
333 DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
335 devices_[device_chromeos->GetAddress()] = device_chromeos;
337 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
338 DeviceAdded(this, device_chromeos));
341 void BluetoothAdapterChromeOS::DeviceRemoved(
342 const dbus::ObjectPath& object_path) {
343 for (DevicesMap::iterator iter = devices_.begin();
344 iter != devices_.end(); ++iter) {
345 BluetoothDeviceChromeOS* device_chromeos =
346 static_cast<BluetoothDeviceChromeOS*>(iter->second);
347 if (device_chromeos->object_path() == object_path) {
348 devices_.erase(iter);
350 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
351 DeviceRemoved(this, device_chromeos));
352 delete device_chromeos;
353 return;
358 void BluetoothAdapterChromeOS::DevicePropertyChanged(
359 const dbus::ObjectPath& object_path,
360 const std::string& property_name) {
361 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
362 if (!device_chromeos)
363 return;
365 BluetoothDeviceClient::Properties* properties =
366 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
367 GetProperties(object_path);
369 if (property_name == properties->bluetooth_class.name() ||
370 property_name == properties->address.name() ||
371 property_name == properties->alias.name() ||
372 property_name == properties->paired.name() ||
373 property_name == properties->trusted.name() ||
374 property_name == properties->connected.name() ||
375 property_name == properties->uuids.name() ||
376 property_name == properties->rssi.name() ||
377 property_name == properties->connection_rssi.name() ||
378 property_name == properties->connection_tx_power.name())
379 NotifyDeviceChanged(device_chromeos);
381 // When a device becomes paired, mark it as trusted so that the user does
382 // not need to approve every incoming connection
383 if (property_name == properties->paired.name() &&
384 properties->paired.value() && !properties->trusted.value())
385 device_chromeos->SetTrusted();
387 // UMA connection counting
388 if (property_name == properties->connected.name()) {
389 // PlayStation joystick tries to reconnect after disconnection from USB.
390 // If it is still not trusted, set it, so it becomes available on the
391 // list of known devices.
392 if (properties->connected.value() && device_chromeos->IsTrustable() &&
393 !properties->trusted.value())
394 device_chromeos->SetTrusted();
396 int count = 0;
398 for (DevicesMap::iterator iter = devices_.begin();
399 iter != devices_.end(); ++iter) {
400 if (iter->second->IsPaired() && iter->second->IsConnected())
401 ++count;
404 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
408 void BluetoothAdapterChromeOS::InputPropertyChanged(
409 const dbus::ObjectPath& object_path,
410 const std::string& property_name) {
411 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
412 if (!device_chromeos)
413 return;
415 BluetoothInputClient::Properties* properties =
416 DBusThreadManager::Get()->GetBluetoothInputClient()->
417 GetProperties(object_path);
419 // Properties structure can be removed, which triggers a change in the
420 // BluetoothDevice::IsConnectable() property, as does a change in the
421 // actual reconnect_mode property.
422 if (!properties ||
423 property_name == properties->reconnect_mode.name())
424 NotifyDeviceChanged(device_chromeos);
427 void BluetoothAdapterChromeOS::Released() {
428 DCHECK(agent_.get());
429 VLOG(1) << "Release";
431 // Called after we unregister the pairing agent, e.g. when changing I/O
432 // capabilities. Nothing much to be done right now.
435 void BluetoothAdapterChromeOS::RequestPinCode(
436 const dbus::ObjectPath& device_path,
437 const PinCodeCallback& callback) {
438 DCHECK(agent_.get());
439 VLOG(1) << device_path.value() << ": RequestPinCode";
441 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
442 if (!pairing) {
443 callback.Run(REJECTED, "");
444 return;
447 pairing->RequestPinCode(callback);
450 void BluetoothAdapterChromeOS::DisplayPinCode(
451 const dbus::ObjectPath& device_path,
452 const std::string& pincode) {
453 DCHECK(agent_.get());
454 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
456 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
457 if (!pairing)
458 return;
460 pairing->DisplayPinCode(pincode);
463 void BluetoothAdapterChromeOS::RequestPasskey(
464 const dbus::ObjectPath& device_path,
465 const PasskeyCallback& callback) {
466 DCHECK(agent_.get());
467 VLOG(1) << device_path.value() << ": RequestPasskey";
469 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
470 if (!pairing) {
471 callback.Run(REJECTED, 0);
472 return;
475 pairing->RequestPasskey(callback);
478 void BluetoothAdapterChromeOS::DisplayPasskey(
479 const dbus::ObjectPath& device_path,
480 uint32 passkey,
481 uint16 entered) {
482 DCHECK(agent_.get());
483 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
484 << " (" << entered << " entered)";
486 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
487 if (!pairing)
488 return;
490 if (entered == 0)
491 pairing->DisplayPasskey(passkey);
493 pairing->KeysEntered(entered);
496 void BluetoothAdapterChromeOS::RequestConfirmation(
497 const dbus::ObjectPath& device_path,
498 uint32 passkey,
499 const ConfirmationCallback& callback) {
500 DCHECK(agent_.get());
501 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
503 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
504 if (!pairing) {
505 callback.Run(REJECTED);
506 return;
509 pairing->RequestConfirmation(passkey, callback);
512 void BluetoothAdapterChromeOS::RequestAuthorization(
513 const dbus::ObjectPath& device_path,
514 const ConfirmationCallback& callback) {
515 DCHECK(agent_.get());
516 VLOG(1) << device_path.value() << ": RequestAuthorization";
518 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
519 if (!pairing) {
520 callback.Run(REJECTED);
521 return;
524 pairing->RequestAuthorization(callback);
527 void BluetoothAdapterChromeOS::AuthorizeService(
528 const dbus::ObjectPath& device_path,
529 const std::string& uuid,
530 const ConfirmationCallback& callback) {
531 DCHECK(agent_.get());
532 VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
534 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(device_path);
535 if (!device_chromeos) {
536 callback.Run(CANCELLED);
537 return;
540 // We always set paired devices to Trusted, so the only reason that this
541 // method call would ever be called is in the case of a race condition where
542 // our "Set('Trusted', true)" method call is still pending in the Bluetooth
543 // daemon because it's busy handling the incoming connection.
544 if (device_chromeos->IsPaired()) {
545 callback.Run(SUCCESS);
546 return;
549 // TODO(keybuk): reject service authorizations when not paired, determine
550 // whether this is acceptable long-term.
551 LOG(WARNING) << "Rejecting service connection from unpaired device "
552 << device_chromeos->GetAddress() << " for UUID " << uuid;
553 callback.Run(REJECTED);
556 void BluetoothAdapterChromeOS::Cancel() {
557 DCHECK(agent_.get());
558 VLOG(1) << "Cancel";
561 void BluetoothAdapterChromeOS::OnRegisterAgent() {
562 VLOG(1) << "Pairing agent registered, requesting to be made default";
564 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
565 RequestDefaultAgent(
566 dbus::ObjectPath(kAgentPath),
567 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
568 weak_ptr_factory_.GetWeakPtr()),
569 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
570 weak_ptr_factory_.GetWeakPtr()));
574 void BluetoothAdapterChromeOS::OnRegisterAgentError(
575 const std::string& error_name,
576 const std::string& error_message) {
577 // Our agent being already registered isn't an error.
578 if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
579 return;
581 LOG(WARNING) << ": Failed to register pairing agent: "
582 << error_name << ": " << error_message;
585 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
586 VLOG(1) << "Pairing agent now default";
589 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
590 const std::string& error_name,
591 const std::string& error_message) {
592 LOG(WARNING) << ": Failed to make pairing agent default: "
593 << error_name << ": " << error_message;
596 BluetoothDeviceChromeOS*
597 BluetoothAdapterChromeOS::GetDeviceWithPath(
598 const dbus::ObjectPath& object_path) {
599 for (DevicesMap::iterator iter = devices_.begin();
600 iter != devices_.end(); ++iter) {
601 BluetoothDeviceChromeOS* device_chromeos =
602 static_cast<BluetoothDeviceChromeOS*>(iter->second);
603 if (device_chromeos->object_path() == object_path)
604 return device_chromeos;
607 return NULL;
610 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
611 const dbus::ObjectPath& object_path)
613 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
614 if (!device_chromeos) {
615 LOG(WARNING) << "Pairing Agent request for unknown device: "
616 << object_path.value();
617 return NULL;
620 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
621 if (pairing)
622 return pairing;
624 // The device doesn't have its own pairing context, so this is an incoming
625 // pairing request that should use our best default delegate (if we have one).
626 BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
627 if (!pairing_delegate)
628 return NULL;
630 return device_chromeos->BeginPairing(pairing_delegate);
633 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
634 DCHECK(!IsPresent());
635 object_path_ = object_path;
637 VLOG(1) << object_path_.value() << ": using adapter.";
639 VLOG(1) << "Registering pairing agent";
640 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
641 RegisterAgent(
642 dbus::ObjectPath(kAgentPath),
643 bluetooth_agent_manager::kKeyboardDisplayCapability,
644 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
645 weak_ptr_factory_.GetWeakPtr()),
646 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
647 weak_ptr_factory_.GetWeakPtr()));
649 SetDefaultAdapterName();
651 BluetoothAdapterClient::Properties* properties =
652 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
653 GetProperties(object_path_);
655 PresentChanged(true);
657 if (properties->powered.value())
658 PoweredChanged(true);
659 if (properties->discoverable.value())
660 DiscoverableChanged(true);
661 if (properties->discovering.value())
662 DiscoveringChanged(true);
664 std::vector<dbus::ObjectPath> device_paths =
665 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
666 GetDevicesForAdapter(object_path_);
668 for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
669 iter != device_paths.end(); ++iter) {
670 DeviceAdded(*iter);
674 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
675 std::string board = base::SysInfo::GetLsbReleaseBoard();
676 std::string alias;
677 if (board.substr(0, 6) == "stumpy") {
678 alias = "Chromebox";
679 } else if (board.substr(0, 4) == "link") {
680 alias = "Chromebook Pixel";
681 } else {
682 alias = "Chromebook";
685 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
688 void BluetoothAdapterChromeOS::RemoveAdapter() {
689 DCHECK(IsPresent());
690 VLOG(1) << object_path_.value() << ": adapter removed.";
692 BluetoothAdapterClient::Properties* properties =
693 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
694 GetProperties(object_path_);
696 object_path_ = dbus::ObjectPath("");
698 if (properties->powered.value())
699 PoweredChanged(false);
700 if (properties->discoverable.value())
701 DiscoverableChanged(false);
702 if (properties->discovering.value())
703 DiscoveringChanged(false);
705 // Copy the devices list here and clear the original so that when we
706 // send DeviceRemoved(), GetDevices() returns no devices.
707 DevicesMap devices = devices_;
708 devices_.clear();
710 for (DevicesMap::iterator iter = devices.begin();
711 iter != devices.end(); ++iter) {
712 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
713 DeviceRemoved(this, iter->second));
714 delete iter->second;
717 PresentChanged(false);
720 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
721 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
722 AdapterPoweredChanged(this, powered));
725 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
726 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
727 AdapterDiscoverableChanged(this, discoverable));
730 void BluetoothAdapterChromeOS::DiscoveringChanged(
731 bool discovering) {
732 // If the adapter stopped discovery due to a reason other than a request by
733 // us, reset the count to 0.
734 VLOG(1) << "Discovering changed: " << discovering;
735 if (!discovering && !discovery_request_pending_
736 && num_discovery_sessions_ > 0) {
737 VLOG(1) << "Marking sessions as inactive.";
738 num_discovery_sessions_ = 0;
739 MarkDiscoverySessionsAsInactive();
741 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
742 AdapterDiscoveringChanged(this, discovering));
745 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
746 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
747 AdapterPresentChanged(this, present));
750 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
751 BluetoothDeviceChromeOS* device) {
752 DCHECK(device->adapter_ == this);
754 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
755 DeviceChanged(this, device));
758 void BluetoothAdapterChromeOS::NotifyGattServiceAdded(
759 BluetoothRemoteGattServiceChromeOS* service) {
760 DCHECK_EQ(service->GetAdapter(), this);
761 DCHECK_EQ(
762 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
763 this);
765 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
766 observers_,
767 GattServiceAdded(this, service->GetDevice(), service));
770 void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
771 BluetoothRemoteGattServiceChromeOS* service) {
772 DCHECK_EQ(service->GetAdapter(), this);
773 DCHECK_EQ(
774 static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
775 this);
777 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
778 observers_,
779 GattServiceRemoved(this, service->GetDevice(), service));
782 void BluetoothAdapterChromeOS::NotifyGattServiceChanged(
783 BluetoothRemoteGattServiceChromeOS* service) {
784 DCHECK_EQ(service->GetAdapter(), this);
786 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
787 observers_,
788 GattServiceChanged(this, service));
791 void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
792 BluetoothRemoteGattServiceChromeOS* service) {
793 DCHECK_EQ(service->GetAdapter(), this);
795 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
796 observers_,
797 GattDiscoveryCompleteForService(this, service));
800 void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
801 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
802 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
803 characteristic->GetService())->GetAdapter(),
804 this);
806 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
807 observers_,
808 GattCharacteristicAdded(this, characteristic));
811 void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
812 BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
813 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
814 characteristic->GetService())->GetAdapter(),
815 this);
817 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
818 observers_,
819 GattCharacteristicRemoved(this, characteristic));
822 void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
823 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
824 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
825 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
826 this);
828 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
829 observers_,
830 GattDescriptorAdded(this, descriptor));
833 void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
834 BluetoothRemoteGattDescriptorChromeOS* descriptor) {
835 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
836 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
837 this);
839 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
840 observers_,
841 GattDescriptorRemoved(this, descriptor));
844 void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged(
845 BluetoothRemoteGattCharacteristicChromeOS* characteristic,
846 const std::vector<uint8>& value) {
847 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
848 characteristic->GetService())->GetAdapter(),
849 this);
851 FOR_EACH_OBSERVER(
852 BluetoothAdapter::Observer,
853 observers_,
854 GattCharacteristicValueChanged(this, characteristic, value));
857 void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
858 BluetoothRemoteGattDescriptorChromeOS* descriptor,
859 const std::vector<uint8>& value) {
860 DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
861 descriptor->GetCharacteristic()->GetService())->GetAdapter(),
862 this);
864 FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
865 observers_,
866 GattDescriptorValueChanged(this, descriptor, value));
869 void BluetoothAdapterChromeOS::OnSetDiscoverable(
870 const base::Closure& callback,
871 const ErrorCallback& error_callback,
872 bool success) {
873 // Set the discoverable_timeout property to zero so the adapter remains
874 // discoverable forever.
875 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
876 GetProperties(object_path_)->discoverable_timeout.Set(
878 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
879 weak_ptr_factory_.GetWeakPtr(),
880 callback,
881 error_callback));
884 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
885 const base::Closure& callback,
886 const ErrorCallback& error_callback,
887 bool success) {
888 if (success)
889 callback.Run();
890 else
891 error_callback.Run();
894 void BluetoothAdapterChromeOS::AddDiscoverySession(
895 const base::Closure& callback,
896 const ErrorCallback& error_callback) {
897 VLOG(1) << __func__;
898 if (discovery_request_pending_) {
899 // The pending request is either to stop a previous session or to start a
900 // new one. Either way, queue this one.
901 DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
902 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
903 << "request to start a new discovery session.";
904 discovery_request_queue_.push(std::make_pair(callback, error_callback));
905 return;
908 // The adapter is already discovering.
909 if (num_discovery_sessions_ > 0) {
910 DCHECK(IsDiscovering());
911 DCHECK(!discovery_request_pending_);
912 num_discovery_sessions_++;
913 callback.Run();
914 return;
917 // There are no active discovery sessions.
918 DCHECK(num_discovery_sessions_ == 0);
920 // This is the first request to start device discovery.
921 discovery_request_pending_ = true;
922 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
923 StartDiscovery(
924 object_path_,
925 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
926 weak_ptr_factory_.GetWeakPtr(),
927 callback),
928 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
929 weak_ptr_factory_.GetWeakPtr(),
930 callback,
931 error_callback));
934 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
935 const base::Closure& callback,
936 const ErrorCallback& error_callback) {
937 VLOG(1) << __func__;
938 // There are active sessions other than the one currently being removed.
939 if (num_discovery_sessions_ > 1) {
940 DCHECK(IsDiscovering());
941 DCHECK(!discovery_request_pending_);
942 num_discovery_sessions_--;
943 callback.Run();
944 return;
947 // If there is a pending request to BlueZ, then queue this request.
948 if (discovery_request_pending_) {
949 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
950 << "request to stop discovery session.";
951 error_callback.Run();
952 return;
955 // There are no active sessions. Return error.
956 if (num_discovery_sessions_ == 0) {
957 // TODO(armansito): This should never happen once we have the
958 // DiscoverySession API. Replace this case with an assert once it's
959 // the deprecated methods have been removed. (See crbug.com/3445008).
960 VLOG(1) << "No active discovery sessions. Returning error.";
961 error_callback.Run();
962 return;
965 // There is exactly one active discovery session. Request BlueZ to stop
966 // discovery.
967 DCHECK(num_discovery_sessions_ == 1);
968 discovery_request_pending_ = true;
969 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
970 StopDiscovery(
971 object_path_,
972 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
973 weak_ptr_factory_.GetWeakPtr(),
974 callback),
975 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
976 weak_ptr_factory_.GetWeakPtr(),
977 error_callback));
980 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) {
981 // Report success on the original request and increment the count.
982 VLOG(1) << __func__;
983 DCHECK(discovery_request_pending_);
984 DCHECK(num_discovery_sessions_ == 0);
985 discovery_request_pending_ = false;
986 num_discovery_sessions_++;
987 callback.Run();
989 // Try to add a new discovery session for each queued request.
990 ProcessQueuedDiscoveryRequests();
993 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
994 const base::Closure& callback,
995 const ErrorCallback& error_callback,
996 const std::string& error_name,
997 const std::string& error_message) {
998 LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
999 << error_name << ": " << error_message;
1001 // Failed to start discovery. This can only happen if the count is at 0.
1002 DCHECK(num_discovery_sessions_ == 0);
1003 DCHECK(discovery_request_pending_);
1004 discovery_request_pending_ = false;
1006 // Discovery request may fail if discovery was previously initiated by Chrome,
1007 // but the session were invalidated due to the discovery state unexpectedly
1008 // changing to false and then back to true. In this case, report success.
1009 if (error_name == bluetooth_device::kErrorInProgress && IsDiscovering()) {
1010 VLOG(1) << "Discovery previously initiated. Reporting success.";
1011 num_discovery_sessions_++;
1012 callback.Run();
1013 } else {
1014 error_callback.Run();
1017 // Try to add a new discovery session for each queued request.
1018 ProcessQueuedDiscoveryRequests();
1021 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
1022 // Report success on the original request and decrement the count.
1023 VLOG(1) << __func__;
1024 DCHECK(discovery_request_pending_);
1025 DCHECK(num_discovery_sessions_ == 1);
1026 discovery_request_pending_ = false;
1027 num_discovery_sessions_--;
1028 callback.Run();
1030 // Try to add a new discovery session for each queued request.
1031 ProcessQueuedDiscoveryRequests();
1034 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
1035 const ErrorCallback& error_callback,
1036 const std::string& error_name,
1037 const std::string& error_message) {
1038 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
1039 << error_name << ": " << error_message;
1041 // Failed to stop discovery. This can only happen if the count is at 1.
1042 DCHECK(discovery_request_pending_);
1043 DCHECK(num_discovery_sessions_ == 1);
1044 discovery_request_pending_ = false;
1045 error_callback.Run();
1047 // Try to add a new discovery session for each queued request.
1048 ProcessQueuedDiscoveryRequests();
1051 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
1052 while (!discovery_request_queue_.empty()) {
1053 VLOG(1) << "Process queued discovery request.";
1054 DiscoveryCallbackPair callbacks = discovery_request_queue_.front();
1055 discovery_request_queue_.pop();
1056 AddDiscoverySession(callbacks.first, callbacks.second);
1058 // If the queued request resulted in a pending call, then let it
1059 // asynchonously process the remaining queued requests once the pending
1060 // call returns.
1061 if (discovery_request_pending_)
1062 return;
1066 } // namespace chromeos