summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
authoryoungki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-16 00:28:17 +0000
committeryoungki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-16 00:28:17 +0000
commit0216e79b17c2d45f596f374d34fde579d131cc46 (patch)
treec82284c61d196416febffc6f6d58939ea32a39c4 /device
parentd39eefeb284e5ef5ec1012a2e27d97697678fc28 (diff)
downloadchromium_src-0216e79b17c2d45f596f374d34fde579d131cc46.zip
chromium_src-0216e79b17c2d45f596f374d34fde579d131cc46.tar.gz
chromium_src-0216e79b17c2d45f596f374d34fde579d131cc46.tar.bz2
Implemented BluetoothTaskManagerWin class.
BluetoothAdapterWin owns BluetoothTaskManagerWin and registers itself as an observer to BluetoothTaskManagerWin. The BluetoothTaskManagerWin polls the Bluetooth Windows API to get the up-to-date adapter status, and notifies BluetoothAdapterWin upon changes. BUG=135470 Review URL: https://chromiumcodereview.appspot.com/11411130 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@177024 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device')
-rw-r--r--device/bluetooth/bluetooth_adapter_factory.cc10
-rw-r--r--device/bluetooth/bluetooth_adapter_win.cc116
-rw-r--r--device/bluetooth/bluetooth_adapter_win.h23
-rw-r--r--device/bluetooth/bluetooth_adapter_win_unittest.cc102
-rw-r--r--device/bluetooth/bluetooth_task_manager_win.cc182
-rw-r--r--device/bluetooth/bluetooth_task_manager_win.h98
-rw-r--r--device/bluetooth/bluetooth_task_manager_win_unittest.cc101
-rw-r--r--device/device.gyp3
8 files changed, 445 insertions, 190 deletions
diff --git a/device/bluetooth/bluetooth_adapter_factory.cc b/device/bluetooth/bluetooth_adapter_factory.cc
index 2e8dac0..23bb07d3 100644
--- a/device/bluetooth/bluetooth_adapter_factory.cc
+++ b/device/bluetooth/bluetooth_adapter_factory.cc
@@ -11,6 +11,8 @@
#if defined(OS_CHROMEOS)
#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#elif defined(OS_WIN)
+#include "device/bluetooth/bluetooth_adapter_win.h"
#endif
namespace {
@@ -30,6 +32,8 @@ namespace device {
bool BluetoothAdapterFactory::IsBluetoothAdapterAvailable() {
#if defined(OS_CHROMEOS)
return true;
+#elif defined(OS_WIN)
+ return true;
#endif
return false;
}
@@ -43,6 +47,10 @@ void BluetoothAdapterFactory::RunCallbackOnAdapterReady(
new chromeos::BluetoothAdapterChromeOs;
new_adapter->TrackDefaultAdapter();
default_adapter.Get() = new_adapter->weak_ptr_factory_.GetWeakPtr();
+#elif defined(OS_WIN)
+ BluetoothAdapterWin* new_adapter = new BluetoothAdapterWin();
+ new_adapter->TrackDefaultAdapter();
+ default_adapter.Get() = new_adapter->weak_ptr_factory_.GetWeakPtr();
#endif
}
@@ -62,6 +70,8 @@ BluetoothAdapter* BluetoothAdapterFactory::Create(const std::string& address) {
new chromeos::BluetoothAdapterChromeOs;
adapter_chromeos->FindAdapter(address);
adapter = adapter_chromeos;
+#elif defined(OS_WIN)
+ adapter = new BluetoothAdapterWin();
#endif
return adapter;
}
diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc
index 0df985cb..1f0efce 100644
--- a/device/bluetooth/bluetooth_adapter_win.cc
+++ b/device/bluetooth/bluetooth_adapter_win.cc
@@ -6,65 +6,14 @@
#include "device/bluetooth/bluetooth_adapter_win.h"
-#include <BluetoothAPIs.h>
-#if defined(_WIN32_WINNT_WIN8) && _MSC_VER < 1700
-// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
-#undef FACILITY_VISUALCPP
-#endif
-#include <delayimp.h>
#include <string>
-#include "base/bind.h"
#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/stringprintf.h"
-#include "base/sys_string_conversions.h"
-#include "base/threading/thread_restrictions.h"
-
-#pragma comment(lib, "Bthprops.lib")
-#pragma comment(lib, "delayimp.lib")
-
-namespace {
-
-const BLUETOOTH_FIND_RADIO_PARAMS bluetooth_adapter_param =
- { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
-
-// A frame-based exception handler filter function for a handler for exceptions
-// generated by the Visual C++ delay loader helper function.
-int FilterVisualCPPExceptions(DWORD exception_code) {
- return HRESULT_FACILITY(exception_code) == FACILITY_VISUALCPP ?
- EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
-}
-
-// Returns true if the machine has a bluetooth stack available. The first call
-// to this function will involve file IO, so it should be done on an
-// appropriate thread. This function is not threadsafe.
-bool HasBluetoothStack() {
- static enum {
- HBS_UNKNOWN,
- HBS_YES,
- HBS_NO,
- } has_bluetooth_stack = HBS_UNKNOWN;
-
- if (has_bluetooth_stack == HBS_UNKNOWN) {
- base::ThreadRestrictions::AssertIOAllowed();
- HRESULT hr = E_FAIL;
- __try {
- hr = __HrLoadAllImportsForDll("bthprops.cpl");
- } __except(FilterVisualCPPExceptions(::GetExceptionCode())) {
- hr = E_FAIL;
- }
- has_bluetooth_stack = SUCCEEDED(hr) ? HBS_YES : HBS_NO;
- }
-
- return has_bluetooth_stack == HBS_YES;
-}
-
-} // namespace
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
namespace device {
-const int BluetoothAdapterWin::kPollIntervalMs = 500;
-
BluetoothAdapterWin::BluetoothAdapterWin()
: BluetoothAdapter(),
powered_(false),
@@ -72,6 +21,10 @@ BluetoothAdapterWin::BluetoothAdapterWin()
}
BluetoothAdapterWin::~BluetoothAdapterWin() {
+ if (task_manager_) {
+ task_manager_->RemoveObserver(this);
+ task_manager_->Shutdown();
+ }
}
void BluetoothAdapterWin::AddObserver(BluetoothAdapter::Observer* observer) {
@@ -131,54 +84,19 @@ void BluetoothAdapterWin::ReadLocalOutOfBandPairingData(
NOTIMPLEMENTED();
}
-void BluetoothAdapterWin::UpdateAdapterState() {
- // TODO(youngki): Move this check to the earliest point reasonable so that no
- // attempts are made to do any bluetooth processing if no BT stack is present.
- if (!HasBluetoothStack())
- return;
-
- HBLUETOOTH_RADIO_FIND bluetooth_adapter_handle = NULL;
- BLUETOOTH_RADIO_INFO bluetooth_adapter_info =
- { sizeof(BLUETOOTH_RADIO_INFO), 0 };
- HBLUETOOTH_RADIO_FIND bluetooth_handle = BluetoothFindFirstRadio(
- &bluetooth_adapter_param, &bluetooth_adapter_handle);
-
- if (bluetooth_adapter_handle) {
- if (ERROR_SUCCESS == BluetoothGetRadioInfo(bluetooth_adapter_handle,
- &bluetooth_adapter_info)) {
- name_ = base::SysWideToUTF8(bluetooth_adapter_info.szName);
- address_ = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
- bluetooth_adapter_info.address.rgBytes[5],
- bluetooth_adapter_info.address.rgBytes[4],
- bluetooth_adapter_info.address.rgBytes[3],
- bluetooth_adapter_info.address.rgBytes[2],
- bluetooth_adapter_info.address.rgBytes[1],
- bluetooth_adapter_info.address.rgBytes[0]);
- powered_ = BluetoothIsConnectable(bluetooth_adapter_handle) ||
- BluetoothIsDiscoverable(bluetooth_adapter_handle);
- } else {
- name_.clear();
- address_.clear();
- powered_ = false;
- }
- }
-
- if (bluetooth_handle)
- BluetoothFindRadioClose(bluetooth_handle);
+void BluetoothAdapterWin::AdapterStateChanged(
+ const BluetoothTaskManagerWin::AdapterState& state) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ name_ = state.name;
+ address_ = state.address;
+ powered_ = state.powered;
}
void BluetoothAdapterWin::TrackDefaultAdapter() {
- PollAdapterState();
-}
-
-void BluetoothAdapterWin::PollAdapterState() {
- UpdateAdapterState();
-
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&BluetoothAdapterWin::PollAdapterState,
- weak_ptr_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kPollIntervalMs));
+ task_manager_ =
+ new BluetoothTaskManagerWin(base::ThreadTaskRunnerHandle::Get());
+ task_manager_->AddObserver(this);
+ task_manager_->Initialize();
}
} // namespace device
diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h
index 0cad233..7519aee 100644
--- a/device/bluetooth/bluetooth_adapter_win.h
+++ b/device/bluetooth/bluetooth_adapter_win.h
@@ -7,8 +7,11 @@
#include <string>
+#include "base/memory/ref_counted.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 device {
@@ -16,7 +19,8 @@ class BluetoothAdapterFactory;
class BluetoothAdapterWinTest;
class BluetoothDevice;
-class BluetoothAdapterWin : public BluetoothAdapter {
+class BluetoothAdapterWin : public BluetoothAdapter,
+ public BluetoothTaskManagerWin::Observer {
public:
// BluetoothAdapter override
virtual void AddObserver(BluetoothAdapter::Observer* observer) OVERRIDE;
@@ -40,25 +44,26 @@ class BluetoothAdapterWin : public BluetoothAdapter {
const BluetoothOutOfBandPairingDataCallback& callback,
const ErrorCallback& error_callback) OVERRIDE;
+ // BluetoothTaskManagerWin::Observer override
+ virtual void AdapterStateChanged(
+ const BluetoothTaskManagerWin::AdapterState& state) OVERRIDE;
+
protected:
+ friend class BluetoothAdapterWinTest;
+
BluetoothAdapterWin();
virtual ~BluetoothAdapterWin();
- virtual void UpdateAdapterState();
-
private:
friend class BluetoothAdapterFactory;
- friend class BluetoothAdapterWinTest;
- // Obtains the default adapter info (the first bluetooth radio info found on
- // the system) and tracks future changes to it.
void TrackDefaultAdapter();
- void PollAdapterState();
+ bool powered_;
- static const int kPollIntervalMs;
+ scoped_refptr<BluetoothTaskManagerWin> task_manager_;
- bool powered_;
+ base::ThreadChecker thread_checker_;
// NOTE: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
diff --git a/device/bluetooth/bluetooth_adapter_win_unittest.cc b/device/bluetooth/bluetooth_adapter_win_unittest.cc
index e8fcb6f..1f68b28 100644
--- a/device/bluetooth/bluetooth_adapter_win_unittest.cc
+++ b/device/bluetooth/bluetooth_adapter_win_unittest.cc
@@ -4,109 +4,47 @@
#include <string>
+#include "base/bind.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop.h"
-#include "base/run_loop.h"
-#include "base/stringprintf.h"
-#include "base/time.h"
-#include "content/public/test/test_browser_thread.h"
+#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_win.h"
-#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_task_manager_win.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-const char* kAdapterAddress = "bluetooth adapter address";
+const char kAdapterAddress[] = "Bluetooth Adapter Address";
+const char kAdapterName[] = "Bluetooth Adapter Name";
} // namespace
namespace device {
-class FakeBluetoothAdapterWin : public BluetoothAdapterWin {
- public:
- FakeBluetoothAdapterWin() : BluetoothAdapterWin() {}
-
- virtual void UpdateAdapterState() {
- address_ = adapter_address_;
- }
-
- void SetAdapterAddressForTest(const std::string& adapter_address) {
- adapter_address_ = adapter_address;
- }
-
- private:
- virtual ~FakeBluetoothAdapterWin() {}
- std::string adapter_address_;
- DISALLOW_COPY_AND_ASSIGN(FakeBluetoothAdapterWin);
-};
-
class BluetoothAdapterWinTest : public testing::Test {
public:
BluetoothAdapterWinTest()
- : ui_thread_(content::BrowserThread::UI, &loop_),
- ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
- }
-
- virtual void SetUp() {
- adapter_ = new FakeBluetoothAdapterWin();
- adapter_->TrackDefaultAdapter();
- }
-
- void SetAdapterAddressForTest() {
- adapter_->SetAdapterAddressForTest(kAdapterAddress);
- }
-
- int GetPollIntervalMs() const {
- return BluetoothAdapterWin::kPollIntervalMs;
+ : adapter_(new BluetoothAdapterWin()),
+ adapter_win_(static_cast<BluetoothAdapterWin*>(adapter_.get())) {
}
protected:
- scoped_refptr<FakeBluetoothAdapterWin> adapter_;
-
- // Main message loop for the test.
- MessageLoopForUI loop_;
-
- // Main thread for the test.
- content::TestBrowserThread ui_thread_;
-
- // NOTE: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<BluetoothAdapterWinTest> weak_ptr_factory_;
+ scoped_refptr<BluetoothAdapter> adapter_;
+ BluetoothAdapterWin* adapter_win_;
};
-TEST_F(BluetoothAdapterWinTest, Polling) {
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(
- &BluetoothAdapterWinTest::SetAdapterAddressForTest,
- weak_ptr_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(GetPollIntervalMs() - 1));
- EXPECT_STRNE(kAdapterAddress, adapter_->address().c_str());
- base::RunLoop run_loop;
-
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(GetPollIntervalMs() + 1));
-
- run_loop.Run();
-
- EXPECT_STREQ(kAdapterAddress, adapter_->address().c_str());
+TEST_F(BluetoothAdapterWinTest, AdapterNotPresent) {
+ BluetoothTaskManagerWin::AdapterState state;
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_FALSE(adapter_win_->IsPresent());
}
-TEST_F(BluetoothAdapterWinTest, IsPresent) {
- EXPECT_FALSE(adapter_->IsPresent());
- SetAdapterAddressForTest();
- base::RunLoop run_loop;
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(GetPollIntervalMs()));
- run_loop.Run();
-
- EXPECT_TRUE(adapter_->IsPresent());
+TEST_F(BluetoothAdapterWinTest, AdapterPresent) {
+ BluetoothTaskManagerWin::AdapterState state;
+ state.address = kAdapterAddress;
+ state.name = kAdapterName;
+ adapter_win_->AdapterStateChanged(state);
+ EXPECT_TRUE(adapter_win_->IsPresent());
}
+
} // namespace device \ No newline at end of file
diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc
new file mode 100644
index 0000000..f9fc0ee
--- /dev/null
+++ b/device/bluetooth/bluetooth_task_manager_win.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_task_manager_win.h"
+
+#include <BluetoothAPIs.h>
+#if defined(_WIN32_WINNT_WIN8) && _MSC_VER < 1700
+// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
+#undef FACILITY_VISUALCPP
+#endif
+#include <delayimp.h>
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "base/stringprintf.h"
+#include "base/sys_string_conversions.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_handle.h"
+
+#pragma comment(lib, "Bthprops.lib")
+
+namespace {
+
+const int kNumThreadsInWorkerPool = 3;
+const char kBluetoothThreadName[] = "BluetoothPollingThreadWin";
+
+// A frame-based exception handler filter function for a handler for exceptions
+// generated by the Visual C++ delay loader helper function.
+int FilterVisualCPPExceptions(DWORD exception_code) {
+ return HRESULT_FACILITY(exception_code) == FACILITY_VISUALCPP ?
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+} // namespace
+
+// Populates bluetooth adapter state using adapter_handle.
+void GetAdapterState(HANDLE adapter_handle,
+ device::BluetoothTaskManagerWin::AdapterState* state) {
+ std::string name;
+ std::string address;
+ bool powered = false;
+ BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 };
+ if (adapter_handle &&
+ ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle,
+ &adapter_info)) {
+ name = base::SysWideToUTF8(adapter_info.szName);
+ address = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
+ adapter_info.address.rgBytes[5],
+ adapter_info.address.rgBytes[4],
+ adapter_info.address.rgBytes[3],
+ adapter_info.address.rgBytes[2],
+ adapter_info.address.rgBytes[1],
+ adapter_info.address.rgBytes[0]);
+ powered = !!BluetoothIsConnectable(adapter_handle);
+ }
+ state->name = name;
+ state->address = address;
+ state->powered = powered;
+}
+
+}
+
+namespace device {
+
+// static
+const int BluetoothTaskManagerWin::kPollIntervalMs = 500;
+
+// static
+bool BluetoothTaskManagerWin::HasBluetoothStack() {
+ static enum {
+ HBS_UNKNOWN,
+ HBS_YES,
+ HBS_NO,
+ } has_bluetooth_stack = HBS_UNKNOWN;
+
+ if (has_bluetooth_stack == HBS_UNKNOWN) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ HRESULT hr = E_FAIL;
+ __try {
+ hr = __HrLoadAllImportsForDll("bthprops.cpl");
+ } __except(FilterVisualCPPExceptions(::GetExceptionCode())) {
+ hr = E_FAIL;
+ }
+ has_bluetooth_stack = SUCCEEDED(hr) ? HBS_YES : HBS_NO;
+ }
+
+ return has_bluetooth_stack == HBS_YES;
+}
+
+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) {
+}
+
+BluetoothTaskManagerWin::~BluetoothTaskManagerWin() {
+}
+
+void BluetoothTaskManagerWin::AddObserver(Observer* observer) {
+ DCHECK(observer);
+ observers_.AddObserver(observer);
+}
+
+void BluetoothTaskManagerWin::RemoveObserver(Observer* observer) {
+ DCHECK(observer);
+ observers_.RemoveObserver(observer);
+}
+
+void BluetoothTaskManagerWin::Initialize() {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ bluetooth_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothTaskManagerWin::StartPolling,
+ this));
+}
+
+void BluetoothTaskManagerWin::StartPolling() {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+
+ // TODO(youngki): Handle this check where BluetoothAdapter is initialized.
+ if (HasBluetoothStack()) {
+ PollAdapter();
+ }
+}
+
+void BluetoothTaskManagerWin::Shutdown() {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ worker_pool_->Shutdown();
+}
+
+void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) {
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
+ FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_,
+ AdapterStateChanged(*state));
+}
+
+void BluetoothTaskManagerWin::PollAdapter() {
+ DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread());
+
+ base::win::ScopedHandle adapter_handle;
+ const BLUETOOTH_FIND_RADIO_PARAMS adapter_param =
+ { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
+ HBLUETOOTH_RADIO_FIND handle = BluetoothFindFirstRadio(
+ &adapter_param, adapter_handle.Receive());
+
+ if (handle)
+ BluetoothFindRadioClose(handle);
+
+ 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));
+}
+
+} // namespace device \ No newline at end of file
diff --git a/device/bluetooth/bluetooth_task_manager_win.h b/device/bluetooth/bluetooth_task_manager_win.h
new file mode 100644
index 0000000..11b5a9c
--- /dev/null
+++ b/device/bluetooth/bluetooth_task_manager_win.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_TASK_MANAGER_WIN_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_TASK_MANAGER_WIN_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+
+class MessageLoop;
+
+namespace base {
+
+class SequencedTaskRunner;
+class SequencedWorkerPool;
+
+} // namespace base
+
+namespace device {
+
+// Manages the blocking Bluetooth tasks using |SequencedWorkerPool|. It runs
+// bluetooth tasks using |SequencedWorkerPool| and informs its observers of
+// bluetooth adapter state changes and any other bluetooth device inquiry
+// result.
+//
+// It delegates the blocking Windows API calls to |bluetooth_task_runner_|'s
+// message loop, and receives responses via methods like OnAdapterStateChanged
+// posted to UI thread.
+class BluetoothTaskManagerWin
+ : public base::RefCountedThreadSafe<BluetoothTaskManagerWin> {
+ public:
+ struct AdapterState {
+ std::string name;
+ std::string address;
+ bool powered;
+ };
+
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ virtual void AdapterStateChanged(const AdapterState& state) {}
+ };
+
+ BluetoothTaskManagerWin(
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ void Initialize();
+ void Shutdown();
+
+ private:
+ friend class base::RefCountedThreadSafe<BluetoothTaskManagerWin>;
+ friend class BluetoothTaskManagerWinTest;
+
+ // Returns true if the machine has a bluetooth stack available. The first call
+ // to this function will involve file IO, so it should be done on an
+ // appropriate thread. This function is not threadsafe.
+ static bool HasBluetoothStack();
+
+ 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);
+
+ // Called on BluetoothTaskRunner.
+ void StartPolling();
+ void PollAdapter();
+
+ // UI task runner reference.
+ const scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+
+ const scoped_refptr<base::SequencedWorkerPool> worker_pool_;
+ const scoped_refptr<base::SequencedTaskRunner> bluetooth_task_runner_;
+
+ // List of observers interested in event notifications.
+ ObserverList<Observer> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothTaskManagerWin);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_TASK_MANAGER_WIN_H_ \ No newline at end of file
diff --git a/device/bluetooth/bluetooth_task_manager_win_unittest.cc b/device/bluetooth/bluetooth_task_manager_win_unittest.cc
new file mode 100644
index 0000000..b4721ca
--- /dev/null
+++ b/device/bluetooth/bluetooth_task_manager_win_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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"
+#include "base/test/test_simple_task_runner.h"
+#include "device/bluetooth/bluetooth_task_manager_win.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class BluetoothTaskObserver : public device::BluetoothTaskManagerWin::Observer {
+ public:
+ BluetoothTaskObserver() : num_updates_(0) {
+ }
+
+ virtual ~BluetoothTaskObserver() {
+ }
+
+ virtual void AdapterStateChanged(
+ const device::BluetoothTaskManagerWin::AdapterState& state) {
+ num_updates_++;
+ }
+
+ int num_updates() const {
+ return num_updates_;
+ }
+
+ private:
+ int num_updates_;
+};
+
+} // namespace
+
+namespace device {
+
+class BluetoothTaskManagerWinTest : public testing::Test {
+ public:
+ BluetoothTaskManagerWinTest()
+ : ui_task_runner_(new base::TestSimpleTaskRunner()),
+ bluetooth_task_runner_(new base::TestSimpleTaskRunner()),
+ task_manager_(new BluetoothTaskManagerWin(ui_task_runner_,
+ bluetooth_task_runner_)),
+ has_bluetooth_stack_(BluetoothTaskManagerWin::HasBluetoothStack()) {
+ }
+
+ virtual void SetUp() {
+ task_manager_->AddObserver(&observer_);
+ task_manager_->Initialize();
+ }
+
+ virtual void TearDown() {
+ task_manager_->RemoveObserver(&observer_);
+ }
+
+ int GetPollingIntervalMs() const {
+ return BluetoothTaskManagerWin::kPollIntervalMs;
+ }
+
+ protected:
+ scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_;
+ scoped_refptr<base::TestSimpleTaskRunner> bluetooth_task_runner_;
+ scoped_refptr<BluetoothTaskManagerWin> task_manager_;
+ BluetoothTaskObserver observer_;
+ const bool has_bluetooth_stack_;
+};
+
+TEST_F(BluetoothTaskManagerWinTest, StartPolling) {
+ const std::deque<base::TestPendingTask>& pending_tasks =
+ bluetooth_task_runner_->GetPendingTasks();
+ EXPECT_EQ(1, bluetooth_task_runner_->GetPendingTasks().size());
+}
+
+TEST_F(BluetoothTaskManagerWinTest, PollAdapterIfBluetoothStackIsAvailable) {
+ bluetooth_task_runner_->RunPendingTasks();
+ int num_expected_pending_tasks = has_bluetooth_stack_ ? 1 : 0;
+ EXPECT_EQ(num_expected_pending_tasks,
+ bluetooth_task_runner_->GetPendingTasks().size());
+}
+
+TEST_F(BluetoothTaskManagerWinTest, Polling) {
+ if (!has_bluetooth_stack_) {
+ return;
+ }
+
+ int expected_num_updates = 5;
+
+ for (int i = 0; i < expected_num_updates; 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());
+}
+
+} // namespace device \ No newline at end of file
diff --git a/device/device.gyp b/device/device.gyp
index c8e6a50..0f06eea 100644
--- a/device/device.gyp
+++ b/device/device.gyp
@@ -38,6 +38,8 @@
'bluetooth/bluetooth_socket_chromeos.h',
'bluetooth/bluetooth_socket_win.cc',
'bluetooth/bluetooth_socket_win.h',
+ 'bluetooth/bluetooth_task_manager_win.cc',
+ 'bluetooth/bluetooth_task_manager_win.h',
'bluetooth/bluetooth_utils.cc',
'bluetooth/bluetooth_utils.h',
],
@@ -134,6 +136,7 @@
'bluetooth/bluetooth_adapter_devices_chromeos_unittest.cc',
'bluetooth/bluetooth_adapter_win_unittest.cc',
'bluetooth/bluetooth_service_record_unittest.cc',
+ 'bluetooth/bluetooth_task_manager_win_unittest.cc',
'bluetooth/bluetooth_utils_unittest.cc',
'test/device_test_suite.cc',
'test/device_test_suite.h',