summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryoungki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-21 22:27:05 +0000
committeryoungki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-21 22:27:05 +0000
commitd7ba4375ff5397e48cace373c094de118228c6eb (patch)
tree819360053382a21a7f58f96123cc72ffd6d99272
parent71b05e336fad0c76397a041bcb681fb84c6decb2 (diff)
downloadchromium_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.cc4
-rw-r--r--chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc74
-rw-r--r--chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc9
-rw-r--r--device/bluetooth/bluetooth_adapter_win.cc189
-rw-r--r--device/bluetooth/bluetooth_adapter_win.h47
-rw-r--r--device/bluetooth/bluetooth_adapter_win_unittest.cc467
-rw-r--r--device/bluetooth/bluetooth_device.h3
-rw-r--r--device/bluetooth/bluetooth_device_win.cc65
-rw-r--r--device/bluetooth/bluetooth_device_win.h26
-rw-r--r--device/bluetooth/bluetooth_service_record_win.h2
-rw-r--r--device/bluetooth/bluetooth_task_manager_win.cc302
-rw-r--r--device/bluetooth/bluetooth_task_manager_win.h73
-rw-r--r--device/bluetooth/bluetooth_task_manager_win_unittest.cc96
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