diff options
author | youngki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-16 00:28:17 +0000 |
---|---|---|
committer | youngki@chromium.org <youngki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-16 00:28:17 +0000 |
commit | 0216e79b17c2d45f596f374d34fde579d131cc46 (patch) | |
tree | c82284c61d196416febffc6f6d58939ea32a39c4 /device | |
parent | d39eefeb284e5ef5ec1012a2e27d97697678fc28 (diff) | |
download | chromium_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.cc | 10 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_win.cc | 116 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_win.h | 23 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_win_unittest.cc | 102 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_task_manager_win.cc | 182 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_task_manager_win.h | 98 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_task_manager_win_unittest.cc | 101 | ||||
-rw-r--r-- | device/device.gyp | 3 |
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', |