diff options
author | armansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-26 18:32:09 +0000 |
---|---|---|
committer | armansito@chromium.org <armansito@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-26 18:32:09 +0000 |
commit | 52f6b5f275a090f05813a17a524c019ff30b98c4 (patch) | |
tree | 3d049d4df82beddb8c0de162c9f0aae9ed525343 /device | |
parent | 3f855262c984c24d51e22c2ab8bec01d823a2e63 (diff) | |
download | chromium_src-52f6b5f275a090f05813a17a524c019ff30b98c4.zip chromium_src-52f6b5f275a090f05813a17a524c019ff30b98c4.tar.gz chromium_src-52f6b5f275a090f05813a17a524c019ff30b98c4.tar.bz2 |
device::BluetoothAdapterChromeOS: Implement reference counted sessions.
Paving the way towards the new DiscoverySession API that's in the works,
this patch modifies BluetoothAdapterChromeOS to keep a count of device
discovery sessions that have been added and removed by clients, to prevent
concurrent sessions from cancelling eachother out. This patch also introduces
two new internal API methods (AddDiscoverySession and RemoveDiscoverySession)
which will be used by the new DiscoverySession class once we add it.
BUG=345006,239702
TEST=1. device_unittests.
2. - Start two concurrent discovery sessions, one via chrome://settings and
the other via the Aura Shell.
- Close the aura shell menu. Device discovery should continue, until the
"Add Bluetooth Device" overlay in chrome://settings is dismissed by
clicking "Cancel".
Review URL: https://codereview.chromium.org/169663003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253517 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device')
-rw-r--r-- | device/bluetooth/bluetooth_adapter.cc | 10 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter.h | 39 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_chromeos.cc | 183 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_chromeos.h | 56 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_mac.h | 15 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_mac.mm | 17 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_win.cc | 52 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_win.h | 15 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_chromeos_unittest.cc | 456 | ||||
-rw-r--r-- | device/bluetooth/test/mock_bluetooth_adapter.h | 6 |
10 files changed, 760 insertions, 89 deletions
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc index 8cce6ec..bb372f1 100644 --- a/device/bluetooth/bluetooth_adapter.cc +++ b/device/bluetooth/bluetooth_adapter.cc @@ -16,6 +16,16 @@ BluetoothAdapter::~BluetoothAdapter() { STLDeleteValues(&devices_); } +void BluetoothAdapter::StartDiscovering(const base::Closure& callback, + const ErrorCallback& error_callback) { + AddDiscoverySession(callback, error_callback); +} + +void BluetoothAdapter::StopDiscovering(const base::Closure& callback, + const ErrorCallback& error_callback) { + RemoveDiscoverySession(callback, error_callback); +} + BluetoothAdapter::DeviceList BluetoothAdapter::GetDevices() { ConstDeviceList const_devices = const_cast<const BluetoothAdapter *>(this)->GetDevices(); diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h index 24e9dcd..42fe8db 100644 --- a/device/bluetooth/bluetooth_adapter.h +++ b/device/bluetooth/bluetooth_adapter.h @@ -146,7 +146,7 @@ class BluetoothAdapter : public base::RefCounted<BluetoothAdapter> { // callers should retrieve the current set of discovered devices by calling // GetDevices() and checking for those with IsPaired() as false. virtual void StartDiscovering(const base::Closure& callback, - const ErrorCallback& error_callback) = 0; + const ErrorCallback& error_callback); // Requests that an earlier call to StartDiscovering() be cancelled; the // adapter may not actually cease discovering devices if other callers @@ -154,7 +154,7 @@ class BluetoothAdapter : public base::RefCounted<BluetoothAdapter> { // success |callback| will be called, on failure |error_callback| will be // called instead. virtual void StopDiscovering(const base::Closure& callback, - const ErrorCallback& error_callback) = 0; + const ErrorCallback& error_callback); // Requests the list of devices from the adapter, all are returned // including those currently connected and those paired. Use the @@ -180,6 +180,41 @@ class BluetoothAdapter : public base::RefCounted<BluetoothAdapter> { BluetoothAdapter(); virtual ~BluetoothAdapter(); + // Internal methods for initiating and terminating device discovery sessions. + // An implementation of BluetoothAdapter keeps an internal reference count to + // make sure that the underlying controller is constantly searching for nearby + // devices and retrieving information from them as long as there are clients + // who have requested discovery. These methods behave in the following way: + // + // On a call to AddDiscoverySession: + // - If there is a pending request to the subsystem, queue this request to + // execute once the pending requests are done. + // - If the count is 0, issue a request to the subsystem to start + // device discovery. On success, increment the count to 1. + // - If the count is greater than 0, increment the count and return + // success. + // As long as the count is non-zero, the underlying controller will be + // discovering for devices. This means that Chrome will restart device + // scan and inquiry sessions if they ever end, unless these sessions + // terminate due to an unexpected reason. + // + // On a call to RemoveDiscoverySession: + // - If there is a pending request to the subsystem, queue this request to + // execute once the pending requests are done. + // - If the count is 0, return failure, as there is no active discovery + // session. + // - If the count is 1, issue a request to the subsystem to stop device + // discovery and decrement the count to 0 on success. + // - If the count is greater than 1, decrement the count and return + // success. + // + // These methods invoke |callback| for success and |error_callback| for + // failures. + virtual void AddDiscoverySession(const base::Closure& callback, + const ErrorCallback& error_callback) = 0; + virtual void RemoveDiscoverySession(const base::Closure& callback, + const ErrorCallback& error_callback) = 0; + // Devices paired with, connected to, discovered by, or visible to the // adapter. The key is the Bluetooth address of the device and the value // is the BluetoothDevice object whose lifetime is managed by the diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc index 3b694e4..29bc05e 100644 --- a/device/bluetooth/bluetooth_adapter_chromeos.cc +++ b/device/bluetooth/bluetooth_adapter_chromeos.cc @@ -53,7 +53,9 @@ void OnUnregisterAgentError(const std::string& error_name, namespace chromeos { BluetoothAdapterChromeOS::BluetoothAdapterChromeOS() - : weak_ptr_factory_(this) { + : num_discovery_sessions_(0), + discovery_request_pending_(false), + weak_ptr_factory_(this) { DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this); DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this); DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this); @@ -211,38 +213,6 @@ bool BluetoothAdapterChromeOS::IsDiscovering() const { return properties->discovering.value(); } -void BluetoothAdapterChromeOS::StartDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) { - // BlueZ counts discovery sessions, and permits multiple sessions for a - // single connection, so issue a StartDiscovery() call for every use - // within Chromium for the right behavior. - DBusThreadManager::Get()->GetBluetoothAdapterClient()-> - StartDiscovery( - object_path_, - base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery, - weak_ptr_factory_.GetWeakPtr(), - callback), - base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError, - weak_ptr_factory_.GetWeakPtr(), - error_callback)); -} - -void BluetoothAdapterChromeOS::StopDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) { - // Inform BlueZ to stop one of our open discovery sessions. - DBusThreadManager::Get()->GetBluetoothAdapterClient()-> - StopDiscovery( - object_path_, - base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery, - weak_ptr_factory_.GetWeakPtr(), - callback), - base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError, - weak_ptr_factory_.GetWeakPtr(), - error_callback)); -} - void BluetoothAdapterChromeOS::ReadLocalOutOfBandPairingData( const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback, const ErrorCallback& error_callback) { @@ -759,6 +729,17 @@ void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) { void BluetoothAdapterChromeOS::DiscoveringChanged( bool discovering) { + // If the adapter stopped discovery due to a reason other than a request by + // us, reset the count to 0. + if (!discovering && !discovery_request_pending_ + && num_discovery_sessions_ > 0) { + num_discovery_sessions_ = 0; + // TODO(armansito): When we implement the DiscoverySession API, all + // active DiscoverySession instances need to be notified to update + // themselves. We want to do this before we notify the other observers + // so that any DiscoverySession objects that those observers might own + // have been marked as inactive. + } FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, AdapterDiscoveringChanged(this, discovering)); } @@ -801,8 +782,106 @@ void BluetoothAdapterChromeOS::OnPropertyChangeCompleted( error_callback.Run(); } +void BluetoothAdapterChromeOS::AddDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) { + VLOG(1) << __func__; + if (discovery_request_pending_) { + // The pending request is either to stop a previous session or to start a + // new one. Either way, queue this one. + DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0); + VLOG(1) << "Pending request to initiate device discovery. Queueing request " + << "to start a new discovery session."; + discovery_request_queue_.push(std::make_pair(callback, error_callback)); + return; + } + + // The adapter is already discovering. + if (num_discovery_sessions_ > 0) { + DCHECK(IsDiscovering()); + DCHECK(!discovery_request_pending_); + num_discovery_sessions_++; + callback.Run(); + return; + } + + // There are no active discovery sessions. + DCHECK(num_discovery_sessions_ == 0); + + // This is the first request to start device discovery. + discovery_request_pending_ = true; + DBusThreadManager::Get()->GetBluetoothAdapterClient()-> + StartDiscovery( + object_path_, + base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery, + weak_ptr_factory_.GetWeakPtr(), + callback), + base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError, + weak_ptr_factory_.GetWeakPtr(), + error_callback)); +} + +void BluetoothAdapterChromeOS::RemoveDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) { + VLOG(1) << __func__; + // There are active sessions other than the one currently being removed. + if (num_discovery_sessions_ > 1) { + DCHECK(IsDiscovering()); + DCHECK(!discovery_request_pending_); + num_discovery_sessions_--; + callback.Run(); + return; + } + + // If there is a pending request to BlueZ, then queue this request. + if (discovery_request_pending_) { + VLOG(1) << "Pending request to initiate device discovery. Queueing request " + << "to stop discovery session."; + // TODO(armansito): We should never hit this case once we have the + // DiscoverySession API, as there would be no active DiscoverySession + // objects to allow calling this method while a call is pending to either + // return the first active or deactivate the last active DiscoverySession + // object in the first place. For now, report error. + error_callback.Run(); + return; + } + + // There are no active sessions. Return error. + if (num_discovery_sessions_ == 0) { + // TODO(armansito): This should never happen once we have the + // DiscoverySession API. Replace this case with an assert once it's + // implemented. (See crbug.com/3445008). + VLOG(1) << "No active discovery sessions. Returning error."; + error_callback.Run(); + return; + } + + // There is exactly one active discovery session. Request BlueZ to stop + // discovery. + DCHECK(num_discovery_sessions_ == 1); + discovery_request_pending_ = true; + DBusThreadManager::Get()->GetBluetoothAdapterClient()-> + StopDiscovery( + object_path_, + base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery, + weak_ptr_factory_.GetWeakPtr(), + callback), + base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError, + weak_ptr_factory_.GetWeakPtr(), + error_callback)); +} + void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) { + // Report success on the original request and increment the count. + DCHECK(discovery_request_pending_); + DCHECK(num_discovery_sessions_ == 0); + discovery_request_pending_ = false; + num_discovery_sessions_++; callback.Run(); + + // Try to add a new discovery session for each queued request. + ProcessQueuedDiscoveryRequests(); } void BluetoothAdapterChromeOS::OnStartDiscoveryError( @@ -811,11 +890,27 @@ void BluetoothAdapterChromeOS::OnStartDiscoveryError( const std::string& error_message) { LOG(WARNING) << object_path_.value() << ": Failed to start discovery: " << error_name << ": " << error_message; + + // Failed to start discovery. This can only happen if the count is at 0. + DCHECK(num_discovery_sessions_ == 0); + DCHECK(discovery_request_pending_); + discovery_request_pending_ = false; error_callback.Run(); + + // Try to add a new discovery session for each queued request. + ProcessQueuedDiscoveryRequests(); } void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) { + // Report success on the original request and decrement the count. + DCHECK(discovery_request_pending_); + DCHECK(num_discovery_sessions_ == 1); + discovery_request_pending_ = false; + num_discovery_sessions_--; callback.Run(); + + // Try to add a new discovery session for each queued request. + ProcessQueuedDiscoveryRequests(); } void BluetoothAdapterChromeOS::OnStopDiscoveryError( @@ -824,7 +919,29 @@ void BluetoothAdapterChromeOS::OnStopDiscoveryError( const std::string& error_message) { LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: " << error_name << ": " << error_message; + + // Failed to stop discovery. This can only happen if the count is at 1. + DCHECK(discovery_request_pending_); + DCHECK(num_discovery_sessions_ == 1); + discovery_request_pending_ = false; error_callback.Run(); + + // Try to add a new discovery session for each queued request. + ProcessQueuedDiscoveryRequests(); +} + +void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() { + while (!discovery_request_queue_.empty()) { + DiscoveryCallbackPair callbacks = discovery_request_queue_.front(); + discovery_request_queue_.pop(); + AddDiscoverySession(callbacks.first, callbacks.second); + + // If the queued request resulted in a pending call, then let it + // asynchonously process the remaining queued requests once the pending + // call returns. + if (discovery_request_pending_) + return; + } } } // namespace chromeos diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h index 926ba86..f48a8a8 100644 --- a/device/bluetooth/bluetooth_adapter_chromeos.h +++ b/device/bluetooth/bluetooth_adapter_chromeos.h @@ -5,6 +5,7 @@ #ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_ #define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_ +#include <queue> #include <string> #include "base/memory/weak_ptr.h" @@ -59,12 +60,6 @@ class BluetoothAdapterChromeOS const base::Closure& callback, const ErrorCallback& error_callback) OVERRIDE; virtual bool IsDiscovering() const OVERRIDE; - virtual void StartDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) OVERRIDE; - virtual void StopDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) OVERRIDE; virtual void ReadLocalOutOfBandPairingData( const device::BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback, @@ -77,6 +72,12 @@ class BluetoothAdapterChromeOS friend class BluetoothProfileChromeOS; friend class BluetoothProfileChromeOSTest; + // typedef for callback parameters that are passed to AddDiscoverySession + // and RemoveDiscoverySession. This is used to queue incoming requests while + // a call to BlueZ is pending. + typedef std::pair<base::Closure, ErrorCallback> DiscoveryCallbackPair; + typedef std::queue<DiscoveryCallbackPair> DiscoveryCallbackQueue; + BluetoothAdapterChromeOS(); virtual ~BluetoothAdapterChromeOS(); @@ -244,6 +245,14 @@ class BluetoothAdapterChromeOS const ErrorCallback& error_callback, bool success); + // BluetoothAdapter override. + virtual void AddDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) OVERRIDE; + virtual void RemoveDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) OVERRIDE; + // Called by dbus:: on completion of the D-Bus method call to start discovery. void OnStartDiscovery(const base::Closure& callback); void OnStartDiscoveryError(const ErrorCallback& error_callback, @@ -256,6 +265,41 @@ class BluetoothAdapterChromeOS const std::string& error_name, const std::string& error_message); + // Processes the queued discovery requests. For each DiscoveryCallbackPair in + // the queue, this method will try to add a new discovery session. This method + // is called whenever a pending D-Bus call to start or stop discovery has + // ended (with either success or failure). + void ProcessQueuedDiscoveryRequests(); + + // Number of discovery sessions that have been added. + int num_discovery_sessions_; + + // True, if there is a pending request to start or stop discovery. + bool discovery_request_pending_; + + // List of queued requests to add new discovery sessions. While there is a + // pending request to BlueZ to start or stop discovery, many requests from + // within Chrome to start or stop discovery sessions may occur. We only + // queue requests to add new sessions to be processed later. All requests to + // remove a session while a call is pending immediately return failure. Note + // that since BlueZ keeps its own reference count of applications that have + // requested discovery, dropping our count to 0 won't necessarily result in + // the controller actually stopping discovery if, for example, an application + // other than Chrome, such as bt_console, was also used to start discovery. + // + // TODO(armansito): With the new API, it will not be possible to have requests + // to remove a discovery session while a call is pending. If the pending + // request is to start discovery, |num_discovery_sessions_| is 0. Since no + // active instance of DiscoverySession exists, clients can only make calls to + // request new sessions. Likewise, if the pending request is to stop + // discovery, |num_discovery_sessions_| is 1 and we're currently processing + // the request to stop the last active DiscoverySession. We should make sure + // that this invariant holds via asserts once we implement DiscoverySession + // and have fully removed the deprecated methods. For now, just return an + // error in the removal case to support the deprecated methods. (See + // crbug.com/3445008). + DiscoveryCallbackQueue discovery_request_queue_; + // Object path of the adapter we track. dbus::ObjectPath object_path_; diff --git a/device/bluetooth/bluetooth_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h index 6639db0..8098206 100644 --- a/device/bluetooth/bluetooth_adapter_mac.h +++ b/device/bluetooth/bluetooth_adapter_mac.h @@ -63,13 +63,6 @@ class BluetoothAdapterMac : public BluetoothAdapter { const base::Closure& callback, const ErrorCallback& error_callback) OVERRIDE; virtual bool IsDiscovering() const OVERRIDE; - - virtual void StartDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) OVERRIDE; - virtual void StopDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) OVERRIDE; virtual void ReadLocalOutOfBandPairingData( const BluetoothOutOfBandPairingDataCallback& callback, const ErrorCallback& error_callback) OVERRIDE; @@ -96,6 +89,14 @@ class BluetoothAdapterMac : public BluetoothAdapter { BluetoothAdapterMac(); virtual ~BluetoothAdapterMac(); + // BluetoothAdapter override. + virtual void AddDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) OVERRIDE; + virtual void RemoveDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) OVERRIDE; + void Init(); void InitForTest(scoped_refptr<base::SequencedTaskRunner> ui_task_runner); void PollAdapter(); diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm index 502ed81..e330965 100644 --- a/device/bluetooth/bluetooth_adapter_mac.mm +++ b/device/bluetooth/bluetooth_adapter_mac.mm @@ -168,7 +168,12 @@ bool BluetoothAdapterMac::IsDiscovering() const { discovery_status_ == DISCOVERY_STOPPING; } -void BluetoothAdapterMac::StartDiscovering( +void BluetoothAdapterMac::ReadLocalOutOfBandPairingData( + const BluetoothOutOfBandPairingDataCallback& callback, + const ErrorCallback& error_callback) { +} + +void BluetoothAdapterMac::AddDiscoverySession( const base::Closure& callback, const ErrorCallback& error_callback) { if (discovery_status_ == DISCOVERING) { @@ -181,8 +186,9 @@ void BluetoothAdapterMac::StartDiscovering( MaybeStartDeviceInquiry(); } -void BluetoothAdapterMac::StopDiscovering(const base::Closure& callback, - const ErrorCallback& error_callback) { +void BluetoothAdapterMac::RemoveDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) { if (discovery_status_ == NOT_DISCOVERING) { error_callback.Run(); return; @@ -192,11 +198,6 @@ void BluetoothAdapterMac::StopDiscovering(const base::Closure& callback, MaybeStopDeviceInquiry(); } -void BluetoothAdapterMac::ReadLocalOutOfBandPairingData( - const BluetoothOutOfBandPairingDataCallback& callback, - const ErrorCallback& error_callback) { -} - void BluetoothAdapterMac::Init() { ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); PollAdapter(); diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc index 521afae..e56ceae 100644 --- a/device/bluetooth/bluetooth_adapter_win.cc +++ b/device/bluetooth/bluetooth_adapter_win.cc @@ -97,32 +97,6 @@ bool BluetoothAdapterWin::IsDiscovering() const { discovery_status_ == DISCOVERY_STOPPING; } -// If the method is called when |discovery_status_| is DISCOVERY_STOPPING, -// starting again is handled by BluetoothAdapterWin::DiscoveryStopped(). -void BluetoothAdapterWin::StartDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) { - if (discovery_status_ == DISCOVERING) { - num_discovery_listeners_++; - callback.Run(); - return; - } - on_start_discovery_callbacks_.push_back( - std::make_pair(callback, error_callback)); - MaybePostStartDiscoveryTask(); -} - -void BluetoothAdapterWin::StopDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) { - if (discovery_status_ == NOT_DISCOVERING) { - error_callback.Run(); - return; - } - on_stop_discovery_callbacks_.push_back(callback); - MaybePostStopDiscoveryTask(); -} - void BluetoothAdapterWin::DiscoveryStarted(bool success) { discovery_status_ = success ? DISCOVERING : NOT_DISCOVERING; for (std::vector<std::pair<base::Closure, ErrorCallback> >::const_iterator @@ -226,6 +200,32 @@ void BluetoothAdapterWin::DevicesUpdated( } } +// If the method is called when |discovery_status_| is DISCOVERY_STOPPING, +// starting again is handled by BluetoothAdapterWin::DiscoveryStopped(). +void BluetoothAdapterWin::AddDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) { + if (discovery_status_ == DISCOVERING) { + num_discovery_listeners_++; + callback.Run(); + return; + } + on_start_discovery_callbacks_.push_back( + std::make_pair(callback, error_callback)); + MaybePostStartDiscoveryTask(); +} + +void BluetoothAdapterWin::RemoveDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) { + if (discovery_status_ == NOT_DISCOVERING) { + error_callback.Run(); + return; + } + on_stop_discovery_callbacks_.push_back(callback); + MaybePostStopDiscoveryTask(); +} + void BluetoothAdapterWin::Init() { ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); task_manager_ = diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h index 773c6f3..a017cd6 100644 --- a/device/bluetooth/bluetooth_adapter_win.h +++ b/device/bluetooth/bluetooth_adapter_win.h @@ -55,13 +55,6 @@ class BluetoothAdapterWin : public BluetoothAdapter, const base::Closure& callback, const ErrorCallback& error_callback) OVERRIDE; virtual bool IsDiscovering() const OVERRIDE; - - virtual void StartDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) OVERRIDE; - virtual void StopDiscovering( - const base::Closure& callback, - const ErrorCallback& error_callback) OVERRIDE; virtual void ReadLocalOutOfBandPairingData( const BluetoothOutOfBandPairingDataCallback& callback, const ErrorCallback& error_callback) OVERRIDE; @@ -93,6 +86,14 @@ class BluetoothAdapterWin : public BluetoothAdapter, explicit BluetoothAdapterWin(const InitCallback& init_callback); virtual ~BluetoothAdapterWin(); + // BluetoothAdapter override. + virtual void AddDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) OVERRIDE; + virtual void RemoveDiscoverySession( + const base::Closure& callback, + const ErrorCallback& error_callback) OVERRIDE; + void Init(); void InitForTest( scoped_refptr<base::SequencedTaskRunner> ui_task_runner, diff --git a/device/bluetooth/bluetooth_chromeos_unittest.cc b/device/bluetooth/bluetooth_chromeos_unittest.cc index 6e4db1a..5576f40 100644 --- a/device/bluetooth/bluetooth_chromeos_unittest.cc +++ b/device/bluetooth/bluetooth_chromeos_unittest.cc @@ -225,6 +225,8 @@ class BluetoothChromeOSTest : public testing::Test { new FakeBluetoothAgentManagerClient)); DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager); + fake_bluetooth_adapter_client_->SetSimulationIntervalMs(10); + callback_count_ = 0; error_callback_count_ = 0; last_connect_error_ = BluetoothDevice::ERROR_UNKNOWN; @@ -238,10 +240,18 @@ class BluetoothChromeOSTest : public testing::Test { // Generic callbacks void Callback() { ++callback_count_; + QuitMessageLoop(); } void ErrorCallback() { ++error_callback_count_; + QuitMessageLoop(); + } + + void DBusErrorCallback(const std::string& error_name, + const std::string& error_message) { + ++error_callback_count_; + QuitMessageLoop(); } void ConnectErrorCallback(enum BluetoothDevice::ConnectErrorCode error) { @@ -286,6 +296,7 @@ class BluetoothChromeOSTest : public testing::Test { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + base::MessageLoop::current()->Run(); ASSERT_EQ(2, callback_count_); ASSERT_EQ(0, error_callback_count_); callback_count_ = 0; @@ -302,6 +313,7 @@ class BluetoothChromeOSTest : public testing::Test { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + base::MessageLoop::current()->Run(); ASSERT_EQ(1, callback_count_); ASSERT_EQ(0, error_callback_count_); callback_count_ = 0; @@ -326,6 +338,15 @@ class BluetoothChromeOSTest : public testing::Test { int callback_count_; int error_callback_count_; enum BluetoothDevice::ConnectErrorCode last_connect_error_; + + private: + // Some tests use a message loop since background processing is simulated; + // break out of those loops. + void QuitMessageLoop() { + if (base::MessageLoop::current() && + base::MessageLoop::current()->is_running()) + base::MessageLoop::current()->Quit(); + } }; TEST_F(BluetoothChromeOSTest, AlreadyPresent) { @@ -597,6 +618,7 @@ TEST_F(BluetoothChromeOSTest, StopDiscovery) { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + message_loop.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; @@ -615,6 +637,7 @@ TEST_F(BluetoothChromeOSTest, StopDiscovery) { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + message_loop.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); @@ -640,6 +663,7 @@ TEST_F(BluetoothChromeOSTest, StopDiscoveryAfterTwoStarts) { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + message_loop.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; @@ -657,6 +681,7 @@ TEST_F(BluetoothChromeOSTest, StopDiscoveryAfterTwoStarts) { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + message_loop.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; @@ -670,6 +695,7 @@ TEST_F(BluetoothChromeOSTest, StopDiscoveryAfterTwoStarts) { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + message_loop.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; @@ -686,6 +712,7 @@ TEST_F(BluetoothChromeOSTest, StopDiscoveryAfterTwoStarts) { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + message_loop.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); @@ -716,6 +743,7 @@ TEST_F(BluetoothChromeOSTest, Discovery) { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + message_loop.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; @@ -758,6 +786,7 @@ TEST_F(BluetoothChromeOSTest, PoweredAndDiscovering) { base::Unretained(this)), base::Bind(&BluetoothChromeOSTest::ErrorCallback, base::Unretained(this))); + message_loop.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; @@ -814,6 +843,433 @@ TEST_F(BluetoothChromeOSTest, PoweredAndDiscovering) { EXPECT_FALSE(adapter_->IsDiscovering()); } +// This unit test asserts that the basic reference counting logic works +// correctly for discovery requests done via the BluetoothAdapter. +TEST_F(BluetoothChromeOSTest, MultipleDiscoverySessions) { + base::MessageLoop message_loop; + GetAdapter(); + adapter_->SetPowered( + true, + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(adapter_->IsPowered()); + callback_count_ = 0; + + TestObserver observer(adapter_); + adapter_->AddObserver(&observer); + + EXPECT_EQ(0, observer.discovering_changed_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + // Request device discovery 3 times. + for (int i = 0; i < 3; i++) { + adapter_->StartDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + } + // Run only once, as there should have been one D-Bus call. + message_loop.Run(); + + // The observer should have received the discovering changed event exactly + // once, the success callback should have been called 3 times and the adapter + // should be discovering. + EXPECT_EQ(1, observer.discovering_changed_count_); + EXPECT_EQ(3, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Request to stop discovery twice. + for (int i = 0; i < 2; i++) { + adapter_->StopDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + } + + // The observer should have received no additional discovering changed events, + // the success callback should have been called 2 times and the adapter should + // still be discovering. + EXPECT_EQ(1, observer.discovering_changed_count_); + EXPECT_EQ(5, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Request device discovery 3 times. + for (int i = 0; i < 3; i++) { + adapter_->StartDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + } + + // The observer should have received no additional discovering changed events, + // the success callback should have been called 3 times and the adapter should + // still be discovering. + EXPECT_EQ(1, observer.discovering_changed_count_); + EXPECT_EQ(8, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Request to stop discovery 4 times. + for (int i = 0; i < 4; i++) { + adapter_->StopDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + } + // Run only once, as there should have been one D-Bus call. + message_loop.Run(); + + // The observer should have received the discovering changed event exactly + // once, the success callback should have been called 4 times and the adapter + // should no longer be discovering. + EXPECT_EQ(2, observer.discovering_changed_count_); + EXPECT_EQ(12, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + // Request to stop discovery once. + adapter_->StopDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + + // The call should have failed. + EXPECT_EQ(2, observer.discovering_changed_count_); + EXPECT_EQ(12, callback_count_); + EXPECT_EQ(1, error_callback_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); +} + +// This unit test asserts that the reference counting logic works correctly in +// the cases when the adapter gets reset and D-Bus calls are made outside of +// the BluetoothAdapter. +TEST_F(BluetoothChromeOSTest, + UnexpectedChangesDuringMultipleDiscoverySessions) { + base::MessageLoop message_loop; + GetAdapter(); + adapter_->SetPowered( + true, + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(adapter_->IsPowered()); + callback_count_ = 0; + + TestObserver observer(adapter_); + adapter_->AddObserver(&observer); + + EXPECT_EQ(0, observer.discovering_changed_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + // Request device discovery 3 times. + for (int i = 0; i < 3; i++) { + adapter_->StartDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + } + // Run only once, as there should have been one D-Bus call. + message_loop.Run(); + + // The observer should have received the discovering changed event exactly + // once, the success callback should have been called 3 times and the adapter + // should be discovering. + EXPECT_EQ(1, observer.discovering_changed_count_); + EXPECT_EQ(3, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Stop the timers that the simulation uses + fake_bluetooth_device_client_->EndDiscoverySimulation( + dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath)); + + ASSERT_TRUE(adapter_->IsPowered()); + ASSERT_TRUE(adapter_->IsDiscovering()); + + // Stop device discovery behind the adapter. The adapter and the observer + // should be notified of the change and the reference count should be reset. + // Even though FakeBluetoothAdapterClient does its own reference counting and + // we called 3 BluetoothAdapter::StartDiscovering 3 times, the + // FakeBluetoothAdapterClient's count should be only 1 and a single call to + // FakeBluetoothAdapterClient::StopDiscovery should work. + fake_bluetooth_adapter_client_->StopDiscovery( + dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath), + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::DBusErrorCallback, + base::Unretained(this))); + message_loop.Run(); + EXPECT_EQ(2, observer.discovering_changed_count_); + EXPECT_EQ(4, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + // It should be possible to successfully start discovery. + for (int i = 0; i < 2; i++) { + adapter_->StartDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + } + // Run only once, as there should have been one D-Bus call. + message_loop.Run(); + EXPECT_EQ(3, observer.discovering_changed_count_); + EXPECT_EQ(6, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + fake_bluetooth_device_client_->EndDiscoverySimulation( + dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath)); + + // Make the adapter disappear and appear. This will make it come back as + // discovering. When this happens, the reference count should become and + // remain 0 as no new request was made through the BluetoothAdapter. + fake_bluetooth_adapter_client_->SetVisible(false); + ASSERT_FALSE(adapter_->IsPresent()); + EXPECT_EQ(4, observer.discovering_changed_count_); + EXPECT_EQ(6, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + fake_bluetooth_adapter_client_->SetVisible(true); + ASSERT_TRUE(adapter_->IsPresent()); + EXPECT_EQ(5, observer.discovering_changed_count_); + EXPECT_EQ(6, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Start and stop discovery. At this point, FakeBluetoothAdapterClient has + // a reference count that is equal to 1. Pretend that this was done by an + // application other than us. Starting and stopping discovery will succeed + // but it won't cause the discovery state to change. + adapter_->StartDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + message_loop.Run(); // Run the loop, as there should have been a D-Bus call. + EXPECT_EQ(5, observer.discovering_changed_count_); + EXPECT_EQ(7, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + adapter_->StopDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + message_loop.Run(); // Run the loop, as there should have been a D-Bus call. + EXPECT_EQ(5, observer.discovering_changed_count_); + EXPECT_EQ(8, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Start discovery again. + adapter_->StartDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + message_loop.Run(); // Run the loop, as there should have been a D-Bus call. + EXPECT_EQ(5, observer.discovering_changed_count_); + EXPECT_EQ(9, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Stop discovery via D-Bus. The fake client's reference count will drop but + // the discovery state won't change since our BluetoothAdapter also just + // requested it via D-Bus. + fake_bluetooth_adapter_client_->StopDiscovery( + dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath), + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::DBusErrorCallback, + base::Unretained(this))); + message_loop.Run(); + EXPECT_EQ(5, observer.discovering_changed_count_); + EXPECT_EQ(10, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Now end the discovery session. This should change the adapter's discovery + // state. + adapter_->StopDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + message_loop.Run(); + EXPECT_EQ(6, observer.discovering_changed_count_); + EXPECT_EQ(11, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); +} + +TEST_F(BluetoothChromeOSTest, QueuedDiscoveryRequests) { + base::MessageLoop message_loop; + GetAdapter(); + + adapter_->SetPowered( + true, + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(adapter_->IsPowered()); + callback_count_ = 0; + + TestObserver observer(adapter_); + adapter_->AddObserver(&observer); + + EXPECT_EQ(0, observer.discovering_changed_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + // Request to start discovery. The call should be pending. + adapter_->StartDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + EXPECT_EQ(0, callback_count_); + + fake_bluetooth_device_client_->EndDiscoverySimulation( + dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath)); + + // The underlying adapter has started discovery, but our call hasn't returned + // yet. + EXPECT_EQ(1, observer.discovering_changed_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Try to stop discovery. This should fail while there is a call pending. + adapter_->StopDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + EXPECT_EQ(0, callback_count_); + EXPECT_EQ(1, error_callback_count_); + EXPECT_EQ(1, observer.discovering_changed_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Request to start discovery twice. These should get queued and there should + // be no change in state. + for (int i = 0; i < 2; i++) { + adapter_->StartDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + } + EXPECT_EQ(0, callback_count_); + EXPECT_EQ(1, error_callback_count_); + EXPECT_EQ(1, observer.discovering_changed_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Process the pending call. The queued calls should execute and the discovery + // session reference count should increase. + message_loop.Run(); + EXPECT_EQ(3, callback_count_); + EXPECT_EQ(1, error_callback_count_); + EXPECT_EQ(1, observer.discovering_changed_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // Verify the reference count by removing sessions 3 times. The last request + // should remain pending. + for (int i = 0; i < 3; i++) { + adapter_->StopDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + } + EXPECT_EQ(5, callback_count_); + EXPECT_EQ(1, error_callback_count_); + EXPECT_EQ(2, observer.discovering_changed_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + // Request to stop should fail. + adapter_->StopDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + EXPECT_EQ(5, callback_count_); + EXPECT_EQ(2, error_callback_count_); + EXPECT_EQ(2, observer.discovering_changed_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + // Request to start should get queued. + adapter_->StartDiscovering( + base::Bind(&BluetoothChromeOSTest::Callback, + base::Unretained(this)), + base::Bind(&BluetoothChromeOSTest::ErrorCallback, + base::Unretained(this))); + EXPECT_EQ(5, callback_count_); + EXPECT_EQ(2, error_callback_count_); + EXPECT_EQ(2, observer.discovering_changed_count_); + EXPECT_FALSE(observer.last_discovering_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + // Run the pending request. + message_loop.Run(); + EXPECT_EQ(6, callback_count_); + EXPECT_EQ(2, error_callback_count_); + EXPECT_EQ(3, observer.discovering_changed_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); + + // The queued request to start discovery should have been issued but is still + // pending. Run the loop and verify. + message_loop.Run(); + EXPECT_EQ(7, callback_count_); + EXPECT_EQ(2, error_callback_count_); + EXPECT_EQ(3, observer.discovering_changed_count_); + EXPECT_TRUE(observer.last_discovering_); + EXPECT_TRUE(adapter_->IsDiscovering()); +} + TEST_F(BluetoothChromeOSTest, DeviceProperties) { GetAdapter(); diff --git a/device/bluetooth/test/mock_bluetooth_adapter.h b/device/bluetooth/test/mock_bluetooth_adapter.h index 0266f03..1e1cb35 100644 --- a/device/bluetooth/test/mock_bluetooth_adapter.h +++ b/device/bluetooth/test/mock_bluetooth_adapter.h @@ -67,6 +67,12 @@ class MockBluetoothAdapter : public BluetoothAdapter { void(const BluetoothOutOfBandPairingDataCallback& callback, const ErrorCallback& error_callback)); protected: + MOCK_METHOD2(AddDiscoverySession, + void(const base::Closure& callback, + const ErrorCallback& error_callback)); + MOCK_METHOD2(RemoveDiscoverySession, + void(const base::Closure& callback, + const ErrorCallback& error_callback)); virtual ~MockBluetoothAdapter(); }; |