diff options
author | youngki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-21 22:27:05 +0000 |
---|---|---|
committer | youngki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-21 22:27:05 +0000 |
commit | d7ba4375ff5397e48cace373c094de118228c6eb (patch) | |
tree | 819360053382a21a7f58f96123cc72ffd6d99272 | |
parent | 71b05e336fad0c76397a041bcb681fb84c6decb2 (diff) | |
download | chromium_src-d7ba4375ff5397e48cace373c094de118228c6eb.zip chromium_src-d7ba4375ff5397e48cace373c094de118228c6eb.tar.gz chromium_src-d7ba4375ff5397e48cace373c094de118228c6eb.tar.bz2 |
Implemented Device/Service discovery with incremented timeout values.
BluetoothTaskManagerWin::StartDiscovery() calls BluetoothTaskManagerWin::DiscoverDevices() with timeout = 1. DiscoverDevices() then issues a device inquiry for timeout period, then posts another DiscoverDevices() with timeout+1. DiscoverDevices() stops posting itself when StopDiscovery() is called, or timeout reaches maximum (48).
BUG=135470,168361
Review URL: https://chromiumcodereview.appspot.com/12041035
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@183869 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/extensions/api/bluetooth/bluetooth_api.cc | 4 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc | 74 | ||||
-rw-r--r-- | chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc | 9 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_win.cc | 189 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_win.h | 47 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_win_unittest.cc | 467 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_device.h | 3 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_device_win.cc | 65 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_device_win.h | 26 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_service_record_win.h | 2 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_task_manager_win.cc | 302 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_task_manager_win.h | 73 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_task_manager_win_unittest.cc | 96 |
13 files changed, 1222 insertions, 135 deletions
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc index d2d3305..877dcc4 100644 --- a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc +++ b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc @@ -514,6 +514,7 @@ void BluetoothStartDiscoveryFunction::OnErrorCallback() { SetError(kStartDiscoveryFailed); GetEventRouter(profile())->SetResponsibleForDiscovery(false); SendResponse(false); + GetEventRouter(profile())->OnListenerRemoved(); } bool BluetoothStartDiscoveryFunction::DoWork( @@ -524,6 +525,7 @@ bool BluetoothStartDiscoveryFunction::DoWork( // else to do. if (!GetEventRouter(profile())->IsResponsibleForDiscovery()) { GetEventRouter(profile())->SetResponsibleForDiscovery(true); + GetEventRouter(profile())->OnListenerAdded(); adapter->StartDiscovering( base::Bind(&BluetoothStartDiscoveryFunction::OnSuccessCallback, this), base::Bind(&BluetoothStartDiscoveryFunction::OnErrorCallback, this)); @@ -534,12 +536,14 @@ bool BluetoothStartDiscoveryFunction::DoWork( void BluetoothStopDiscoveryFunction::OnSuccessCallback() { SendResponse(true); + GetEventRouter(profile())->OnListenerRemoved(); } void BluetoothStopDiscoveryFunction::OnErrorCallback() { SetError(kStopDiscoveryFailed); GetEventRouter(profile())->SetResponsibleForDiscovery(true); SendResponse(false); + GetEventRouter(profile())->OnListenerRemoved(); } bool BluetoothStopDiscoveryFunction::DoWork( diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc index 46afeb0..63828ff 100644 --- a/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc +++ b/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc @@ -47,6 +47,14 @@ class BluetoothApiTest : public ExtensionApiTest { } virtual void SetUpOnMainThread() OVERRIDE { + SetUpMockAdapter(); + } + + virtual void CleanUpOnMainThread() OVERRIDE { + EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); + } + + void SetUpMockAdapter() { // The browser will clean this up when it is torn down mock_adapter_ = new testing::StrictMock<MockBluetoothAdapter>( kAdapterAddress, kName); @@ -60,10 +68,6 @@ class BluetoothApiTest : public ExtensionApiTest { false /* paired */, true /* bonded */, false /* connected */)); } - virtual void CleanUpOnMainThread() OVERRIDE { - EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); - } - template <class T> T* setupFunction(T* function) { function->set_extension(empty_extension_.get()); @@ -103,6 +107,18 @@ static bool CallClosure(const base::Closure& callback) { return true; } +static void CallDiscoveryCallback( + const base::Closure& callback, + const BluetoothAdapter::ErrorCallback& error_callback) { + callback.Run(); +} + +static void CallDiscoveryErrorCallback( + const base::Closure& callback, + const BluetoothAdapter::ErrorCallback& error_callback) { + error_callback.Run(); +} + static void CallOutOfBandPairingDataCallback( const BluetoothAdapter::BluetoothOutOfBandPairingDataCallback& callback, const BluetoothAdapter::ErrorCallback& error_callback) { @@ -227,9 +243,10 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, SetOutOfBandPairingData) { IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) { // Try with a failure to start - EXPECT_CALL(*mock_adapter_, - StartDiscovering(testing::_, - testing::Truly(CallClosure))); + EXPECT_CALL(*mock_adapter_, StartDiscovering(testing::_, testing::_)) + .WillOnce(testing::Invoke(CallDiscoveryErrorCallback)); + // StartDiscovery failure will remove the adapter that is no longer used. + EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); scoped_refptr<api::BluetoothStartDiscoveryFunction> start_function; start_function = setupFunction(new api::BluetoothStartDiscoveryFunction); std::string error( @@ -237,38 +254,39 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Discovery) { ASSERT_TRUE(!error.empty()); // Reset for a successful start - testing::Mock::VerifyAndClearExpectations(mock_adapter_); - EXPECT_CALL(*mock_adapter_, - StartDiscovering(testing::Truly(CallClosure), - testing::_)); + SetUpMockAdapter(); + EXPECT_CALL(*mock_adapter_, StartDiscovering(testing::_, testing::_)) + .WillOnce(testing::Invoke(CallDiscoveryCallback)); start_function = setupFunction(new api::BluetoothStartDiscoveryFunction); (void)utils::RunFunctionAndReturnError(start_function, "[]", browser()); // Reset to try stopping testing::Mock::VerifyAndClearExpectations(mock_adapter_); - EXPECT_CALL(*mock_adapter_, - StopDiscovering(testing::Truly(CallClosure), - testing::_)); + EXPECT_CALL(*mock_adapter_, StopDiscovering(testing::_, testing::_)) + .WillOnce(testing::Invoke(CallDiscoveryCallback)); + // StopDiscovery success will remove the apapter that is no longer used. + EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); scoped_refptr<api::BluetoothStopDiscoveryFunction> stop_function; stop_function = setupFunction(new api::BluetoothStopDiscoveryFunction); (void)utils::RunFunctionAndReturnSingleResult(stop_function, "[]", browser()); // Reset to try stopping with an error - testing::Mock::VerifyAndClearExpectations(mock_adapter_); - EXPECT_CALL(*mock_adapter_, - StopDiscovering(testing::_, - testing::Truly(CallClosure))); + SetUpMockAdapter(); + EXPECT_CALL(*mock_adapter_, StopDiscovering(testing::_, testing::_)) + .WillOnce(testing::Invoke(CallDiscoveryErrorCallback)); + EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); stop_function = setupFunction(new api::BluetoothStopDiscoveryFunction); error = utils::RunFunctionAndReturnError(stop_function, "[]", browser()); ASSERT_TRUE(!error.empty()); + SetUpMockAdapter(); } IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryCallback) { - EXPECT_CALL(*mock_adapter_, - StartDiscovering(testing::Truly(CallClosure), testing::_)); - EXPECT_CALL(*mock_adapter_, - StopDiscovering(testing::Truly(CallClosure), testing::_)); + EXPECT_CALL(*mock_adapter_, StartDiscovering(testing::_, testing::_)) + .WillOnce(testing::Invoke(CallDiscoveryCallback)); + EXPECT_CALL(*mock_adapter_, StopDiscovering(testing::_, testing::_)) + .WillOnce(testing::Invoke(CallDiscoveryCallback)); ResultCatcher catcher; catcher.RestrictToProfile(browser()->profile()); @@ -282,8 +300,10 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryCallback) { discovery_started.Reply("go"); ExtensionTestMessageListener discovery_stopped("ready", true); + EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); EXPECT_TRUE(discovery_stopped.WaitUntilSatisfied()); + SetUpMockAdapter(); event_router()->DeviceAdded(mock_adapter_, device2_.get()); discovery_stopped.Reply("go"); @@ -307,10 +327,10 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryInProgress) { ResultCatcher catcher; catcher.RestrictToProfile(browser()->profile()); - EXPECT_CALL(*mock_adapter_, - StartDiscovering(testing::Truly(CallClosure), testing::_)); - EXPECT_CALL(*mock_adapter_, - StopDiscovering(testing::Truly(CallClosure), testing::_)); + EXPECT_CALL(*mock_adapter_, StartDiscovering(testing::_, testing::_)) + .WillOnce(testing::Invoke(CallDiscoveryCallback)); + EXPECT_CALL(*mock_adapter_, StopDiscovering(testing::_, testing::_)) + .WillOnce(testing::Invoke(CallDiscoveryCallback)); ExtensionTestMessageListener discovery_started("ready", true); ASSERT_TRUE(LoadExtension( @@ -322,8 +342,10 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryInProgress) { discovery_started.Reply("go"); ExtensionTestMessageListener discovery_stopped("ready", true); + EXPECT_CALL(*mock_adapter_, RemoveObserver(testing::_)); EXPECT_TRUE(discovery_stopped.WaitUntilSatisfied()); + SetUpMockAdapter(); // This should never be received. event_router()->DeviceAdded(mock_adapter_, device2_.get()); discovery_stopped.Reply("go"); diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc index 46ea7c8..9cb6e5f 100644 --- a/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc +++ b/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc @@ -63,8 +63,8 @@ void ExtensionBluetoothEventRouter::OnListenerAdded() { } void ExtensionBluetoothEventRouter::OnListenerRemoved() { - num_event_listeners_--; - CHECK(num_event_listeners_ >= 0); + if (num_event_listeners_ > 0) + num_event_listeners_--; MaybeReleaseAdapter(); } @@ -192,9 +192,10 @@ void ExtensionBluetoothEventRouter::InitializeAdapterIfNeeded() { void ExtensionBluetoothEventRouter::InitializeAdapter( scoped_refptr<device::BluetoothAdapter> adapter) { - adapter_ = adapter; - if (adapter_) + if (!adapter_) { + adapter_ = adapter; adapter_->AddObserver(this); + } } void ExtensionBluetoothEventRouter::MaybeReleaseAdapter() { diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc index 8678668..d9f3520 100644 --- a/device/bluetooth/bluetooth_adapter_win.cc +++ b/device/bluetooth/bluetooth_adapter_win.cc @@ -6,11 +6,17 @@ #include "device/bluetooth/bluetooth_adapter_win.h" +#include <hash_set> #include <string> +#include <utility> + #include "base/logging.h" #include "base/sequenced_task_runner.h" #include "base/single_thread_task_runner.h" +#include "base/stl_util.h" #include "base/thread_task_runner_handle.h" +#include "device/bluetooth/bluetooth_device_win.h" +#include "device/bluetooth/bluetooth_task_manager_win.h" namespace device { @@ -19,6 +25,9 @@ BluetoothAdapterWin::BluetoothAdapterWin(const InitCallback& init_callback) init_callback_(init_callback), initialized_(false), powered_(false), + discovery_status_(NOT_DISCOVERING), + scanning_(false), + num_discovery_listeners_(0), ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { } @@ -27,6 +36,7 @@ BluetoothAdapterWin::~BluetoothAdapterWin() { task_manager_->RemoveObserver(this); task_manager_->Shutdown(); } + STLDeleteValues(&devices_); } void BluetoothAdapterWin::AddObserver(BluetoothAdapter::Observer* observer) { @@ -61,41 +71,85 @@ void BluetoothAdapterWin::SetPowered( } bool BluetoothAdapterWin::IsDiscovering() const { - NOTIMPLEMENTED(); - return false; + return discovery_status_ == DISCOVERING || + discovery_status_ == DISCOVERY_STOPPING; } bool BluetoothAdapterWin::IsScanning() const { - NOTIMPLEMENTED(); - return false; + return scanning_; } +// 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) { - NOTIMPLEMENTED(); + 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) { - NOTIMPLEMENTED(); + if (discovery_status_ == NOT_DISCOVERING) { + error_callback.Run(); + return; + } + on_stop_discovery_callbacks_.push_back(callback); + MaybePostStopDiscoveryTask(); } -BluetoothAdapter::ConstDeviceList BluetoothAdapterWin::GetDevices() const { - NOTIMPLEMENTED(); - return BluetoothAdapter::ConstDeviceList(); -} +void BluetoothAdapterWin::DiscoveryStarted(bool success) { + discovery_status_ = success ? DISCOVERING : NOT_DISCOVERING; + for (std::vector<std::pair<base::Closure, ErrorCallback> >::const_iterator + iter = on_start_discovery_callbacks_.begin(); + iter != on_start_discovery_callbacks_.end(); + ++iter) { + if (success) + ui_task_runner_->PostTask(FROM_HERE, iter->first); + else + ui_task_runner_->PostTask(FROM_HERE, iter->second); + } + num_discovery_listeners_ = on_start_discovery_callbacks_.size(); + on_start_discovery_callbacks_.clear(); -BluetoothDevice* BluetoothAdapterWin::GetDevice(const std::string& address) { - NOTIMPLEMENTED(); - return NULL; + if (success) { + FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, + AdapterDiscoveringChanged(this, true)); + + // If there are stop discovery requests, post the stop discovery again. + MaybePostStopDiscoveryTask(); + } else if (!on_stop_discovery_callbacks_.empty()) { + // If there are stop discovery requests but start discovery has failed, + // notify that stop discovery has been complete. + DiscoveryStopped(); + } } -const BluetoothDevice* BluetoothAdapterWin::GetDevice( - const std::string& address) const { - NOTIMPLEMENTED(); - return NULL; +void BluetoothAdapterWin::DiscoveryStopped() { + bool was_discovering = IsDiscovering(); + discovery_status_ = NOT_DISCOVERING; + for (std::vector<base::Closure>::const_iterator iter = + on_stop_discovery_callbacks_.begin(); + iter != on_stop_discovery_callbacks_.end(); + ++iter) { + ui_task_runner_->PostTask(FROM_HERE, *iter); + } + num_discovery_listeners_ = 0; + on_stop_discovery_callbacks_.clear(); + ScanningChanged(false); + if (was_discovering) + FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, + AdapterDiscoveringChanged(this, false)); + + // If there are start discovery requests, post the start discovery again. + MaybePostStartDiscoveryTask(); } void BluetoothAdapterWin::ReadLocalOutOfBandPairingData( @@ -111,16 +165,113 @@ void BluetoothAdapterWin::AdapterStateChanged( address_ = state.address; powered_ = state.powered; if (!initialized_) { + initialized_ = true; init_callback_.Run(); } - initialized_ = true; +} + +void BluetoothAdapterWin::ScanningChanged(bool scanning) { + if (scanning_ != scanning) { + scanning_ = scanning; + FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, + AdapterScanningChanged(this, scanning_)); + } +} + +void BluetoothAdapterWin::DevicesDiscovered( + const ScopedVector<BluetoothTaskManagerWin::DeviceState>& devices) { + std::hash_set<std::string> device_address_list; + for (ScopedVector<BluetoothTaskManagerWin::DeviceState>::const_iterator iter = + devices.begin(); + iter != devices.end(); + ++iter) { + device_address_list.insert((*iter)->address); + DevicesMap::iterator found_device_iter = devices_.find((*iter)->address); + + if (found_device_iter == devices_.end()) { + devices_[(*iter)->address] = new BluetoothDeviceWin(**iter); + FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, + DeviceAdded(this, devices_[(*iter)->address])); + continue; + } + BluetoothDeviceWin* device_win = + static_cast<BluetoothDeviceWin*>(found_device_iter->second); + if (device_win->device_fingerprint() != + BluetoothDeviceWin::ComputeDeviceFingerprint(**iter)) { + devices_[(*iter)->address] = new BluetoothDeviceWin(**iter); + FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, + DeviceChanged(this, devices_[(*iter)->address])); + delete device_win; + } + } + + DevicesMap::iterator device_iter = devices_.begin(); + while (device_iter != devices_.end()) { + if (device_address_list.find(device_iter->first) != + device_address_list.end()) { + ++device_iter; + continue; + } + if (device_iter->second->IsConnected() || device_iter->second->IsPaired()) { + BluetoothDeviceWin* device_win = + static_cast<BluetoothDeviceWin*>(device_iter->second); + device_win->SetVisible(false); + FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, + DeviceChanged(this, device_win)); + ++device_iter; + continue; + } + FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, + DeviceRemoved(this, device_iter->second)); + delete device_iter->second; + device_iter = devices_.erase(device_iter); + } } void BluetoothAdapterWin::TrackDefaultAdapter() { + ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); task_manager_ = - new BluetoothTaskManagerWin(base::ThreadTaskRunnerHandle::Get()); + new BluetoothTaskManagerWin(ui_task_runner_); task_manager_->AddObserver(this); task_manager_->Initialize(); } +void BluetoothAdapterWin::TrackTestAdapter( + scoped_refptr<base::SequencedTaskRunner> ui_task_runner, + scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) { + ui_task_runner_ = ui_task_runner; + task_manager_ = + new BluetoothTaskManagerWin(ui_task_runner_); + task_manager_->AddObserver(this); + task_manager_->InitializeWithBluetoothTaskRunner(bluetooth_task_runner); +} + +void BluetoothAdapterWin::MaybePostStartDiscoveryTask() { + if (discovery_status_ == NOT_DISCOVERING && + !on_start_discovery_callbacks_.empty()) { + discovery_status_ = DISCOVERY_STARTING; + task_manager_->PostStartDiscoveryTask(); + } +} + +void BluetoothAdapterWin::MaybePostStopDiscoveryTask() { + if (discovery_status_ != DISCOVERING) + return; + + if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) { + for (std::vector<base::Closure>::const_iterator iter = + on_stop_discovery_callbacks_.begin(); + iter != on_stop_discovery_callbacks_.end(); + ++iter) { + ui_task_runner_->PostTask(FROM_HERE, *iter); + } + num_discovery_listeners_ -= on_stop_discovery_callbacks_.size(); + on_stop_discovery_callbacks_.clear(); + return; + } + + discovery_status_ = DISCOVERY_STOPPING; + task_manager_->PostStopDiscoveryTask(); +} + } // namespace device diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h index 0feb0f0..178a995 100644 --- a/device/bluetooth/bluetooth_adapter_win.h +++ b/device/bluetooth/bluetooth_adapter_win.h @@ -6,13 +6,22 @@ #define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_WIN_H_ #include <string> +#include <utility> +#include <vector> #include "base/memory/ref_counted.h" +#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_task_manager_win.h" +namespace base { + +class SequencedTaskRunner; + +} // namespace base + namespace device { class BluetoothAdapterFactory; @@ -36,16 +45,13 @@ class BluetoothAdapterWin : public BluetoothAdapter, const ErrorCallback& error_callback) OVERRIDE; virtual bool IsDiscovering() const OVERRIDE; virtual bool IsScanning() 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 ConstDeviceList GetDevices() const OVERRIDE; - virtual BluetoothDevice* GetDevice(const std::string& address) OVERRIDE; - virtual const BluetoothDevice* GetDevice( - const std::string& address) const OVERRIDE; virtual void ReadLocalOutOfBandPairingData( const BluetoothOutOfBandPairingDataCallback& callback, const ErrorCallback& error_callback) OVERRIDE; @@ -53,22 +59,47 @@ class BluetoothAdapterWin : public BluetoothAdapter, // BluetoothTaskManagerWin::Observer override virtual void AdapterStateChanged( const BluetoothTaskManagerWin::AdapterState& state) OVERRIDE; + virtual void DiscoveryStarted(bool success) OVERRIDE; + virtual void DiscoveryStopped() OVERRIDE; + virtual void ScanningChanged(bool scanning) OVERRIDE; + virtual void DevicesDiscovered( + const ScopedVector<BluetoothTaskManagerWin::DeviceState>& devices) + OVERRIDE; - protected: + private: + friend class BluetoothAdapterFactory; friend class BluetoothAdapterWinTest; + enum DiscoveryStatus { + NOT_DISCOVERING, + DISCOVERY_STARTING, + DISCOVERING, + DISCOVERY_STOPPING + }; + BluetoothAdapterWin(const InitCallback& init_callback); virtual ~BluetoothAdapterWin(); - private: - friend class BluetoothAdapterFactory; - void TrackDefaultAdapter(); + void TrackTestAdapter( + scoped_refptr<base::SequencedTaskRunner> ui_task_runner, + scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner); + + void MaybePostStartDiscoveryTask(); + void MaybePostStopDiscoveryTask(); InitCallback init_callback_; bool initialized_; bool powered_; + DiscoveryStatus discovery_status_; + bool scanning_; + + std::vector<std::pair<base::Closure, ErrorCallback> > + on_start_discovery_callbacks_; + std::vector<base::Closure> on_stop_discovery_callbacks_; + size_t num_discovery_listeners_; + scoped_refptr<base::SequencedTaskRunner> ui_task_runner_; scoped_refptr<BluetoothTaskManagerWin> task_manager_; base::ThreadChecker thread_checker_; diff --git a/device/bluetooth/bluetooth_adapter_win_unittest.cc b/device/bluetooth/bluetooth_adapter_win_unittest.cc index afd85b6..d71c48f 100644 --- a/device/bluetooth/bluetooth_adapter_win_unittest.cc +++ b/device/bluetooth/bluetooth_adapter_win_unittest.cc @@ -6,8 +6,10 @@ #include "base/bind.h" #include "base/memory/ref_counted.h" +#include "base/test/test_simple_task_runner.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_adapter_win.h" +#include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_task_manager_win.h" #include "testing/gtest/include/gtest/gtest.h" @@ -16,6 +18,87 @@ namespace { const char kAdapterAddress[] = "Bluetooth Adapter Address"; const char kAdapterName[] = "Bluetooth Adapter Name"; + +void MakeDeviceState(const std::string& name, + const std::string& address, + device::BluetoothTaskManagerWin::DeviceState* state) { + state->name = name; + state->address = address; + state->bluetooth_class = 0; + state->authenticated = false; + state->connected = false; +} + +class AdapterObserver : public device::BluetoothAdapter::Observer { + public: + AdapterObserver() { + Clear(); + } + + void Clear() { + num_discovering_changed_ = 0; + num_scanning_changed_ = 0; + num_device_added_ = 0; + num_device_changed_ = 0; + num_device_removed_ = 0; + } + + virtual void AdapterDiscoveringChanged( + device::BluetoothAdapter* adapter, bool discovering) OVERRIDE { + num_discovering_changed_++; + } + + virtual void AdapterScanningChanged( + device::BluetoothAdapter* adapter, bool scanning) OVERRIDE { + num_scanning_changed_++; + } + + virtual void DeviceAdded( + device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) OVERRIDE { + num_device_added_++; + } + + virtual void DeviceChanged( + device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) OVERRIDE { + num_device_changed_++; + } + + virtual void DeviceRemoved( + device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) OVERRIDE { + num_device_removed_++; + } + + int num_discovering_changed() const { + return num_discovering_changed_; + } + + int num_scanning_changed() const { + return num_scanning_changed_; + } + + int num_device_added() const { + return num_device_added_; + } + + int num_device_changed() const { + return num_device_changed_; + } + + int num_device_removed() const { + return num_device_removed_; + } + + private: + int num_discovering_changed_; + int num_scanning_changed_; + int num_device_added_; + int num_device_changed_; + int num_device_removed_; +}; + } // namespace namespace device { @@ -23,21 +106,60 @@ namespace device { class BluetoothAdapterWinTest : public testing::Test { public: BluetoothAdapterWinTest() - : adapter_(new BluetoothAdapterWin( + : ui_task_runner_(new base::TestSimpleTaskRunner()), + bluetooth_task_runner_(new base::TestSimpleTaskRunner()), + adapter_(new BluetoothAdapterWin( base::Bind(&BluetoothAdapterWinTest::RunInitCallback, base::Unretained(this)))), adapter_win_(static_cast<BluetoothAdapterWin*>(adapter_.get())), init_callback_called_(false) { + adapter_win_->TrackTestAdapter(ui_task_runner_, + bluetooth_task_runner_); + } + + virtual void SetUp() OVERRIDE { + adapter_win_->AddObserver(&adapter_observer_); + num_start_discovery_callbacks_ = 0; + num_start_discovery_error_callbacks_ = 0; + num_stop_discovery_callbacks_ = 0; + num_stop_discovery_error_callbacks_ = 0; + } + + virtual void TearDown() OVERRIDE { + adapter_win_->RemoveObserver(&adapter_observer_); } void RunInitCallback() { init_callback_called_ = true; } + void IncrementNumStartDiscoveryCallbacks() { + num_start_discovery_callbacks_++; + } + + void IncrementNumStartDiscoveryErrorCallbacks() { + num_start_discovery_error_callbacks_++; + } + + void IncrementNumStopDiscoveryCallbacks() { + num_stop_discovery_callbacks_++; + } + + void IncrementNumStopDiscoveryErrorCallbacks() { + num_stop_discovery_error_callbacks_++; + } + protected: + scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_; + scoped_refptr<base::TestSimpleTaskRunner> bluetooth_task_runner_; scoped_refptr<BluetoothAdapter> adapter_; BluetoothAdapterWin* adapter_win_; + AdapterObserver adapter_observer_; bool init_callback_called_; + int num_start_discovery_callbacks_; + int num_start_discovery_error_callbacks_; + int num_stop_discovery_callbacks_; + int num_stop_discovery_error_callbacks_; }; TEST_F(BluetoothAdapterWinTest, AdapterNotPresent) { @@ -63,4 +185,345 @@ TEST_F(BluetoothAdapterWinTest, AdapterInitialized) { EXPECT_TRUE(init_callback_called_); } -} // namespace device
\ No newline at end of file +TEST_F(BluetoothAdapterWinTest, SingleStartDiscovery) { + bluetooth_task_runner_->ClearPendingTasks(); + adapter_win_->StartDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + EXPECT_TRUE(ui_task_runner_->GetPendingTasks().empty()); + EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size()); + EXPECT_FALSE(adapter_->IsDiscovering()); + EXPECT_EQ(0, num_start_discovery_callbacks_); + adapter_win_->DiscoveryStarted(true); + ui_task_runner_->RunPendingTasks(); + EXPECT_TRUE(adapter_->IsDiscovering()); + EXPECT_EQ(1, num_start_discovery_callbacks_); + EXPECT_EQ(1, adapter_observer_.num_discovering_changed()); +} + +TEST_F(BluetoothAdapterWinTest, SingleStartDiscoveryFailure) { + adapter_win_->StartDiscovering( + base::Closure(), + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks, + base::Unretained(this))); + adapter_win_->DiscoveryStarted(false); + ui_task_runner_->RunPendingTasks(); + EXPECT_FALSE(adapter_->IsDiscovering()); + EXPECT_EQ(1, num_start_discovery_error_callbacks_); + EXPECT_EQ(0, adapter_observer_.num_discovering_changed()); +} + +TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveries) { + bluetooth_task_runner_->ClearPendingTasks(); + int num_discoveries = 5; + for (int i = 0; i < num_discoveries; i++) { + adapter_win_->StartDiscovering( + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size()); + } + EXPECT_TRUE(ui_task_runner_->GetPendingTasks().empty()); + EXPECT_FALSE(adapter_->IsDiscovering()); + EXPECT_EQ(0, num_start_discovery_callbacks_); + adapter_win_->DiscoveryStarted(true); + ui_task_runner_->RunPendingTasks(); + EXPECT_TRUE(adapter_->IsDiscovering()); + EXPECT_EQ(num_discoveries, num_start_discovery_callbacks_); + EXPECT_EQ(1, adapter_observer_.num_discovering_changed()); +} + +TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveriesFailure) { + int num_discoveries = 5; + for (int i = 0; i < num_discoveries; i++) { + adapter_win_->StartDiscovering( + base::Closure(), + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks, + base::Unretained(this))); + } + adapter_win_->DiscoveryStarted(false); + ui_task_runner_->RunPendingTasks(); + EXPECT_FALSE(adapter_->IsDiscovering()); + EXPECT_EQ(num_discoveries, num_start_discovery_error_callbacks_); + EXPECT_EQ(0, adapter_observer_.num_discovering_changed()); +} + +TEST_F(BluetoothAdapterWinTest, MultipleStartDiscoveriesAfterDiscovering) { + adapter_win_->StartDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + adapter_win_->DiscoveryStarted(true); + ui_task_runner_->RunPendingTasks(); + EXPECT_TRUE(adapter_->IsDiscovering()); + EXPECT_EQ(1, num_start_discovery_callbacks_); + + bluetooth_task_runner_->ClearPendingTasks(); + for (int i = 0; i < 5; i++) { + int num_start_discovery_callbacks = num_start_discovery_callbacks_; + adapter_win_->StartDiscovering( + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + EXPECT_TRUE(adapter_->IsDiscovering()); + EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty()); + EXPECT_TRUE(ui_task_runner_->GetPendingTasks().empty()); + EXPECT_EQ(num_start_discovery_callbacks + 1, + num_start_discovery_callbacks_); + } + EXPECT_EQ(1, adapter_observer_.num_discovering_changed()); +} + +TEST_F(BluetoothAdapterWinTest, StartDiscoveryAfterDiscoveringFailure) { + adapter_win_->StartDiscovering( + base::Closure(), + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks, + base::Unretained(this))); + adapter_win_->DiscoveryStarted(false); + ui_task_runner_->RunPendingTasks(); + EXPECT_FALSE(adapter_->IsDiscovering()); + EXPECT_EQ(1, num_start_discovery_error_callbacks_); + + adapter_win_->StartDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + adapter_win_->DiscoveryStarted(true); + ui_task_runner_->RunPendingTasks(); + EXPECT_TRUE(adapter_->IsDiscovering()); + EXPECT_EQ(1, num_start_discovery_callbacks_); +} + +TEST_F(BluetoothAdapterWinTest, SingleStopDiscovery) { + adapter_win_->StartDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + adapter_win_->DiscoveryStarted(true); + ui_task_runner_->ClearPendingTasks(); + adapter_win_->StopDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + EXPECT_TRUE(adapter_->IsDiscovering()); + EXPECT_EQ(0, num_stop_discovery_callbacks_); + bluetooth_task_runner_->ClearPendingTasks(); + adapter_win_->DiscoveryStopped(); + ui_task_runner_->RunPendingTasks(); + EXPECT_FALSE(adapter_->IsDiscovering()); + EXPECT_EQ(1, num_stop_discovery_callbacks_); + EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty()); + EXPECT_EQ(2, adapter_observer_.num_discovering_changed()); +} + +TEST_F(BluetoothAdapterWinTest, MultipleStopDiscoveries) { + int num_discoveries = 5; + for (int i = 0; i < num_discoveries; i++) { + adapter_win_->StartDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + } + adapter_win_->DiscoveryStarted(true); + ui_task_runner_->ClearPendingTasks(); + bluetooth_task_runner_->ClearPendingTasks(); + for (int i = 0; i < num_discoveries - 1; i++) { + adapter_win_->StopDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty()); + ui_task_runner_->RunPendingTasks(); + EXPECT_EQ(i + 1, num_stop_discovery_callbacks_); + } + adapter_win_->StopDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size()); + EXPECT_TRUE(adapter_->IsDiscovering()); + adapter_win_->DiscoveryStopped(); + ui_task_runner_->RunPendingTasks(); + EXPECT_FALSE(adapter_->IsDiscovering()); + EXPECT_EQ(num_discoveries, num_stop_discovery_callbacks_); + EXPECT_EQ(2, adapter_observer_.num_discovering_changed()); +} + +TEST_F(BluetoothAdapterWinTest, + StartDiscoveryAndStartDiscoveryAndStopDiscoveries) { + adapter_win_->StartDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + adapter_win_->DiscoveryStarted(true); + adapter_win_->StartDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + ui_task_runner_->ClearPendingTasks(); + bluetooth_task_runner_->ClearPendingTasks(); + adapter_win_->StopDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty()); + adapter_win_->StopDiscovering( + base::Bind(&BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size()); +} + +TEST_F(BluetoothAdapterWinTest, + StartDiscoveryAndStopDiscoveryAndStartDiscovery) { + adapter_win_->StartDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + adapter_win_->DiscoveryStarted(true); + EXPECT_TRUE(adapter_->IsDiscovering()); + adapter_win_->StopDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + adapter_win_->DiscoveryStopped(); + EXPECT_FALSE(adapter_->IsDiscovering()); + adapter_win_->StartDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + adapter_win_->DiscoveryStarted(true); + EXPECT_TRUE(adapter_->IsDiscovering()); +} + +TEST_F(BluetoothAdapterWinTest, StartDiscoveryBeforeDiscoveryStopped) { + adapter_win_->StartDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + adapter_win_->DiscoveryStarted(true); + adapter_win_->StopDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + adapter_win_->StartDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + bluetooth_task_runner_->ClearPendingTasks(); + adapter_win_->DiscoveryStopped(); + EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size()); +} + +TEST_F(BluetoothAdapterWinTest, StopDiscoveryWithoutStartDiscovery) { + adapter_win_->StopDiscovering( + base::Closure(), + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStopDiscoveryErrorCallbacks, + base::Unretained(this))); + EXPECT_EQ(1, num_stop_discovery_error_callbacks_); +} + +TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStarted) { + adapter_win_->StartDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + adapter_win_->StopDiscovering( + base::Closure(), BluetoothAdapter::ErrorCallback()); + bluetooth_task_runner_->ClearPendingTasks(); + adapter_win_->DiscoveryStarted(true); + EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size()); +} + +TEST_F(BluetoothAdapterWinTest, StartAndStopBeforeDiscoveryStarted) { + int num_expected_start_discoveries = 3; + int num_expected_stop_discoveries = 2; + for (int i = 0; i < num_expected_start_discoveries; i++) { + adapter_win_->StartDiscovering( + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStartDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + } + for (int i = 0; i < num_expected_stop_discoveries; i++) { + adapter_win_->StopDiscovering( + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + } + bluetooth_task_runner_->ClearPendingTasks(); + adapter_win_->DiscoveryStarted(true); + EXPECT_TRUE(bluetooth_task_runner_->GetPendingTasks().empty()); + ui_task_runner_->RunPendingTasks(); + EXPECT_EQ(num_expected_start_discoveries, num_start_discovery_callbacks_); + EXPECT_EQ(num_expected_stop_discoveries, num_stop_discovery_callbacks_); +} + +TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStartedAndFailed) { + adapter_win_->StartDiscovering( + base::Closure(), + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStartDiscoveryErrorCallbacks, + base::Unretained(this))); + adapter_win_->StopDiscovering( + base::Bind( + &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, + base::Unretained(this)), + BluetoothAdapter::ErrorCallback()); + ui_task_runner_->ClearPendingTasks(); + adapter_win_->DiscoveryStarted(false); + ui_task_runner_->RunPendingTasks(); + EXPECT_EQ(1, num_start_discovery_error_callbacks_); + EXPECT_EQ(1, num_stop_discovery_callbacks_); + EXPECT_EQ(0, adapter_observer_.num_discovering_changed()); +} + +TEST_F(BluetoothAdapterWinTest, ScanningChanged) { + adapter_win_->ScanningChanged(false); + EXPECT_EQ(0, adapter_observer_.num_scanning_changed()); + adapter_win_->ScanningChanged(true); + EXPECT_EQ(1, adapter_observer_.num_scanning_changed()); + adapter_win_->ScanningChanged(true); + EXPECT_EQ(1, adapter_observer_.num_scanning_changed()); + adapter_win_->ScanningChanged(false); + EXPECT_EQ(2, adapter_observer_.num_scanning_changed()); +} + +TEST_F(BluetoothAdapterWinTest, ScanningFalseOnDiscoveryStopped) { + adapter_win_->ScanningChanged(true); + adapter_win_->DiscoveryStopped(); + EXPECT_EQ(2, adapter_observer_.num_scanning_changed()); +} + +TEST_F(BluetoothAdapterWinTest, DevicesDiscovered) { + BluetoothTaskManagerWin::DeviceState* android_phone_state = + new BluetoothTaskManagerWin::DeviceState(); + MakeDeviceState("phone", "android phone address", android_phone_state); + BluetoothTaskManagerWin::DeviceState* laptop_state = + new BluetoothTaskManagerWin::DeviceState(); + MakeDeviceState("laptop", "laptop address", laptop_state); + BluetoothTaskManagerWin::DeviceState* iphone_state = + new BluetoothTaskManagerWin::DeviceState(); + MakeDeviceState("phone", "iphone address", iphone_state); + ScopedVector<BluetoothTaskManagerWin::DeviceState> devices; + devices.push_back(android_phone_state); + devices.push_back(laptop_state); + devices.push_back(iphone_state); + + adapter_win_->DevicesDiscovered(devices); + EXPECT_EQ(3, adapter_observer_.num_device_added()); + adapter_observer_.Clear(); + + iphone_state->name = "apple phone"; + adapter_win_->DevicesDiscovered(devices); + EXPECT_EQ(0, adapter_observer_.num_device_added()); + EXPECT_EQ(1, adapter_observer_.num_device_changed()); + EXPECT_EQ(0, adapter_observer_.num_device_removed()); + adapter_observer_.Clear(); + + laptop_state->address = "notebook address"; + laptop_state->connected = true; + adapter_win_->DevicesDiscovered(devices); + EXPECT_EQ(1, adapter_observer_.num_device_added()); + EXPECT_EQ(0, adapter_observer_.num_device_changed()); + EXPECT_EQ(1, adapter_observer_.num_device_removed()); + adapter_observer_.Clear(); + + devices.clear(); + adapter_win_->DevicesDiscovered(devices); + + EXPECT_EQ(2, adapter_observer_.num_device_removed()); + EXPECT_EQ(1, adapter_observer_.num_device_changed()); +} + +} // namespace device diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h index 319b549..865852a 100644 --- a/device/bluetooth/bluetooth_device.h +++ b/device/bluetooth/bluetooth_device.h @@ -9,8 +9,9 @@ #include <vector> #include "base/callback.h" -#include "base/string16.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_vector.h" +#include "base/string16.h" namespace device { diff --git a/device/bluetooth/bluetooth_device_win.cc b/device/bluetooth/bluetooth_device_win.cc index 14fe785..a083f09 100644 --- a/device/bluetooth/bluetooth_device_win.cc +++ b/device/bluetooth/bluetooth_device_win.cc @@ -7,20 +7,58 @@ #include "device/bluetooth/bluetooth_device_win.h" #include <string> + #include "base/basictypes.h" +#include "base/hash.h" #include "base/logging.h" +#include "base/memory/scoped_vector.h" +#include "base/stringprintf.h" #include "device/bluetooth/bluetooth_out_of_band_pairing_data.h" +#include "device/bluetooth/bluetooth_service_record_win.h" + +namespace { + +const int kSdpBytesBufferSize = 1024; + +} // namespace namespace device { -BluetoothDeviceWin::BluetoothDeviceWin() : BluetoothDevice() { +BluetoothDeviceWin::BluetoothDeviceWin( + const BluetoothTaskManagerWin::DeviceState& state) + : BluetoothDevice(), device_fingerprint_(ComputeDeviceFingerprint(state)) { + name_ = state.name; + address_ = state.address; + bluetooth_class_ = state.bluetooth_class; + connected_ = state.connected; + bonded_ = state.authenticated; + + for (ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>::const_iterator + iter = state.service_record_states.begin(); + iter != state.service_record_states.end(); + ++iter) { + uint8 sdp_bytes_buffer[kSdpBytesBufferSize]; + std::copy((*iter)->sdp_bytes.begin(), + (*iter)->sdp_bytes.end(), + sdp_bytes_buffer); + BluetoothServiceRecord* service_record = new BluetoothServiceRecordWin( + (*iter)->name, + (*iter)->address, + (*iter)->sdp_bytes.size(), + sdp_bytes_buffer); + service_record_list_.push_back(service_record); + service_uuids_.push_back(service_record->uuid()); + } } BluetoothDeviceWin::~BluetoothDeviceWin() { } +void BluetoothDeviceWin::SetVisible(bool visible) { + visible_ = visible; +} + bool BluetoothDeviceWin::IsPaired() const { - NOTIMPLEMENTED(); return false; } @@ -118,4 +156,27 @@ void BluetoothDeviceWin::ClearOutOfBandPairingData( NOTIMPLEMENTED(); } +// static +uint32 BluetoothDeviceWin::ComputeDeviceFingerprint( + const BluetoothTaskManagerWin::DeviceState& state) { + std::string device_string = base::StringPrintf("%s%s%u%s%s%s", + state.name.c_str(), + state.address.c_str(), + state.bluetooth_class, + state.visible ? "true" : "false", + state.connected ? "true" : "false", + state.authenticated ? "true" : "false"); + for (ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>::const_iterator + iter = state.service_record_states.begin(); + iter != state.service_record_states.end(); + ++iter) { + base::StringAppendF(&device_string, + "%s%s%d", + (*iter)->name.c_str(), + (*iter)->address.c_str(), + (*iter)->sdp_bytes.size()); + } + return base::Hash(device_string); +} + } // namespace device diff --git a/device/bluetooth/bluetooth_device_win.h b/device/bluetooth/bluetooth_device_win.h index 3040fac..12c3a3f 100644 --- a/device/bluetooth/bluetooth_device_win.h +++ b/device/bluetooth/bluetooth_device_win.h @@ -6,17 +6,24 @@ #define DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_WIN_H_ #include <string> +#include <vector> #include "base/basictypes.h" #include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/bluetooth_task_manager_win.h" namespace device { +class BluetoothAdapterWin; + class BluetoothDeviceWin : public BluetoothDevice { public: - BluetoothDeviceWin(); + BluetoothDeviceWin(const BluetoothTaskManagerWin::DeviceState& state); virtual ~BluetoothDeviceWin(); + void SetVisible(bool visible); + + // BluetoothDevice override virtual bool IsPaired() const OVERRIDE; virtual const ServiceList& GetServices() const OVERRIDE; virtual void GetServiceRecords( @@ -54,8 +61,23 @@ class BluetoothDeviceWin : public BluetoothDevice { const ErrorCallback& error_callback) OVERRIDE; private: + friend class BluetoothAdapterWin; + + // Computes the fingerprint that can be used to compare the devices. + static uint32 ComputeDeviceFingerprint( + const BluetoothTaskManagerWin::DeviceState& state); + + uint32 device_fingerprint() const { + return device_fingerprint_; + } + + // Used to compare the devices. + uint32 device_fingerprint_; + ServiceRecordList service_record_list_; // The services (identified by UUIDs) that this device provides. - std::vector<std::string> service_uuids_; + ServiceList service_uuids_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceWin); }; } // namespace device diff --git a/device/bluetooth/bluetooth_service_record_win.h b/device/bluetooth/bluetooth_service_record_win.h index d799f35..b9f0331 100644 --- a/device/bluetooth/bluetooth_service_record_win.h +++ b/device/bluetooth/bluetooth_service_record_win.h @@ -26,6 +26,8 @@ class BluetoothServiceRecordWin : public BluetoothServiceRecord { private: BTH_ADDR bth_addr_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothServiceRecordWin); }; } // namespace device diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc index ddb051e..b747f3b 100644 --- a/device/bluetooth/bluetooth_task_manager_win.cc +++ b/device/bluetooth/bluetooth_task_manager_win.cc @@ -4,10 +4,14 @@ #include "device/bluetooth/bluetooth_task_manager_win.h" +#include <winsock2.h> + #include <string> +#include "base/basictypes.h" #include "base/bind.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_vector.h" #include "base/message_loop.h" #include "base/sequenced_task_runner.h" #include "base/stringprintf.h" @@ -15,11 +19,16 @@ #include "base/threading/sequenced_worker_pool.h" #include "base/win/scoped_handle.h" #include "device/bluetooth/bluetooth_init_win.h" +#include "device/bluetooth/bluetooth_service_record_win.h" +#include "net/base/winsock_init.h" namespace { const int kNumThreadsInWorkerPool = 3; const char kBluetoothThreadName[] = "BluetoothPollingThreadWin"; +const int kMaxNumDeviceAddressChar = 127; +const int kServiceDiscoveryResultBufferSize = 5000; +const int kMaxDeviceDiscoveryTimeout = 48; // Populates bluetooth adapter state using adapter_handle. void GetAdapterState(HANDLE adapter_handle, @@ -46,8 +55,24 @@ void GetAdapterState(HANDLE adapter_handle, state->powered = powered; } +void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info, + device::BluetoothTaskManagerWin::DeviceState* state) { + state->name = base::SysWideToUTF8(device_info.szName); + state->address = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", + device_info.Address.rgBytes[5], + device_info.Address.rgBytes[4], + device_info.Address.rgBytes[3], + device_info.Address.rgBytes[2], + device_info.Address.rgBytes[1], + device_info.Address.rgBytes[0]); + state->bluetooth_class = device_info.ulClassofDevice; + state->visible = true; + state->connected = !!device_info.fConnected; + state->authenticated = !!device_info.fAuthenticated; } +} // namespace + namespace device { // static @@ -56,19 +81,7 @@ const int BluetoothTaskManagerWin::kPollIntervalMs = 500; BluetoothTaskManagerWin::BluetoothTaskManagerWin( scoped_refptr<base::SequencedTaskRunner> ui_task_runner) : ui_task_runner_(ui_task_runner), - worker_pool_(new base::SequencedWorkerPool(kNumThreadsInWorkerPool, - kBluetoothThreadName)), - bluetooth_task_runner_( - worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( - worker_pool_->GetSequenceToken(), - base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) { -} - -BluetoothTaskManagerWin::BluetoothTaskManagerWin( - scoped_refptr<base::SequencedTaskRunner> ui_task_runner, - scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) - : ui_task_runner_(ui_task_runner), - bluetooth_task_runner_(bluetooth_task_runner) { + discovering_(false) { } BluetoothTaskManagerWin::~BluetoothTaskManagerWin() { @@ -88,16 +101,26 @@ void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) { void BluetoothTaskManagerWin::Initialize() { DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + worker_pool_ = new base::SequencedWorkerPool(kNumThreadsInWorkerPool, + kBluetoothThreadName); + InitializeWithBluetoothTaskRunner( + worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( + worker_pool_->GetSequenceToken(), + base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)); +} + +void BluetoothTaskManagerWin::InitializeWithBluetoothTaskRunner( + scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + bluetooth_task_runner_ = bluetooth_task_runner; bluetooth_task_runner_->PostTask( FROM_HERE, - base::Bind(&BluetoothTaskManagerWin::StartPolling, - this)); + base::Bind(&BluetoothTaskManagerWin::StartPolling, this)); } void BluetoothTaskManagerWin::StartPolling() { DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); - // TODO(youngki): Handle this check where BluetoothAdapter is initialized. if (device::bluetooth_init_win::HasBluetoothStack()) { PollAdapter(); } else { @@ -115,7 +138,8 @@ void BluetoothTaskManagerWin::StartPolling() { void BluetoothTaskManagerWin::Shutdown() { DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); - worker_pool_->Shutdown(); + if (worker_pool_) + worker_pool_->Shutdown(); } void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask( @@ -132,41 +156,87 @@ void BluetoothTaskManagerWin::PostSetPoweredBluetoothTask( error_callback)); } +void BluetoothTaskManagerWin::PostStartDiscoveryTask() { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + bluetooth_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this)); +} + +void BluetoothTaskManagerWin::PostStopDiscoveryTask() { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + bluetooth_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this)); +} + void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) { DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, AdapterStateChanged(*state)); } +void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, + DiscoveryStarted(success)); +} + +void BluetoothTaskManagerWin::OnDiscoveryStopped() { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, + DiscoveryStopped()); +} + +void BluetoothTaskManagerWin::OnScanningChanged(bool scanning) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, + ScanningChanged(scanning)); +} + +void BluetoothTaskManagerWin::OnDevicesDiscovered( + const ScopedVector<DeviceState>* devices) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, + DevicesDiscovered(*devices)); +} + void BluetoothTaskManagerWin::PollAdapter() { DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); - const BLUETOOTH_FIND_RADIO_PARAMS adapter_param = - { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; - if (adapter_handle_) - adapter_handle_.Close(); - HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio( - &adapter_param, adapter_handle_.Receive()); + // Skips updating the adapter info if the adapter is in discovery mode. + if (!discovering_) { + const BLUETOOTH_FIND_RADIO_PARAMS adapter_param = + { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; + if (adapter_handle_) + adapter_handle_.Close(); + HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio( + &adapter_param, adapter_handle_.Receive()); + + if (handle) { + GetKnownDevices(); + BluetoothFindRadioClose(handle); + } + PostAdapterStateToUi(); + } - if (handle) - BluetoothFindRadioClose(handle); + // Re-poll. + bluetooth_task_runner_->PostDelayedTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::PollAdapter, + this), + base::TimeDelta::FromMilliseconds(kPollIntervalMs)); +} +void BluetoothTaskManagerWin::PostAdapterStateToUi() { + DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); AdapterState* state = new AdapterState(); GetAdapterState(adapter_handle_, state); - - // Notify the UI thread of the Bluetooth Adapter state. ui_task_runner_->PostTask( FROM_HERE, base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged, this, base::Owned(state))); - - // Re-poll. - bluetooth_task_runner_->PostDelayedTask( - FROM_HERE, - base::Bind(&BluetoothTaskManagerWin::PollAdapter, - this), - base::TimeDelta::FromMilliseconds(kPollIntervalMs)); } void BluetoothTaskManagerWin::SetPowered( @@ -182,16 +252,168 @@ void BluetoothTaskManagerWin::SetPowered( } if (success) { - AdapterState* state = new AdapterState(); - GetAdapterState(adapter_handle_, state); + PostAdapterStateToUi(); + ui_task_runner_->PostTask(FROM_HERE, callback); + } else { + ui_task_runner_->PostTask(FROM_HERE, error_callback); + } +} + +void BluetoothTaskManagerWin::StartDiscovery() { + DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); + ui_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStarted, + this, + !!adapter_handle_)); + if (!adapter_handle_) + return; + discovering_ = true; + + DiscoverDevices(1); +} + +void BluetoothTaskManagerWin::StopDiscovery() { + DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); + discovering_ = false; + ui_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); +} + +void BluetoothTaskManagerWin::DiscoverDevices(int timeout) { + DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); + if (!discovering_ || !adapter_handle_) { ui_task_runner_->PostTask( FROM_HERE, - base::Bind(&BluetoothTaskManagerWin::OnAdapterStateChanged, + base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); + return; + } + + ui_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::OnScanningChanged, this, true)); + + ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); + SearchDevices(timeout, false, device_list); + if (device_list->empty()) { + delete device_list; + } else { + ui_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::OnScanningChanged, this, false)); + DiscoverServices(device_list); + ui_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered, this, - base::Owned(state))); - ui_task_runner_->PostTask(FROM_HERE, callback); + base::Owned(device_list))); + } + + if (timeout < kMaxDeviceDiscoveryTimeout) { + bluetooth_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::DiscoverDevices, + this, + timeout + 1)); } else { - ui_task_runner_->PostTask(FROM_HERE, error_callback); + ui_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); + discovering_ = false; + } +} + +void BluetoothTaskManagerWin::GetKnownDevices() { + ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); + SearchDevices(1, true, device_list); + if (device_list->empty()) { + delete device_list; + return; + } + DiscoverServices(device_list); + ui_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered, + this, + base::Owned(device_list))); +} + +void BluetoothTaskManagerWin::SearchDevices( + int timeout, + bool search_cached_devices_only, + ScopedVector<DeviceState>* device_list) { + BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = { + sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), + 1, // return authenticated devices + 1, // return remembered devices + search_cached_devices_only ? 0 : 1, // return unknown devices + 1, // return connected devices + search_cached_devices_only ? 0 : 1, // issue a new inquiry + timeout, // timeout for the inquiry in increments of 1.28 seconds + adapter_handle_ + }; + + BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 }; + // Issues a device inquiry and waits for |timeout| * 1.28 seconds. + HBLUETOOTH_DEVICE_FIND handle = + BluetoothFindFirstDevice(&device_search_params, &device_info); + if (handle) { + do { + DeviceState* device_state = new DeviceState(); + GetDeviceState(device_info, device_state); + device_list->push_back(device_state); + } while (BluetoothFindNextDevice(handle, &device_info)); + + BluetoothFindDeviceClose(handle); + } +} + +void BluetoothTaskManagerWin::DiscoverServices( + ScopedVector<DeviceState>* device_list) { + DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); + net::EnsureWinsockInit(); + for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); + iter != device_list->end(); + ++iter) { + const std::string device_address = (*iter)->address; + ScopedVector<ServiceRecordState>* service_record_states = + &(*iter)->service_record_states; + WSAQUERYSET sdp_query; + ZeroMemory(&sdp_query, sizeof(sdp_query)); + sdp_query.dwSize = sizeof(sdp_query); + GUID protocol = L2CAP_PROTOCOL_UUID; + sdp_query.lpServiceClassId = &protocol; + sdp_query.dwNameSpace = NS_BTH; + wchar_t device_address_context[kMaxNumDeviceAddressChar]; + std::size_t length = + base::SysUTF8ToWide("(" + device_address + ")").copy( + device_address_context, kMaxNumDeviceAddressChar); + device_address_context[length] = NULL; + sdp_query.lpszContext = device_address_context; + HANDLE sdp_handle; + if (ERROR_SUCCESS != + WSALookupServiceBegin(&sdp_query, LUP_RETURN_ALL, &sdp_handle)) { + return; + } + char sdp_buffer[kServiceDiscoveryResultBufferSize]; + LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer); + DWORD sdp_buffer_size = sizeof(sdp_buffer); + while (ERROR_SUCCESS == WSALookupServiceNext(sdp_handle, + LUP_RETURN_ALL, + &sdp_buffer_size, + sdp_result_data)) { + ServiceRecordState* service_record_state = new ServiceRecordState(); + service_record_state->name = + base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName); + service_record_state->address = device_address; + for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) { + service_record_state->sdp_bytes.push_back( + sdp_result_data->lpBlob->pBlobData[i]); + } + service_record_states->push_back(service_record_state); + } + WSALookupServiceEnd(sdp_handle); } } diff --git a/device/bluetooth/bluetooth_task_manager_win.h b/device/bluetooth/bluetooth_task_manager_win.h index 1f2e1d6..9b8d690 100644 --- a/device/bluetooth/bluetooth_task_manager_win.h +++ b/device/bluetooth/bluetooth_task_manager_win.h @@ -6,14 +6,14 @@ #define DEVICE_BLUETOOTH_BLUETOOTH_TASK_MANAGER_WIN_H_ #include <string> +#include <vector> #include "base/memory/ref_counted.h" +#include "base/memory/scoped_vector.h" #include "base/observer_list.h" #include "base/win/scoped_handle.h" #include "device/bluetooth/bluetooth_adapter.h" -class MessageLoop; - namespace base { class SequencedTaskRunner; @@ -40,11 +40,31 @@ class BluetoothTaskManagerWin bool powered; }; + struct ServiceRecordState { + std::string name; + std::string address; + std::vector<uint8> sdp_bytes; + }; + + struct DeviceState { + std::string name; + std::string address; + uint32 bluetooth_class; + bool visible; + bool connected; + bool authenticated; + ScopedVector<ServiceRecordState> service_record_states; + }; + class Observer { public: virtual ~Observer() {} virtual void AdapterStateChanged(const AdapterState& state) {} + virtual void DiscoveryStarted(bool success) {} + virtual void DiscoveryStopped() {} + virtual void ScanningChanged(bool scanning) {} + virtual void DevicesDiscovered(const ScopedVector<DeviceState>& devices) {} }; BluetoothTaskManagerWin( @@ -54,12 +74,16 @@ class BluetoothTaskManagerWin void RemoveObserver(Observer* observer); void Initialize(); + void InitializeWithBluetoothTaskRunner( + scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner); void Shutdown(); void PostSetPoweredBluetoothTask( bool powered, const base::Closure& callback, const BluetoothAdapter::ErrorCallback& error_callback); + void PostStartDiscoveryTask(); + void PostStopDiscoveryTask(); private: friend class base::RefCountedThreadSafe<BluetoothTaskManagerWin>; @@ -67,30 +91,54 @@ class BluetoothTaskManagerWin static const int kPollIntervalMs; - // Constructor to pass |ui_task_runner_| and |bluetooth_task_runner_| for - // testing. - BluetoothTaskManagerWin( - scoped_refptr<base::SequencedTaskRunner> ui_task_runner, - scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner); - virtual ~BluetoothTaskManagerWin(); // Notify all Observers of updated AdapterState. Should only be called on the // UI thread. void OnAdapterStateChanged(const AdapterState* state); + void OnDiscoveryStarted(bool success); + void OnDiscoveryStopped(); + void OnScanningChanged(bool scanning); + void OnDevicesDiscovered(const ScopedVector<DeviceState>* devices); // Called on BluetoothTaskRunner. void StartPolling(); void PollAdapter(); + void PostAdapterStateToUi(); void SetPowered(bool powered, const base::Closure& callback, const BluetoothAdapter::ErrorCallback& error_callback); + // Starts discovery. Once the discovery starts, it issues a discovery inquiry + // with a short timeout, then issues more inquiries with greater timeout + // values. The discovery finishes when StopDiscovery() is called or timeout + // has reached its maximum value. + void StartDiscovery(); + void StopDiscovery(); + + // Issues a device inquiry that runs for |timeout| * 1.28 seconds. + // This posts itself again with |timeout| + 1 until |timeout| reaches the + // maximum value or stop discovery call is received. + void DiscoverDevices(int timeout); + + // Fetch already known device information. Similar to |StartDiscovery|, except + // this function does not issue a discovery inquiry. Instead it gets the + // device info cached in the adapter. + void GetKnownDevices(); + + // Sends a device search API call to the adapter. + void SearchDevices(int timeout, + bool search_cached_devices_only, + ScopedVector<DeviceState>* device_list); + + // Discover services for the devices in |device_list|. + void DiscoverServices(ScopedVector<DeviceState>* device_list); + // UI task runner reference. - const scoped_refptr<base::SequencedTaskRunner> ui_task_runner_; + scoped_refptr<base::SequencedTaskRunner> ui_task_runner_; - const scoped_refptr<base::SequencedWorkerPool> worker_pool_; - const scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner_; + scoped_refptr<base::SequencedWorkerPool> worker_pool_; + scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner_; // List of observers interested in event notifications. ObserverList<Observer> observers_; @@ -98,6 +146,9 @@ class BluetoothTaskManagerWin // Adapter handle owned by bluetooth task runner. base::win::ScopedHandle adapter_handle_; + // indicates whether the adapter is in discovery mode or not. + bool discovering_; + DISALLOW_COPY_AND_ASSIGN(BluetoothTaskManagerWin); }; diff --git a/device/bluetooth/bluetooth_task_manager_win_unittest.cc b/device/bluetooth/bluetooth_task_manager_win_unittest.cc index 99e7e2f..87a3ef5 100644 --- a/device/bluetooth/bluetooth_task_manager_win_unittest.cc +++ b/device/bluetooth/bluetooth_task_manager_win_unittest.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <deque> - #include "base/bind.h" #include "base/memory/ref_counted.h" #include "base/test/test_pending_task.h" @@ -16,23 +14,70 @@ namespace { class BluetoothTaskObserver : public device::BluetoothTaskManagerWin::Observer { public: - BluetoothTaskObserver() : num_updates_(0) { + BluetoothTaskObserver() { + Clear(); } virtual ~BluetoothTaskObserver() { } virtual void AdapterStateChanged( - const device::BluetoothTaskManagerWin::AdapterState& state) { - num_updates_++; + const device::BluetoothTaskManagerWin::AdapterState& state) OVERRIDE { + num_adapter_state_changed_++; + } + + virtual void DiscoveryStarted(bool success) OVERRIDE { + num_discovery_started_++; + } + + virtual void DiscoveryStopped() OVERRIDE { + num_discovery_stopped_++; + } + + virtual void ScanningChanged(bool scanning) OVERRIDE { + num_scanning_changed_++; + } + + virtual void DevicesDiscovered( + const ScopedVector<device::BluetoothTaskManagerWin::DeviceState>& + devices) OVERRIDE { + num_devices_discovered_++; + } + + void Clear() { + num_adapter_state_changed_ = 0; + num_discovery_started_ = 0; + num_discovery_stopped_ = 0; + num_scanning_changed_ = 0; + num_devices_discovered_ = 0; + } + + int num_adapter_state_changed() const { + return num_adapter_state_changed_; + } + + int num_discovery_started() const { + return num_discovery_started_; } - int num_updates() const { - return num_updates_; + int num_discovery_stopped() const { + return num_discovery_stopped_; + } + + int num_scanning_changed() const { + return num_scanning_changed_; + } + + int num_devices_discovered() const { + return num_devices_discovered_; } private: - int num_updates_; + int num_adapter_state_changed_; + int num_discovery_started_; + int num_discovery_stopped_; + int num_scanning_changed_; + int num_devices_discovered_; }; } // namespace @@ -44,9 +89,9 @@ class BluetoothTaskManagerWinTest : public testing::Test { BluetoothTaskManagerWinTest() : ui_task_runner_(new base::TestSimpleTaskRunner()), bluetooth_task_runner_(new base::TestSimpleTaskRunner()), - task_manager_(new BluetoothTaskManagerWin(ui_task_runner_, - bluetooth_task_runner_)), + task_manager_(new BluetoothTaskManagerWin(ui_task_runner_)), has_bluetooth_stack_(device::bluetooth_init_win::HasBluetoothStack()) { + task_manager_->InitializeWithBluetoothTaskRunner(bluetooth_task_runner_); } virtual void SetUp() { @@ -70,14 +115,10 @@ class BluetoothTaskManagerWinTest : public testing::Test { }; TEST_F(BluetoothTaskManagerWinTest, StartPolling) { - task_manager_->Initialize(); - const std::deque<base::TestPendingTask>& pending_tasks = - bluetooth_task_runner_->GetPendingTasks(); EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size()); } TEST_F(BluetoothTaskManagerWinTest, PollAdapterIfBluetoothStackIsAvailable) { - task_manager_->Initialize(); bluetooth_task_runner_->RunPendingTasks(); int num_expected_pending_tasks = has_bluetooth_stack_ ? 1 : 0; EXPECT_EQ(num_expected_pending_tasks, @@ -88,22 +129,21 @@ TEST_F(BluetoothTaskManagerWinTest, Polling) { if (!has_bluetooth_stack_) return; - task_manager_->Initialize(); - int expected_num_updates = 5; + int num_polls = 5; - for (int i = 0; i < expected_num_updates; i++) { + for (int i = 0; i < num_polls; i++) { bluetooth_task_runner_->RunPendingTasks(); } - EXPECT_EQ(expected_num_updates, ui_task_runner_->GetPendingTasks().size()); ui_task_runner_->RunPendingTasks(); - EXPECT_EQ(expected_num_updates, observer_.num_updates()); + EXPECT_EQ(num_polls, observer_.num_adapter_state_changed()); } TEST_F(BluetoothTaskManagerWinTest, SetPowered) { if (!has_bluetooth_stack_) return; + bluetooth_task_runner_->ClearPendingTasks(); base::Closure closure; task_manager_->PostSetPoweredBluetoothTask(true, closure, closure); @@ -112,4 +152,20 @@ TEST_F(BluetoothTaskManagerWinTest, SetPowered) { EXPECT_TRUE(ui_task_runner_->GetPendingTasks().size() >= 1); } -} // namespace device
\ No newline at end of file +TEST_F(BluetoothTaskManagerWinTest, Discovery) { + if (!has_bluetooth_stack_) + return; + + bluetooth_task_runner_->RunPendingTasks(); + bluetooth_task_runner_->ClearPendingTasks(); + task_manager_->PostStartDiscoveryTask(); + bluetooth_task_runner_->RunPendingTasks(); + ui_task_runner_->RunPendingTasks(); + EXPECT_EQ(1, observer_.num_discovery_started()); + task_manager_->PostStopDiscoveryTask(); + bluetooth_task_runner_->RunPendingTasks(); + ui_task_runner_->RunPendingTasks(); + EXPECT_EQ(1, observer_.num_discovery_stopped()); +} + +} // namespace device |