Revert 269361 "Fix WebURLLoaderImpl::Context leak if a pending r..."
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_chromeos.cc
blob1519209230f3434de0dd4ea1d21ad5a76e1cdbd5
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_socket_chromeos.h"
26 #include "device/bluetooth/bluetooth_socket_thread.h"
27 #include "device/bluetooth/bluetooth_uuid.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
30 using device::BluetoothAdapter;
31 using device::BluetoothDevice;
32 using device::BluetoothSocket;
33 using device::BluetoothUUID;
35 namespace {
37 // The agent path is relatively meaningless since BlueZ only permits one to
38 // exist per D-Bus connection, it just has to be unique within Chromium.
39 const char kAgentPath[] = "/org/chromium/bluetooth_agent";
41 void OnUnregisterAgentError(const std::string& error_name,
42 const std::string& error_message) {
43 // It's okay if the agent didn't exist, it means we never saw an adapter.
44 if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
45 return;
47 LOG(WARNING) << "Failed to unregister pairing agent: "
48 << error_name << ": " << error_message;
51 } // namespace
53 namespace device {
55 // static
56 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
57 const InitCallback& init_callback) {
58 return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
63 namespace chromeos {
65 // static
66 base::WeakPtr<BluetoothAdapter> BluetoothAdapterChromeOS::CreateAdapter() {
67 BluetoothAdapterChromeOS* adapter = new BluetoothAdapterChromeOS();
68 return adapter->weak_ptr_factory_.GetWeakPtr();
71 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
72 : num_discovery_sessions_(0),
73 discovery_request_pending_(false),
74 weak_ptr_factory_(this) {
75 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
76 socket_thread_ = device::BluetoothSocketThread::Get();
78 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
79 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
80 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
82 // Register the pairing agent.
83 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
84 agent_.reset(BluetoothAgentServiceProvider::Create(
85 system_bus, dbus::ObjectPath(kAgentPath), this));
86 DCHECK(agent_.get());
88 std::vector<dbus::ObjectPath> object_paths =
89 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
91 if (!object_paths.empty()) {
92 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
93 SetAdapter(object_paths[0]);
97 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
98 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
99 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
100 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
102 VLOG(1) << "Unregistering pairing agent";
103 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
104 UnregisterAgent(
105 dbus::ObjectPath(kAgentPath),
106 base::Bind(&base::DoNothing),
107 base::Bind(&OnUnregisterAgentError));
110 void BluetoothAdapterChromeOS::AddObserver(
111 BluetoothAdapter::Observer* observer) {
112 DCHECK(observer);
113 observers_.AddObserver(observer);
116 void BluetoothAdapterChromeOS::RemoveObserver(
117 BluetoothAdapter::Observer* observer) {
118 DCHECK(observer);
119 observers_.RemoveObserver(observer);
122 std::string BluetoothAdapterChromeOS::GetAddress() const {
123 if (!IsPresent())
124 return std::string();
126 BluetoothAdapterClient::Properties* properties =
127 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
128 GetProperties(object_path_);
129 DCHECK(properties);
131 return BluetoothDevice::CanonicalizeAddress(properties->address.value());
134 std::string BluetoothAdapterChromeOS::GetName() const {
135 if (!IsPresent())
136 return std::string();
138 BluetoothAdapterClient::Properties* properties =
139 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
140 GetProperties(object_path_);
141 DCHECK(properties);
143 return properties->alias.value();
146 void BluetoothAdapterChromeOS::SetName(const std::string& name,
147 const base::Closure& callback,
148 const ErrorCallback& error_callback) {
149 if (!IsPresent())
150 error_callback.Run();
152 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
153 GetProperties(object_path_)->alias.Set(
154 name,
155 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
156 weak_ptr_factory_.GetWeakPtr(),
157 callback,
158 error_callback));
161 bool BluetoothAdapterChromeOS::IsInitialized() const {
162 return true;
165 bool BluetoothAdapterChromeOS::IsPresent() const {
166 return !object_path_.value().empty();
169 bool BluetoothAdapterChromeOS::IsPowered() const {
170 if (!IsPresent())
171 return false;
173 BluetoothAdapterClient::Properties* properties =
174 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
175 GetProperties(object_path_);
177 return properties->powered.value();
180 void BluetoothAdapterChromeOS::SetPowered(
181 bool powered,
182 const base::Closure& callback,
183 const ErrorCallback& error_callback) {
184 if (!IsPresent())
185 error_callback.Run();
187 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
188 GetProperties(object_path_)->powered.Set(
189 powered,
190 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
191 weak_ptr_factory_.GetWeakPtr(),
192 callback,
193 error_callback));
196 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
197 if (!IsPresent())
198 return false;
200 BluetoothAdapterClient::Properties* properties =
201 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
202 GetProperties(object_path_);
204 return properties->discoverable.value();
207 void BluetoothAdapterChromeOS::SetDiscoverable(
208 bool discoverable,
209 const base::Closure& callback,
210 const ErrorCallback& error_callback) {
211 if (!IsPresent())
212 error_callback.Run();
214 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
215 GetProperties(object_path_)->discoverable.Set(
216 discoverable,
217 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
218 weak_ptr_factory_.GetWeakPtr(),
219 callback,
220 error_callback));
223 bool BluetoothAdapterChromeOS::IsDiscovering() const {
224 if (!IsPresent())
225 return false;
227 BluetoothAdapterClient::Properties* properties =
228 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
229 GetProperties(object_path_);
231 return properties->discovering.value();
234 void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
235 const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
236 const ErrorCallback& error_callback) {
237 error_callback.Run();
240 void BluetoothAdapterChromeOS::CreateRfcommService(
241 const BluetoothUUID& uuid,
242 int channel,
243 bool insecure,
244 const CreateServiceCallback& callback,
245 const CreateServiceErrorCallback& error_callback) {
246 VLOG(1) << object_path_.value() << ": Creating RFCOMM service: "
247 << uuid.canonical_value();
248 scoped_refptr<BluetoothSocketChromeOS> socket =
249 BluetoothSocketChromeOS::CreateBluetoothSocket(
250 ui_task_runner_,
251 socket_thread_,
252 NULL,
253 net::NetLog::Source());
254 socket->Listen(this,
255 BluetoothSocketChromeOS::kRfcomm,
256 uuid,
257 channel,
258 insecure,
259 base::Bind(callback, socket),
260 error_callback);
263 void BluetoothAdapterChromeOS::CreateL2capService(
264 const BluetoothUUID& uuid,
265 int psm,
266 const CreateServiceCallback& callback,
267 const CreateServiceErrorCallback& error_callback) {
268 VLOG(1) << object_path_.value() << ": Creating L2CAP service: "
269 << uuid.canonical_value();
270 scoped_refptr<BluetoothSocketChromeOS> socket =
271 BluetoothSocketChromeOS::CreateBluetoothSocket(
272 ui_task_runner_,
273 socket_thread_,
274 NULL,
275 net::NetLog::Source());
276 socket->Listen(this,
277 BluetoothSocketChromeOS::kL2cap,
278 uuid,
279 psm,
280 false,
281 base::Bind(callback, socket),
282 error_callback);
285 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
286 BluetoothDevice::PairingDelegate* pairing_delegate) {
287 // Before removing a pairing delegate make sure that there aren't any devices
288 // currently using it; if there are, clear the pairing context which will
289 // make any responses no-ops.
290 for (DevicesMap::iterator iter = devices_.begin();
291 iter != devices_.end(); ++iter) {
292 BluetoothDeviceChromeOS* device_chromeos =
293 static_cast<BluetoothDeviceChromeOS*>(iter->second);
295 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
296 if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
297 device_chromeos->EndPairing();
301 void BluetoothAdapterChromeOS::AdapterAdded(
302 const dbus::ObjectPath& object_path) {
303 // Set the adapter to the newly added adapter only if no adapter is present.
304 if (!IsPresent())
305 SetAdapter(object_path);
308 void BluetoothAdapterChromeOS::AdapterRemoved(
309 const dbus::ObjectPath& object_path) {
310 if (object_path == object_path_)
311 RemoveAdapter();
314 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
315 const dbus::ObjectPath& object_path,
316 const std::string& property_name) {
317 if (object_path != object_path_)
318 return;
320 BluetoothAdapterClient::Properties* properties =
321 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
322 GetProperties(object_path_);
324 if (property_name == properties->powered.name())
325 PoweredChanged(properties->powered.value());
326 else if (property_name == properties->discoverable.name())
327 DiscoverableChanged(properties->discoverable.value());
328 else if (property_name == properties->discovering.name())
329 DiscoveringChanged(properties->discovering.value());
332 void BluetoothAdapterChromeOS::DeviceAdded(
333 const dbus::ObjectPath& object_path) {
334 BluetoothDeviceClient::Properties* properties =
335 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
336 GetProperties(object_path);
337 if (properties->adapter.value() != object_path_)
338 return;
340 BluetoothDeviceChromeOS* device_chromeos =
341 new BluetoothDeviceChromeOS(this,
342 object_path,
343 ui_task_runner_,
344 socket_thread_);
345 DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
347 devices_[device_chromeos->GetAddress()] = device_chromeos;
349 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
350 DeviceAdded(this, device_chromeos));
353 void BluetoothAdapterChromeOS::DeviceRemoved(
354 const dbus::ObjectPath& object_path) {
355 for (DevicesMap::iterator iter = devices_.begin();
356 iter != devices_.end(); ++iter) {
357 BluetoothDeviceChromeOS* device_chromeos =
358 static_cast<BluetoothDeviceChromeOS*>(iter->second);
359 if (device_chromeos->object_path() == object_path) {
360 devices_.erase(iter);
362 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
363 DeviceRemoved(this, device_chromeos));
364 delete device_chromeos;
365 return;
370 void BluetoothAdapterChromeOS::DevicePropertyChanged(
371 const dbus::ObjectPath& object_path,
372 const std::string& property_name) {
373 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
374 if (!device_chromeos)
375 return;
377 BluetoothDeviceClient::Properties* properties =
378 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
379 GetProperties(object_path);
381 if (property_name == properties->bluetooth_class.name() ||
382 property_name == properties->address.name() ||
383 property_name == properties->alias.name() ||
384 property_name == properties->paired.name() ||
385 property_name == properties->trusted.name() ||
386 property_name == properties->connected.name() ||
387 property_name == properties->uuids.name() ||
388 property_name == properties->rssi.name() ||
389 property_name == properties->connection_rssi.name() ||
390 property_name == properties->connection_tx_power.name())
391 NotifyDeviceChanged(device_chromeos);
393 // When a device becomes paired, mark it as trusted so that the user does
394 // not need to approve every incoming connection
395 if (property_name == properties->paired.name() &&
396 properties->paired.value() && !properties->trusted.value())
397 device_chromeos->SetTrusted();
399 // UMA connection counting
400 if (property_name == properties->connected.name()) {
401 // PlayStation joystick tries to reconnect after disconnection from USB.
402 // If it is still not trusted, set it, so it becomes available on the
403 // list of known devices.
404 if (properties->connected.value() && device_chromeos->IsTrustable() &&
405 !properties->trusted.value())
406 device_chromeos->SetTrusted();
408 int count = 0;
410 for (DevicesMap::iterator iter = devices_.begin();
411 iter != devices_.end(); ++iter) {
412 if (iter->second->IsPaired() && iter->second->IsConnected())
413 ++count;
416 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
420 void BluetoothAdapterChromeOS::InputPropertyChanged(
421 const dbus::ObjectPath& object_path,
422 const std::string& property_name) {
423 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
424 if (!device_chromeos)
425 return;
427 BluetoothInputClient::Properties* properties =
428 DBusThreadManager::Get()->GetBluetoothInputClient()->
429 GetProperties(object_path);
431 // Properties structure can be removed, which triggers a change in the
432 // BluetoothDevice::IsConnectable() property, as does a change in the
433 // actual reconnect_mode property.
434 if (!properties ||
435 property_name == properties->reconnect_mode.name())
436 NotifyDeviceChanged(device_chromeos);
439 void BluetoothAdapterChromeOS::Released() {
440 DCHECK(agent_.get());
441 VLOG(1) << "Release";
443 // Called after we unregister the pairing agent, e.g. when changing I/O
444 // capabilities. Nothing much to be done right now.
447 void BluetoothAdapterChromeOS::RequestPinCode(
448 const dbus::ObjectPath& device_path,
449 const PinCodeCallback& callback) {
450 DCHECK(agent_.get());
451 VLOG(1) << device_path.value() << ": RequestPinCode";
453 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
454 if (!pairing) {
455 callback.Run(REJECTED, "");
456 return;
459 pairing->RequestPinCode(callback);
462 void BluetoothAdapterChromeOS::DisplayPinCode(
463 const dbus::ObjectPath& device_path,
464 const std::string& pincode) {
465 DCHECK(agent_.get());
466 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
468 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
469 if (!pairing)
470 return;
472 pairing->DisplayPinCode(pincode);
475 void BluetoothAdapterChromeOS::RequestPasskey(
476 const dbus::ObjectPath& device_path,
477 const PasskeyCallback& callback) {
478 DCHECK(agent_.get());
479 VLOG(1) << device_path.value() << ": RequestPasskey";
481 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
482 if (!pairing) {
483 callback.Run(REJECTED, 0);
484 return;
487 pairing->RequestPasskey(callback);
490 void BluetoothAdapterChromeOS::DisplayPasskey(
491 const dbus::ObjectPath& device_path,
492 uint32 passkey,
493 uint16 entered) {
494 DCHECK(agent_.get());
495 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
496 << " (" << entered << " entered)";
498 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
499 if (!pairing)
500 return;
502 if (entered == 0)
503 pairing->DisplayPasskey(passkey);
505 pairing->KeysEntered(entered);
508 void BluetoothAdapterChromeOS::RequestConfirmation(
509 const dbus::ObjectPath& device_path,
510 uint32 passkey,
511 const ConfirmationCallback& callback) {
512 DCHECK(agent_.get());
513 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
515 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
516 if (!pairing) {
517 callback.Run(REJECTED);
518 return;
521 pairing->RequestConfirmation(passkey, callback);
524 void BluetoothAdapterChromeOS::RequestAuthorization(
525 const dbus::ObjectPath& device_path,
526 const ConfirmationCallback& callback) {
527 DCHECK(agent_.get());
528 VLOG(1) << device_path.value() << ": RequestAuthorization";
530 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
531 if (!pairing) {
532 callback.Run(REJECTED);
533 return;
536 pairing->RequestAuthorization(callback);
539 void BluetoothAdapterChromeOS::AuthorizeService(
540 const dbus::ObjectPath& device_path,
541 const std::string& uuid,
542 const ConfirmationCallback& callback) {
543 DCHECK(agent_.get());
544 VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
546 // TODO(keybuk): implement
547 callback.Run(CANCELLED);
550 void BluetoothAdapterChromeOS::Cancel() {
551 DCHECK(agent_.get());
552 VLOG(1) << "Cancel";
555 void BluetoothAdapterChromeOS::OnRegisterAgent() {
556 VLOG(1) << "Pairing agent registered, requesting to be made default";
558 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
559 RequestDefaultAgent(
560 dbus::ObjectPath(kAgentPath),
561 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
562 weak_ptr_factory_.GetWeakPtr()),
563 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
564 weak_ptr_factory_.GetWeakPtr()));
568 void BluetoothAdapterChromeOS::OnRegisterAgentError(
569 const std::string& error_name,
570 const std::string& error_message) {
571 // Our agent being already registered isn't an error.
572 if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
573 return;
575 LOG(WARNING) << ": Failed to register pairing agent: "
576 << error_name << ": " << error_message;
579 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
580 VLOG(1) << "Pairing agent now default";
583 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
584 const std::string& error_name,
585 const std::string& error_message) {
586 LOG(WARNING) << ": Failed to make pairing agent default: "
587 << error_name << ": " << error_message;
590 BluetoothDeviceChromeOS*
591 BluetoothAdapterChromeOS::GetDeviceWithPath(
592 const dbus::ObjectPath& object_path) {
593 for (DevicesMap::iterator iter = devices_.begin();
594 iter != devices_.end(); ++iter) {
595 BluetoothDeviceChromeOS* device_chromeos =
596 static_cast<BluetoothDeviceChromeOS*>(iter->second);
597 if (device_chromeos->object_path() == object_path)
598 return device_chromeos;
601 return NULL;
604 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
605 const dbus::ObjectPath& object_path)
607 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
608 if (!device_chromeos) {
609 LOG(WARNING) << "Pairing Agent request for unknown device: "
610 << object_path.value();
611 return NULL;
614 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
615 if (pairing)
616 return pairing;
618 // The device doesn't have its own pairing context, so this is an incoming
619 // pairing request that should use our best default delegate (if we have one).
620 BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
621 if (!pairing_delegate)
622 return NULL;
624 return device_chromeos->BeginPairing(pairing_delegate);
627 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
628 DCHECK(!IsPresent());
629 object_path_ = object_path;
631 VLOG(1) << object_path_.value() << ": using adapter.";
633 VLOG(1) << "Registering pairing agent";
634 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
635 RegisterAgent(
636 dbus::ObjectPath(kAgentPath),
637 bluetooth_agent_manager::kKeyboardDisplayCapability,
638 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
639 weak_ptr_factory_.GetWeakPtr()),
640 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
641 weak_ptr_factory_.GetWeakPtr()));
643 SetDefaultAdapterName();
645 BluetoothAdapterClient::Properties* properties =
646 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
647 GetProperties(object_path_);
649 PresentChanged(true);
651 if (properties->powered.value())
652 PoweredChanged(true);
653 if (properties->discoverable.value())
654 DiscoverableChanged(true);
655 if (properties->discovering.value())
656 DiscoveringChanged(true);
658 std::vector<dbus::ObjectPath> device_paths =
659 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
660 GetDevicesForAdapter(object_path_);
662 for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
663 iter != device_paths.end(); ++iter) {
664 DeviceAdded(*iter);
668 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
669 std::string board = base::SysInfo::GetLsbReleaseBoard();
670 std::string alias;
671 if (board.substr(0, 6) == "stumpy") {
672 alias = "Chromebox";
673 } else if (board.substr(0, 4) == "link") {
674 alias = "Chromebook Pixel";
675 } else {
676 alias = "Chromebook";
679 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
682 void BluetoothAdapterChromeOS::RemoveAdapter() {
683 DCHECK(IsPresent());
684 VLOG(1) << object_path_.value() << ": adapter removed.";
686 BluetoothAdapterClient::Properties* properties =
687 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
688 GetProperties(object_path_);
690 object_path_ = dbus::ObjectPath("");
692 if (properties->powered.value())
693 PoweredChanged(false);
694 if (properties->discoverable.value())
695 DiscoverableChanged(false);
696 if (properties->discovering.value())
697 DiscoveringChanged(false);
699 // Copy the devices list here and clear the original so that when we
700 // send DeviceRemoved(), GetDevices() returns no devices.
701 DevicesMap devices = devices_;
702 devices_.clear();
704 for (DevicesMap::iterator iter = devices.begin();
705 iter != devices.end(); ++iter) {
706 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
707 DeviceRemoved(this, iter->second));
708 delete iter->second;
711 PresentChanged(false);
714 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
715 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
716 AdapterPoweredChanged(this, powered));
719 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
720 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
721 AdapterDiscoverableChanged(this, discoverable));
724 void BluetoothAdapterChromeOS::DiscoveringChanged(
725 bool discovering) {
726 // If the adapter stopped discovery due to a reason other than a request by
727 // us, reset the count to 0.
728 VLOG(1) << "Discovering changed: " << discovering;
729 if (!discovering && !discovery_request_pending_
730 && num_discovery_sessions_ > 0) {
731 VLOG(1) << "Marking sessions as inactive.";
732 num_discovery_sessions_ = 0;
733 MarkDiscoverySessionsAsInactive();
735 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
736 AdapterDiscoveringChanged(this, discovering));
739 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
740 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
741 AdapterPresentChanged(this, present));
744 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
745 BluetoothDeviceChromeOS* device) {
746 DCHECK(device->adapter_ == this);
748 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
749 DeviceChanged(this, device));
752 void BluetoothAdapterChromeOS::OnSetDiscoverable(
753 const base::Closure& callback,
754 const ErrorCallback& error_callback,
755 bool success) {
756 // Set the discoverable_timeout property to zero so the adapter remains
757 // discoverable forever.
758 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
759 GetProperties(object_path_)->discoverable_timeout.Set(
761 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
762 weak_ptr_factory_.GetWeakPtr(),
763 callback,
764 error_callback));
767 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
768 const base::Closure& callback,
769 const ErrorCallback& error_callback,
770 bool success) {
771 if (success)
772 callback.Run();
773 else
774 error_callback.Run();
777 void BluetoothAdapterChromeOS::AddDiscoverySession(
778 const base::Closure& callback,
779 const ErrorCallback& error_callback) {
780 VLOG(1) << __func__;
781 if (discovery_request_pending_) {
782 // The pending request is either to stop a previous session or to start a
783 // new one. Either way, queue this one.
784 DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
785 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
786 << "request to start a new discovery session.";
787 discovery_request_queue_.push(std::make_pair(callback, error_callback));
788 return;
791 // The adapter is already discovering.
792 if (num_discovery_sessions_ > 0) {
793 DCHECK(IsDiscovering());
794 DCHECK(!discovery_request_pending_);
795 num_discovery_sessions_++;
796 callback.Run();
797 return;
800 // There are no active discovery sessions.
801 DCHECK(num_discovery_sessions_ == 0);
803 // This is the first request to start device discovery.
804 discovery_request_pending_ = true;
805 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
806 StartDiscovery(
807 object_path_,
808 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
809 weak_ptr_factory_.GetWeakPtr(),
810 callback),
811 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
812 weak_ptr_factory_.GetWeakPtr(),
813 callback,
814 error_callback));
817 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
818 const base::Closure& callback,
819 const ErrorCallback& error_callback) {
820 VLOG(1) << __func__;
821 // There are active sessions other than the one currently being removed.
822 if (num_discovery_sessions_ > 1) {
823 DCHECK(IsDiscovering());
824 DCHECK(!discovery_request_pending_);
825 num_discovery_sessions_--;
826 callback.Run();
827 return;
830 // If there is a pending request to BlueZ, then queue this request.
831 if (discovery_request_pending_) {
832 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
833 << "request to stop discovery session.";
834 error_callback.Run();
835 return;
838 // There are no active sessions. Return error.
839 if (num_discovery_sessions_ == 0) {
840 // TODO(armansito): This should never happen once we have the
841 // DiscoverySession API. Replace this case with an assert once it's
842 // the deprecated methods have been removed. (See crbug.com/3445008).
843 VLOG(1) << "No active discovery sessions. Returning error.";
844 error_callback.Run();
845 return;
848 // There is exactly one active discovery session. Request BlueZ to stop
849 // discovery.
850 DCHECK(num_discovery_sessions_ == 1);
851 discovery_request_pending_ = true;
852 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
853 StopDiscovery(
854 object_path_,
855 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
856 weak_ptr_factory_.GetWeakPtr(),
857 callback),
858 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
859 weak_ptr_factory_.GetWeakPtr(),
860 error_callback));
863 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) {
864 // Report success on the original request and increment the count.
865 VLOG(1) << __func__;
866 DCHECK(discovery_request_pending_);
867 DCHECK(num_discovery_sessions_ == 0);
868 discovery_request_pending_ = false;
869 num_discovery_sessions_++;
870 callback.Run();
872 // Try to add a new discovery session for each queued request.
873 ProcessQueuedDiscoveryRequests();
876 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
877 const base::Closure& callback,
878 const ErrorCallback& error_callback,
879 const std::string& error_name,
880 const std::string& error_message) {
881 LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
882 << error_name << ": " << error_message;
884 // Failed to start discovery. This can only happen if the count is at 0.
885 DCHECK(num_discovery_sessions_ == 0);
886 DCHECK(discovery_request_pending_);
887 discovery_request_pending_ = false;
889 // Discovery request may fail if discovery was previously initiated by Chrome,
890 // but the session were invalidated due to the discovery state unexpectedly
891 // changing to false and then back to true. In this case, report success.
892 if (error_name == bluetooth_device::kErrorInProgress && IsDiscovering()) {
893 VLOG(1) << "Discovery previously initiated. Reporting success.";
894 num_discovery_sessions_++;
895 callback.Run();
896 } else {
897 error_callback.Run();
900 // Try to add a new discovery session for each queued request.
901 ProcessQueuedDiscoveryRequests();
904 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
905 // Report success on the original request and decrement the count.
906 VLOG(1) << __func__;
907 DCHECK(discovery_request_pending_);
908 DCHECK(num_discovery_sessions_ == 1);
909 discovery_request_pending_ = false;
910 num_discovery_sessions_--;
911 callback.Run();
913 // Try to add a new discovery session for each queued request.
914 ProcessQueuedDiscoveryRequests();
917 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
918 const ErrorCallback& error_callback,
919 const std::string& error_name,
920 const std::string& error_message) {
921 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
922 << error_name << ": " << error_message;
924 // Failed to stop discovery. This can only happen if the count is at 1.
925 DCHECK(discovery_request_pending_);
926 DCHECK(num_discovery_sessions_ == 1);
927 discovery_request_pending_ = false;
928 error_callback.Run();
930 // Try to add a new discovery session for each queued request.
931 ProcessQueuedDiscoveryRequests();
934 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
935 while (!discovery_request_queue_.empty()) {
936 VLOG(1) << "Process queued discovery request.";
937 DiscoveryCallbackPair callbacks = discovery_request_queue_.front();
938 discovery_request_queue_.pop();
939 AddDiscoverySession(callbacks.first, callbacks.second);
941 // If the queued request resulted in a pending call, then let it
942 // asynchonously process the remaining queued requests once the pending
943 // call returns.
944 if (discovery_request_pending_)
945 return;
949 } // namespace chromeos