Add DriveAppRegistryObserver.
[chromium-blink-merge.git] / device / bluetooth / bluetooth_adapter_chromeos.cc
blob2be5528c89e4fe9298a438c19a271a2136f347db
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/sys_info.h"
13 #include "chromeos/dbus/bluetooth_adapter_client.h"
14 #include "chromeos/dbus/bluetooth_agent_manager_client.h"
15 #include "chromeos/dbus/bluetooth_agent_service_provider.h"
16 #include "chromeos/dbus/bluetooth_device_client.h"
17 #include "chromeos/dbus/bluetooth_input_client.h"
18 #include "chromeos/dbus/dbus_thread_manager.h"
19 #include "device/bluetooth/bluetooth_device.h"
20 #include "device/bluetooth/bluetooth_device_chromeos.h"
21 #include "device/bluetooth/bluetooth_pairing_chromeos.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 using device::BluetoothAdapter;
25 using device::BluetoothDevice;
27 namespace {
29 // The agent path is relatively meaningless since BlueZ only permits one to
30 // exist per D-Bus connection, it just has to be unique within Chromium.
31 const char kAgentPath[] = "/org/chromium/bluetooth_agent";
33 void OnUnregisterAgentError(const std::string& error_name,
34 const std::string& error_message) {
35 // It's okay if the agent didn't exist, it means we never saw an adapter.
36 if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
37 return;
39 LOG(WARNING) << "Failed to unregister pairing agent: "
40 << error_name << ": " << error_message;
43 } // namespace
45 namespace chromeos {
47 BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
48 : num_discovery_sessions_(0),
49 discovery_request_pending_(false),
50 weak_ptr_factory_(this) {
51 DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
52 DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
53 DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
55 // Register the pairing agent.
56 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
57 agent_.reset(BluetoothAgentServiceProvider::Create(
58 system_bus, dbus::ObjectPath(kAgentPath), this));
59 DCHECK(agent_.get());
61 std::vector<dbus::ObjectPath> object_paths =
62 DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
64 if (!object_paths.empty()) {
65 VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
66 SetAdapter(object_paths[0]);
70 BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
71 DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
72 DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
73 DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
75 VLOG(1) << "Unregistering pairing agent";
76 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
77 UnregisterAgent(
78 dbus::ObjectPath(kAgentPath),
79 base::Bind(&base::DoNothing),
80 base::Bind(&OnUnregisterAgentError));
83 void BluetoothAdapterChromeOS::AddObserver(
84 BluetoothAdapter::Observer* observer) {
85 DCHECK(observer);
86 observers_.AddObserver(observer);
89 void BluetoothAdapterChromeOS::RemoveObserver(
90 BluetoothAdapter::Observer* observer) {
91 DCHECK(observer);
92 observers_.RemoveObserver(observer);
95 std::string BluetoothAdapterChromeOS::GetAddress() const {
96 if (!IsPresent())
97 return std::string();
99 BluetoothAdapterClient::Properties* properties =
100 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
101 GetProperties(object_path_);
102 DCHECK(properties);
104 return properties->address.value();
107 std::string BluetoothAdapterChromeOS::GetName() const {
108 if (!IsPresent())
109 return std::string();
111 BluetoothAdapterClient::Properties* properties =
112 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
113 GetProperties(object_path_);
114 DCHECK(properties);
116 return properties->alias.value();
119 void BluetoothAdapterChromeOS::SetName(const std::string& name,
120 const base::Closure& callback,
121 const ErrorCallback& error_callback) {
122 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
123 GetProperties(object_path_)->alias.Set(
124 name,
125 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
126 weak_ptr_factory_.GetWeakPtr(),
127 callback,
128 error_callback));
131 bool BluetoothAdapterChromeOS::IsInitialized() const {
132 return true;
135 bool BluetoothAdapterChromeOS::IsPresent() const {
136 return !object_path_.value().empty();
139 bool BluetoothAdapterChromeOS::IsPowered() const {
140 if (!IsPresent())
141 return false;
143 BluetoothAdapterClient::Properties* properties =
144 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
145 GetProperties(object_path_);
147 return properties->powered.value();
150 void BluetoothAdapterChromeOS::SetPowered(
151 bool powered,
152 const base::Closure& callback,
153 const ErrorCallback& error_callback) {
154 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
155 GetProperties(object_path_)->powered.Set(
156 powered,
157 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
158 weak_ptr_factory_.GetWeakPtr(),
159 callback,
160 error_callback));
163 bool BluetoothAdapterChromeOS::IsDiscoverable() const {
164 if (!IsPresent())
165 return false;
167 BluetoothAdapterClient::Properties* properties =
168 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
169 GetProperties(object_path_);
171 return properties->discoverable.value();
174 void BluetoothAdapterChromeOS::SetDiscoverable(
175 bool discoverable,
176 const base::Closure& callback,
177 const ErrorCallback& error_callback) {
178 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
179 GetProperties(object_path_)->discoverable.Set(
180 discoverable,
181 base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
182 weak_ptr_factory_.GetWeakPtr(),
183 callback,
184 error_callback));
187 bool BluetoothAdapterChromeOS::IsDiscovering() const {
188 if (!IsPresent())
189 return false;
191 BluetoothAdapterClient::Properties* properties =
192 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
193 GetProperties(object_path_);
195 return properties->discovering.value();
198 void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData(
199 const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback,
200 const ErrorCallback& error_callback) {
201 error_callback.Run();
204 void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
205 BluetoothDevice::PairingDelegate* pairing_delegate) {
206 // Before removing a pairing delegate make sure that there aren't any devices
207 // currently using it; if there are, clear the pairing context which will
208 // make any responses no-ops.
209 for (DevicesMap::iterator iter = devices_.begin();
210 iter != devices_.end(); ++iter) {
211 BluetoothDeviceChromeOS* device_chromeos =
212 static_cast<BluetoothDeviceChromeOS*>(iter->second);
214 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
215 if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
216 device_chromeos->EndPairing();
220 void BluetoothAdapterChromeOS::AdapterAdded(
221 const dbus::ObjectPath& object_path) {
222 // Set the adapter to the newly added adapter only if no adapter is present.
223 if (!IsPresent())
224 SetAdapter(object_path);
227 void BluetoothAdapterChromeOS::AdapterRemoved(
228 const dbus::ObjectPath& object_path) {
229 if (object_path == object_path_)
230 RemoveAdapter();
233 void BluetoothAdapterChromeOS::AdapterPropertyChanged(
234 const dbus::ObjectPath& object_path,
235 const std::string& property_name) {
236 if (object_path != object_path_)
237 return;
239 BluetoothAdapterClient::Properties* properties =
240 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
241 GetProperties(object_path_);
243 if (property_name == properties->powered.name())
244 PoweredChanged(properties->powered.value());
245 else if (property_name == properties->discoverable.name())
246 DiscoverableChanged(properties->discoverable.value());
247 else if (property_name == properties->discovering.name())
248 DiscoveringChanged(properties->discovering.value());
251 void BluetoothAdapterChromeOS::DeviceAdded(
252 const dbus::ObjectPath& object_path) {
253 BluetoothDeviceClient::Properties* properties =
254 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
255 GetProperties(object_path);
256 if (properties->adapter.value() != object_path_)
257 return;
259 BluetoothDeviceChromeOS* device_chromeos =
260 new BluetoothDeviceChromeOS(this, object_path);
261 DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
263 devices_[device_chromeos->GetAddress()] = device_chromeos;
265 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
266 DeviceAdded(this, device_chromeos));
269 void BluetoothAdapterChromeOS::DeviceRemoved(
270 const dbus::ObjectPath& object_path) {
271 for (DevicesMap::iterator iter = devices_.begin();
272 iter != devices_.end(); ++iter) {
273 BluetoothDeviceChromeOS* device_chromeos =
274 static_cast<BluetoothDeviceChromeOS*>(iter->second);
275 if (device_chromeos->object_path() == object_path) {
276 devices_.erase(iter);
278 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
279 DeviceRemoved(this, device_chromeos));
280 delete device_chromeos;
281 return;
286 void BluetoothAdapterChromeOS::DevicePropertyChanged(
287 const dbus::ObjectPath& object_path,
288 const std::string& property_name) {
289 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
290 if (!device_chromeos)
291 return;
293 BluetoothDeviceClient::Properties* properties =
294 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
295 GetProperties(object_path);
297 if (property_name == properties->bluetooth_class.name() ||
298 property_name == properties->address.name() ||
299 property_name == properties->alias.name() ||
300 property_name == properties->paired.name() ||
301 property_name == properties->trusted.name() ||
302 property_name == properties->connected.name() ||
303 property_name == properties->uuids.name())
304 NotifyDeviceChanged(device_chromeos);
306 // When a device becomes paired, mark it as trusted so that the user does
307 // not need to approve every incoming connection
308 if (property_name == properties->paired.name() &&
309 properties->paired.value())
310 device_chromeos->SetTrusted();
312 // UMA connection counting
313 if (property_name == properties->connected.name()) {
314 int count = 0;
316 for (DevicesMap::iterator iter = devices_.begin();
317 iter != devices_.end(); ++iter) {
318 if (iter->second->IsPaired() && iter->second->IsConnected())
319 ++count;
322 UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
326 void BluetoothAdapterChromeOS::InputPropertyChanged(
327 const dbus::ObjectPath& object_path,
328 const std::string& property_name) {
329 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
330 if (!device_chromeos)
331 return;
333 BluetoothInputClient::Properties* properties =
334 DBusThreadManager::Get()->GetBluetoothInputClient()->
335 GetProperties(object_path);
337 // Properties structure can be removed, which triggers a change in the
338 // BluetoothDevice::IsConnectable() property, as does a change in the
339 // actual reconnect_mode property.
340 if (!properties ||
341 property_name == properties->reconnect_mode.name())
342 NotifyDeviceChanged(device_chromeos);
345 void BluetoothAdapterChromeOS::Released() {
346 DCHECK(agent_.get());
347 VLOG(1) << "Release";
349 // Called after we unregister the pairing agent, e.g. when changing I/O
350 // capabilities. Nothing much to be done right now.
353 void BluetoothAdapterChromeOS::RequestPinCode(
354 const dbus::ObjectPath& device_path,
355 const PinCodeCallback& callback) {
356 DCHECK(agent_.get());
357 VLOG(1) << device_path.value() << ": RequestPinCode";
359 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
360 if (!pairing) {
361 callback.Run(REJECTED, "");
362 return;
365 pairing->RequestPinCode(callback);
368 void BluetoothAdapterChromeOS::DisplayPinCode(
369 const dbus::ObjectPath& device_path,
370 const std::string& pincode) {
371 DCHECK(agent_.get());
372 VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
374 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
375 if (!pairing)
376 return;
378 pairing->DisplayPinCode(pincode);
381 void BluetoothAdapterChromeOS::RequestPasskey(
382 const dbus::ObjectPath& device_path,
383 const PasskeyCallback& callback) {
384 DCHECK(agent_.get());
385 VLOG(1) << device_path.value() << ": RequestPasskey";
387 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
388 if (!pairing) {
389 callback.Run(REJECTED, 0);
390 return;
393 pairing->RequestPasskey(callback);
396 void BluetoothAdapterChromeOS::DisplayPasskey(
397 const dbus::ObjectPath& device_path,
398 uint32 passkey,
399 uint16 entered) {
400 DCHECK(agent_.get());
401 VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
402 << " (" << entered << " entered)";
404 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
405 if (!pairing)
406 return;
408 if (entered == 0)
409 pairing->DisplayPasskey(passkey);
411 pairing->KeysEntered(entered);
414 void BluetoothAdapterChromeOS::RequestConfirmation(
415 const dbus::ObjectPath& device_path,
416 uint32 passkey,
417 const ConfirmationCallback& callback) {
418 DCHECK(agent_.get());
419 VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
421 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
422 if (!pairing) {
423 callback.Run(REJECTED);
424 return;
427 pairing->RequestConfirmation(passkey, callback);
430 void BluetoothAdapterChromeOS::RequestAuthorization(
431 const dbus::ObjectPath& device_path,
432 const ConfirmationCallback& callback) {
433 DCHECK(agent_.get());
434 VLOG(1) << device_path.value() << ": RequestAuthorization";
436 BluetoothPairingChromeOS* pairing = GetPairing(device_path);
437 if (!pairing) {
438 callback.Run(REJECTED);
439 return;
442 pairing->RequestAuthorization(callback);
445 void BluetoothAdapterChromeOS::AuthorizeService(
446 const dbus::ObjectPath& device_path,
447 const std::string& uuid,
448 const ConfirmationCallback& callback) {
449 DCHECK(agent_.get());
450 VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
452 // TODO(keybuk): implement
453 callback.Run(CANCELLED);
456 void BluetoothAdapterChromeOS::Cancel() {
457 DCHECK(agent_.get());
458 VLOG(1) << "Cancel";
461 void BluetoothAdapterChromeOS::OnRegisterAgent() {
462 VLOG(1) << "Pairing agent registered, requesting to be made default";
464 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
465 RequestDefaultAgent(
466 dbus::ObjectPath(kAgentPath),
467 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
468 weak_ptr_factory_.GetWeakPtr()),
469 base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
470 weak_ptr_factory_.GetWeakPtr()));
474 void BluetoothAdapterChromeOS::OnRegisterAgentError(
475 const std::string& error_name,
476 const std::string& error_message) {
477 // Our agent being already registered isn't an error.
478 if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
479 return;
481 LOG(WARNING) << ": Failed to register pairing agent: "
482 << error_name << ": " << error_message;
485 void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
486 VLOG(1) << "Pairing agent now default";
489 void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
490 const std::string& error_name,
491 const std::string& error_message) {
492 LOG(WARNING) << ": Failed to make pairing agent default: "
493 << error_name << ": " << error_message;
496 BluetoothDeviceChromeOS*
497 BluetoothAdapterChromeOS::GetDeviceWithPath(
498 const dbus::ObjectPath& object_path) {
499 for (DevicesMap::iterator iter = devices_.begin();
500 iter != devices_.end(); ++iter) {
501 BluetoothDeviceChromeOS* device_chromeos =
502 static_cast<BluetoothDeviceChromeOS*>(iter->second);
503 if (device_chromeos->object_path() == object_path)
504 return device_chromeos;
507 return NULL;
510 BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
511 const dbus::ObjectPath& object_path)
513 BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
514 if (!device_chromeos) {
515 LOG(WARNING) << "Pairing Agent request for unknown device: "
516 << object_path.value();
517 return NULL;
520 BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
521 if (pairing)
522 return pairing;
524 // The device doesn't have its own pairing context, so this is an incoming
525 // pairing request that should use our best default delegate (if we have one).
526 BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
527 if (!pairing_delegate)
528 return NULL;
530 return device_chromeos->BeginPairing(pairing_delegate);
533 void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
534 DCHECK(!IsPresent());
535 object_path_ = object_path;
537 VLOG(1) << object_path_.value() << ": using adapter.";
539 VLOG(1) << "Registering pairing agent";
540 DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
541 RegisterAgent(
542 dbus::ObjectPath(kAgentPath),
543 bluetooth_agent_manager::kKeyboardDisplayCapability,
544 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
545 weak_ptr_factory_.GetWeakPtr()),
546 base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
547 weak_ptr_factory_.GetWeakPtr()));
549 SetDefaultAdapterName();
551 BluetoothAdapterClient::Properties* properties =
552 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
553 GetProperties(object_path_);
555 PresentChanged(true);
557 if (properties->powered.value())
558 PoweredChanged(true);
559 if (properties->discoverable.value())
560 DiscoverableChanged(true);
561 if (properties->discovering.value())
562 DiscoveringChanged(true);
564 std::vector<dbus::ObjectPath> device_paths =
565 DBusThreadManager::Get()->GetBluetoothDeviceClient()->
566 GetDevicesForAdapter(object_path_);
568 for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
569 iter != device_paths.end(); ++iter) {
570 BluetoothDeviceChromeOS* device_chromeos =
571 new BluetoothDeviceChromeOS(this, *iter);
573 devices_[device_chromeos->GetAddress()] = device_chromeos;
575 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
576 DeviceAdded(this, device_chromeos));
580 void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
581 std::string board = base::SysInfo::GetLsbReleaseBoard();
582 std::string alias;
583 if (board.substr(0, 6) == "stumpy") {
584 alias = "Chromebox";
585 } else if (board.substr(0, 4) == "link") {
586 alias = "Chromebook Pixel";
587 } else {
588 alias = "Chromebook";
591 SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
594 void BluetoothAdapterChromeOS::RemoveAdapter() {
595 DCHECK(IsPresent());
596 VLOG(1) << object_path_.value() << ": adapter removed.";
598 BluetoothAdapterClient::Properties* properties =
599 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
600 GetProperties(object_path_);
602 object_path_ = dbus::ObjectPath("");
604 if (properties->powered.value())
605 PoweredChanged(false);
606 if (properties->discoverable.value())
607 DiscoverableChanged(false);
608 if (properties->discovering.value())
609 DiscoveringChanged(false);
611 // Copy the devices list here and clear the original so that when we
612 // send DeviceRemoved(), GetDevices() returns no devices.
613 DevicesMap devices = devices_;
614 devices_.clear();
616 for (DevicesMap::iterator iter = devices.begin();
617 iter != devices.end(); ++iter) {
618 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
619 DeviceRemoved(this, iter->second));
620 delete iter->second;
623 PresentChanged(false);
626 void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
627 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
628 AdapterPoweredChanged(this, powered));
631 void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
632 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
633 AdapterDiscoverableChanged(this, discoverable));
636 void BluetoothAdapterChromeOS::DiscoveringChanged(
637 bool discovering) {
638 // If the adapter stopped discovery due to a reason other than a request by
639 // us, reset the count to 0.
640 VLOG(1) << "Discovering changed: " << discovering;
641 if (!discovering && !discovery_request_pending_
642 && num_discovery_sessions_ > 0) {
643 VLOG(1) << "Marking sessions as inactive.";
644 num_discovery_sessions_ = 0;
645 MarkDiscoverySessionsAsInactive();
647 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
648 AdapterDiscoveringChanged(this, discovering));
651 void BluetoothAdapterChromeOS::PresentChanged(bool present) {
652 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
653 AdapterPresentChanged(this, present));
656 void BluetoothAdapterChromeOS::NotifyDeviceChanged(
657 BluetoothDeviceChromeOS* device) {
658 DCHECK(device->adapter_ == this);
660 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
661 DeviceChanged(this, device));
664 void BluetoothAdapterChromeOS::OnSetDiscoverable(
665 const base::Closure& callback,
666 const ErrorCallback& error_callback,
667 bool success) {
668 // Set the discoverable_timeout property to zero so the adapter remains
669 // discoverable forever.
670 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
671 GetProperties(object_path_)->discoverable_timeout.Set(
673 base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
674 weak_ptr_factory_.GetWeakPtr(),
675 callback,
676 error_callback));
679 void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
680 const base::Closure& callback,
681 const ErrorCallback& error_callback,
682 bool success) {
683 if (success)
684 callback.Run();
685 else
686 error_callback.Run();
689 void BluetoothAdapterChromeOS::AddDiscoverySession(
690 const base::Closure& callback,
691 const ErrorCallback& error_callback) {
692 VLOG(1) << __func__;
693 if (discovery_request_pending_) {
694 // The pending request is either to stop a previous session or to start a
695 // new one. Either way, queue this one.
696 DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
697 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
698 << "request to start a new discovery session.";
699 discovery_request_queue_.push(std::make_pair(callback, error_callback));
700 return;
703 // The adapter is already discovering.
704 if (num_discovery_sessions_ > 0) {
705 DCHECK(IsDiscovering());
706 DCHECK(!discovery_request_pending_);
707 num_discovery_sessions_++;
708 callback.Run();
709 return;
712 // There are no active discovery sessions.
713 DCHECK(num_discovery_sessions_ == 0);
715 // This is the first request to start device discovery.
716 discovery_request_pending_ = true;
717 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
718 StartDiscovery(
719 object_path_,
720 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
721 weak_ptr_factory_.GetWeakPtr(),
722 callback),
723 base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
724 weak_ptr_factory_.GetWeakPtr(),
725 callback,
726 error_callback));
729 void BluetoothAdapterChromeOS::RemoveDiscoverySession(
730 const base::Closure& callback,
731 const ErrorCallback& error_callback) {
732 VLOG(1) << __func__;
733 // There are active sessions other than the one currently being removed.
734 if (num_discovery_sessions_ > 1) {
735 DCHECK(IsDiscovering());
736 DCHECK(!discovery_request_pending_);
737 num_discovery_sessions_--;
738 callback.Run();
739 return;
742 // If there is a pending request to BlueZ, then queue this request.
743 if (discovery_request_pending_) {
744 VLOG(1) << "Pending request to start/stop device discovery. Queueing "
745 << "request to stop discovery session.";
746 error_callback.Run();
747 return;
750 // There are no active sessions. Return error.
751 if (num_discovery_sessions_ == 0) {
752 // TODO(armansito): This should never happen once we have the
753 // DiscoverySession API. Replace this case with an assert once it's
754 // the deprecated methods have been removed. (See crbug.com/3445008).
755 VLOG(1) << "No active discovery sessions. Returning error.";
756 error_callback.Run();
757 return;
760 // There is exactly one active discovery session. Request BlueZ to stop
761 // discovery.
762 DCHECK(num_discovery_sessions_ == 1);
763 discovery_request_pending_ = true;
764 DBusThreadManager::Get()->GetBluetoothAdapterClient()->
765 StopDiscovery(
766 object_path_,
767 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
768 weak_ptr_factory_.GetWeakPtr(),
769 callback),
770 base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
771 weak_ptr_factory_.GetWeakPtr(),
772 error_callback));
775 void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) {
776 // Report success on the original request and increment the count.
777 VLOG(1) << __func__;
778 DCHECK(discovery_request_pending_);
779 DCHECK(num_discovery_sessions_ == 0);
780 discovery_request_pending_ = false;
781 num_discovery_sessions_++;
782 callback.Run();
784 // Try to add a new discovery session for each queued request.
785 ProcessQueuedDiscoveryRequests();
788 void BluetoothAdapterChromeOS::OnStartDiscoveryError(
789 const base::Closure& callback,
790 const ErrorCallback& error_callback,
791 const std::string& error_name,
792 const std::string& error_message) {
793 LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
794 << error_name << ": " << error_message;
796 // Failed to start discovery. This can only happen if the count is at 0.
797 DCHECK(num_discovery_sessions_ == 0);
798 DCHECK(discovery_request_pending_);
799 discovery_request_pending_ = false;
801 // Discovery request may fail if discovery was previously initiated by Chrome,
802 // but the session were invalidated due to the discovery state unexpectedly
803 // changing to false and then back to true. In this case, report success.
804 if (error_name == bluetooth_device::kErrorInProgress && IsDiscovering()) {
805 VLOG(1) << "Discovery previously initiated. Reporting success.";
806 num_discovery_sessions_++;
807 callback.Run();
808 } else {
809 error_callback.Run();
812 // Try to add a new discovery session for each queued request.
813 ProcessQueuedDiscoveryRequests();
816 void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
817 // Report success on the original request and decrement the count.
818 VLOG(1) << __func__;
819 DCHECK(discovery_request_pending_);
820 DCHECK(num_discovery_sessions_ == 1);
821 discovery_request_pending_ = false;
822 num_discovery_sessions_--;
823 callback.Run();
825 // Try to add a new discovery session for each queued request.
826 ProcessQueuedDiscoveryRequests();
829 void BluetoothAdapterChromeOS::OnStopDiscoveryError(
830 const ErrorCallback& error_callback,
831 const std::string& error_name,
832 const std::string& error_message) {
833 LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
834 << error_name << ": " << error_message;
836 // Failed to stop discovery. This can only happen if the count is at 1.
837 DCHECK(discovery_request_pending_);
838 DCHECK(num_discovery_sessions_ == 1);
839 discovery_request_pending_ = false;
840 error_callback.Run();
842 // Try to add a new discovery session for each queued request.
843 ProcessQueuedDiscoveryRequests();
846 void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
847 while (!discovery_request_queue_.empty()) {
848 VLOG(1) << "Process queued discovery request.";
849 DiscoveryCallbackPair callbacks = discovery_request_queue_.front();
850 discovery_request_queue_.pop();
851 AddDiscoverySession(callbacks.first, callbacks.second);
853 // If the queued request resulted in a pending call, then let it
854 // asynchonously process the remaining queued requests once the pending
855 // call returns.
856 if (discovery_request_pending_)
857 return;
861 } // namespace chromeos