summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorallanwoj@chromium.org <allanwoj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-17 12:21:22 +0000
committerallanwoj@chromium.org <allanwoj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-17 12:21:22 +0000
commitf9f23a78dc32653b41b716110d3cc7e6d0363607 (patch)
tree7746cc6ab899dd80512bee312bf1ef9b814a4a09
parentc61a6b6d9e4315174806366425fece0da631cc7c (diff)
downloadchromium_src-f9f23a78dc32653b41b716110d3cc7e6d0363607.zip
chromium_src-f9f23a78dc32653b41b716110d3cc7e6d0363607.tar.gz
chromium_src-f9f23a78dc32653b41b716110d3cc7e6d0363607.tar.bz2
TBR: I didn't upload the six files that I added last time round see here http://src.chromium.org/viewvc/chrome?view=rev&revision=56332
BUG=45535 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56334 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/geolocation/win7_location_api_unittest_win.cc335
-rw-r--r--chrome/browser/geolocation/win7_location_api_win.cc152
-rw-r--r--chrome/browser/geolocation/win7_location_api_win.h60
-rw-r--r--chrome/browser/geolocation/win7_location_provider_unittest_win.cc138
-rw-r--r--chrome/browser/geolocation/win7_location_provider_win.cc106
-rw-r--r--chrome/browser/geolocation/win7_location_provider_win.h46
6 files changed, 837 insertions, 0 deletions
diff --git a/chrome/browser/geolocation/win7_location_api_unittest_win.cc b/chrome/browser/geolocation/win7_location_api_unittest_win.cc
new file mode 100644
index 0000000..b76e8dd
--- /dev/null
+++ b/chrome/browser/geolocation/win7_location_api_unittest_win.cc
@@ -0,0 +1,335 @@
+// Copyright (c) 2010 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 <algorithm>
+#include <cmath>
+#include <Objbase.h>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "base/win_util.h"
+#include "chrome/common/geoposition.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/geolocation/win7_location_api_win.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::DoDefault;
+using testing::Invoke;
+using testing::Return;
+
+class MockLatLongReport : public ILatLongReport {
+public:
+ MockLatLongReport() : ref_count_(1) {
+ ON_CALL(*this, GetAltitude(_))
+ .WillByDefault(Invoke(this, &MockLatLongReport::GetAltitudeValid));
+ ON_CALL(*this, GetAltitudeError(_))
+ .WillByDefault(Invoke(this,
+ &MockLatLongReport::GetAltitudeErrorValid));
+ ON_CALL(*this, GetErrorRadius(_))
+ .WillByDefault(Invoke(this, &MockLatLongReport::GetErrorRadiusValid));
+ ON_CALL(*this, GetLatitude(_))
+ .WillByDefault(Invoke(this, &MockLatLongReport::GetLatitudeValid));
+ ON_CALL(*this, GetLongitude(_))
+ .WillByDefault(Invoke(this, &MockLatLongReport::GetLongitudeValid));
+ ON_CALL(*this, GetValue(_,_))
+ .WillByDefault(Invoke(this, &MockLatLongReport::GetValueValid));
+ ON_CALL(*this, Release())
+ .WillByDefault(Invoke(this, &MockLatLongReport::ReleaseInternal));
+ ON_CALL(*this, AddRef())
+ .WillByDefault(Invoke(this, &MockLatLongReport::AddRefInternal));
+ }
+
+ // ILatLongReport
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetAltitude,
+ HRESULT(DOUBLE*));
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetAltitudeError,
+ HRESULT(DOUBLE*));
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetErrorRadius,
+ HRESULT(DOUBLE*));
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetLatitude,
+ HRESULT(DOUBLE*));
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetLongitude,
+ HRESULT(DOUBLE*));
+ // ILocationReport
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetSensorID,
+ HRESULT(SENSOR_ID*));
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetTimestamp,
+ HRESULT(SYSTEMTIME*));
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetValue,
+ HRESULT(REFPROPERTYKEY, PROPVARIANT*));
+ // IUnknown
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ QueryInterface,
+ HRESULT(REFIID, void**));
+ MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ AddRef,
+ ULONG());
+ MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ Release,
+ ULONG());
+
+ HRESULT GetAltitudeValid(DOUBLE* altitude) {
+ *altitude = 20.5;
+ return S_OK;
+ }
+ HRESULT GetAltitudeErrorValid(DOUBLE* altitude_error) {
+ *altitude_error = 10.0;
+ return S_OK;
+ }
+ HRESULT GetErrorRadiusValid(DOUBLE* error) {
+ *error = 5.0;
+ return S_OK;
+ }
+ HRESULT GetLatitudeValid(DOUBLE* latitude) {
+ *latitude = 51.0;
+ return S_OK;
+ }
+ HRESULT GetLongitudeValid(DOUBLE* longitude) {
+ *longitude = -0.1;
+ return S_OK;
+ }
+ HRESULT GetValueValid(REFPROPERTYKEY prop_key, PROPVARIANT* prop) {
+ prop->dblVal = 10.0;
+ return S_OK;
+ }
+
+ private:
+ ~MockLatLongReport() {}
+
+ ULONG AddRefInternal() {
+ return InterlockedIncrement(&ref_count_);
+ }
+ ULONG ReleaseInternal() {
+ LONG new_ref_count = InterlockedDecrement(&ref_count_);
+ if (0 == new_ref_count)
+ delete this;
+ return new_ref_count;
+ }
+
+ LONG ref_count_;
+};
+
+class MockReport : public ILocationReport {
+ public:
+ MockReport() : ref_count_(1) {
+ mock_lat_long_report_ =
+ new MockLatLongReport();
+ ON_CALL(*this, QueryInterface(_, _))
+ .WillByDefault(Invoke(this, &MockReport::QueryInterfaceValid));
+ ON_CALL(*this, Release())
+ .WillByDefault(Invoke(this, &MockReport::ReleaseInternal));
+ ON_CALL(*this, AddRef())
+ .WillByDefault(Invoke(this, &MockReport::AddRefInternal));
+ }
+
+ // ILocationReport
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetSensorID,
+ HRESULT(SENSOR_ID*));
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetTimestamp,
+ HRESULT(SYSTEMTIME*));
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetValue,
+ HRESULT(REFPROPERTYKEY, PROPVARIANT*));
+ // IUnknown
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ QueryInterface,
+ HRESULT(REFIID, void**));
+ MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ AddRef,
+ ULONG());
+ MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ Release,
+ ULONG());
+
+ MockLatLongReport* mock_lat_long_report_;
+
+private:
+ ~MockReport() {
+ mock_lat_long_report_->Release();
+ }
+
+ ULONG AddRefInternal() {
+ return InterlockedIncrement(&ref_count_);
+ }
+ ULONG ReleaseInternal() {
+ LONG new_ref_count = InterlockedDecrement(&ref_count_);
+ if (0 == new_ref_count)
+ delete this;
+ return new_ref_count;
+ }
+ HRESULT QueryInterfaceValid(REFIID id, void** report) {
+ EXPECT_TRUE(id == IID_ILatLongReport);
+ *report = reinterpret_cast<ILatLongReport*>(mock_lat_long_report_);
+ mock_lat_long_report_->AddRef();
+ return S_OK;
+ }
+
+ LONG ref_count_;
+};
+
+class MockLocation : public ILocation {
+ public:
+ MockLocation() : ref_count_(1) {
+ mock_report_ = new MockReport();
+ ON_CALL(*this, SetDesiredAccuracy(_, _))
+ .WillByDefault(Return(S_OK));
+ ON_CALL(*this, GetReport(_, _))
+ .WillByDefault(Invoke(this, &MockLocation::GetReportValid));
+ ON_CALL(*this, RequestPermissions(_, _, _, _))
+ .WillByDefault(Return(S_OK));
+ ON_CALL(*this, AddRef())
+ .WillByDefault(Invoke(this, &MockLocation::AddRefInternal));
+ ON_CALL(*this, Release())
+ .WillByDefault(Invoke(this, &MockLocation::ReleaseInternal));
+ }
+
+ // ILocation
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetDesiredAccuracy,
+ HRESULT(REFIID, LOCATION_DESIRED_ACCURACY*));
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetReport,
+ HRESULT(REFIID, ILocationReport**));
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetReportInterval,
+ HRESULT(REFIID, DWORD*));
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ GetReportStatus,
+ HRESULT(REFIID, LOCATION_REPORT_STATUS*));
+ MOCK_METHOD4_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ RequestPermissions,
+ HRESULT(HWND, IID*, ULONG, BOOL));
+ MOCK_METHOD3_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ RegisterForReport,
+ HRESULT(ILocationEvents*, REFIID, DWORD));
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ SetDesiredAccuracy,
+ HRESULT(REFIID, LOCATION_DESIRED_ACCURACY));
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ SetReportInterval,
+ HRESULT(REFIID, DWORD));
+ MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ UnregisterForReport,
+ HRESULT(REFIID));
+ // IUnknown
+ MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ QueryInterface,
+ HRESULT(REFIID, void**));
+ MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ AddRef,
+ ULONG());
+ MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE,
+ Release,
+ ULONG());
+
+ MockReport* mock_report_;
+
+ private:
+ ~MockLocation() {
+ mock_report_->Release();
+ }
+
+ HRESULT GetReportValid(REFIID report_type,
+ ILocationReport** location_report) {
+ *location_report = reinterpret_cast<ILocationReport*>(mock_report_);
+ mock_report_->AddRef();
+ return S_OK;
+ }
+ ULONG AddRefInternal() {
+ return InterlockedIncrement(&ref_count_);
+ }
+ ULONG ReleaseInternal() {
+ LONG new_ref_count = InterlockedDecrement(&ref_count_);
+ if (0 == new_ref_count)
+ delete this;
+ return new_ref_count;
+ }
+
+ LONG ref_count_;
+};
+
+
+HRESULT __stdcall MockPropVariantToDoubleFunction(REFPROPVARIANT propvarIn,
+ DOUBLE *pdblRet) {
+ CHECK_EQ(10.0, propvarIn.dblVal);
+ *pdblRet = 10.0;
+ return S_OK;
+}
+
+// TODO(allanwoj): Either make mock classes into NiceMock classes
+// or check every mock method call.
+class GeolocationApiWin7Tests : public testing::Test {
+ public:
+ GeolocationApiWin7Tests() {
+ }
+ virtual void SetUp() {
+ api_.reset(CreateMock());
+ report_ = locator_->mock_report_;
+ lat_long_report_ = report_->mock_lat_long_report_;
+ }
+ virtual void TearDown() {
+ locator_->Release();
+ api_.reset();
+ }
+ ~GeolocationApiWin7Tests(){
+ }
+ protected:
+ Win7LocationApi* CreateMock() {
+ MockLocation* locator = new MockLocation();
+ locator_ = locator;
+ return new Win7LocationApi(NULL,
+ &MockPropVariantToDoubleFunction,
+ locator);
+ }
+
+ scoped_ptr<Win7LocationApi> api_;
+ MockLatLongReport* lat_long_report_;
+ MockLocation* locator_;
+ MockReport* report_;
+};
+
+TEST_F(GeolocationApiWin7Tests, PermissionDenied) {
+ EXPECT_CALL(*locator_, GetReport(_, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(E_ACCESSDENIED));
+ Geoposition position;
+ api_->GetPosition(&position);
+ EXPECT_EQ(Geoposition::ERROR_CODE_PERMISSION_DENIED,
+ position.error_code);
+}
+
+TEST_F(GeolocationApiWin7Tests, GetValidPosition) {
+ EXPECT_CALL(*locator_, GetReport(_, _))
+ .Times(AtLeast(1));
+ Geoposition position;
+ api_->GetPosition(&position);
+ EXPECT_TRUE(position.IsValidFix());
+}
+
+TEST_F(GeolocationApiWin7Tests, GetInvalidPosition) {
+ EXPECT_CALL(*lat_long_report_, GetLatitude(_))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(HRESULT_FROM_WIN32(ERROR_NO_DATA)));
+ EXPECT_CALL(*locator_, GetReport(_, _))
+ .Times(AtLeast(1));
+ Geoposition position;
+ api_->GetPosition(&position);
+ EXPECT_FALSE(position.IsValidFix());
+}
diff --git a/chrome/browser/geolocation/win7_location_api_win.cc b/chrome/browser/geolocation/win7_location_api_win.cc
new file mode 100644
index 0000000..18bda1b
--- /dev/null
+++ b/chrome/browser/geolocation/win7_location_api_win.cc
@@ -0,0 +1,152 @@
+// Copyright (c) 2010 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 "chrome/browser/geolocation/win7_location_api_win.h"
+
+#include "base/base_paths_win.h"
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/geoposition.h"
+
+namespace {
+const double kKnotsToMetresPerSecondConversionFactor = 0.5144;
+
+void ConvertKnotsToMetresPerSecond(double* knots) {
+ *knots *= kKnotsToMetresPerSecondConversionFactor;
+}
+
+HINSTANCE LoadWin7Library(const string16& lib_name) {
+ FilePath sys_dir;
+ PathService::Get(base::DIR_SYSTEM, &sys_dir);
+ return LoadLibrary(sys_dir.Append(lib_name).value().c_str());
+}
+}
+
+Win7LocationApi::Win7LocationApi(
+ HINSTANCE prop_library,
+ PropVariantToDoubleFunction PropVariantToDouble_function,
+ ILocation* locator)
+ : prop_lib_(prop_library),
+ PropVariantToDouble_function_(PropVariantToDouble_function),
+ locator_(locator) {
+}
+
+Win7LocationApi::~Win7LocationApi() {
+ if (prop_lib_ != NULL)
+ FreeLibrary(prop_lib_);
+}
+
+Win7LocationApi* Win7LocationApi::Create() {
+ if (!CommandLine::ForCurrentProcess()
+ ->HasSwitch(switches::kEnableWin7Location))
+ return NULL;
+ // Load probsys.dll
+ string16 lib_needed = L"propsys.dll";
+ HINSTANCE prop_lib = LoadWin7Library(lib_needed);
+ if (!prop_lib)
+ return NULL;
+ // Get pointer to function.
+ PropVariantToDoubleFunction PropVariantToDouble_function;
+ PropVariantToDouble_function =
+ reinterpret_cast<PropVariantToDoubleFunction>(
+ GetProcAddress(prop_lib, "PropVariantToDouble"));
+ if (!PropVariantToDouble_function) {
+ FreeLibrary(prop_lib);
+ return NULL;
+ }
+ // Create the ILocation object that receives location reports.
+ HRESULT result_type;
+ CComPtr<ILocation> locator;
+ result_type = CoCreateInstance(
+ CLSID_Location, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&locator));
+ if (!SUCCEEDED(result_type)) {
+ FreeLibrary(prop_lib);
+ return NULL;
+ }
+ IID reports_needed[] = { IID_ILatLongReport };
+ result_type = locator->RequestPermissions(NULL, reports_needed, 1, TRUE);
+ return new Win7LocationApi(prop_lib,
+ PropVariantToDouble_function,
+ locator);
+}
+
+void Win7LocationApi::GetPosition(Geoposition* position) {
+ DCHECK(position);
+ position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ if (!locator_)
+ return;
+ // Try to get a position fix
+ if (!GetPositionIfFixed(position))
+ return;
+ position->error_code = Geoposition::ERROR_CODE_NONE;
+ if (!position->IsValidFix()) {
+ // GetPositionIfFixed returned true, yet we've not got a valid fix.
+ // This shouldn't happen; something went wrong in the conversion.
+ NOTREACHED() << "Invalid position from GetPositionIfFixed: lat,long "
+ << position->latitude << "," << position->longitude
+ << " accuracy " << position->accuracy << " time "
+ << position->timestamp.ToDoubleT();
+ position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ position->error_message = "Bad fix from Win7 provider";
+ }
+}
+
+bool Win7LocationApi::GetPositionIfFixed(Geoposition* position) {
+ HRESULT result_type;
+ CComPtr<ILocationReport> location_report;
+ CComPtr<ILatLongReport> lat_long_report;
+ result_type = locator_->GetReport(IID_ILatLongReport, &location_report);
+ // Checks to see if location access is allowed.
+ if (result_type == E_ACCESSDENIED)
+ position->error_code = Geoposition::ERROR_CODE_PERMISSION_DENIED;
+ // Checks for any other errors while requesting a location report.
+ if(!SUCCEEDED(result_type))
+ return false;
+ result_type = location_report->QueryInterface(&lat_long_report);
+ if(!SUCCEEDED(result_type))
+ return false;
+ result_type = lat_long_report->GetLatitude(&position->latitude);
+ if(!SUCCEEDED(result_type))
+ return false;
+ result_type = lat_long_report->GetLongitude(&position->longitude);
+ if(!SUCCEEDED(result_type))
+ return false;
+ result_type = lat_long_report->GetErrorRadius(&position->accuracy);
+ if (!SUCCEEDED(result_type) || position->accuracy <= 0)
+ return false;
+ double temp_dbl;
+ result_type = lat_long_report->GetAltitude(&temp_dbl);
+ if (SUCCEEDED(result_type))
+ position->altitude = temp_dbl;
+ result_type = lat_long_report->GetAltitudeError(&temp_dbl);
+ if (SUCCEEDED(result_type))
+ position->altitude_accuracy = temp_dbl;
+ PROPVARIANT heading;
+ PropVariantInit(&heading);
+ result_type = lat_long_report->GetValue(
+ SENSOR_DATA_TYPE_TRUE_HEADING_DEGREES, &heading);
+ if (SUCCEEDED(result_type))
+ PropVariantToDouble_function_(heading, &position->heading);
+ PROPVARIANT speed;
+ PropVariantInit(&speed);
+ result_type = lat_long_report->GetValue(
+ SENSOR_DATA_TYPE_SPEED_KNOTS, &speed);
+ if (SUCCEEDED(result_type)) {
+ PropVariantToDouble_function_(speed, &position->speed);
+ ConvertKnotsToMetresPerSecond(&position->speed);
+ }
+ position->timestamp = base::Time::Now();
+ return true;
+}
+
+bool Win7LocationApi::SetHighAccuracy(bool acc) {
+ HRESULT result_type;
+ result_type = locator_->SetDesiredAccuracy(IID_ILatLongReport,
+ acc ? LOCATION_DESIRED_ACCURACY_HIGH :
+ LOCATION_DESIRED_ACCURACY_DEFAULT);
+ return SUCCEEDED(result_type);
+}
diff --git a/chrome/browser/geolocation/win7_location_api_win.h b/chrome/browser/geolocation/win7_location_api_win.h
new file mode 100644
index 0000000..bbbd30e
--- /dev/null
+++ b/chrome/browser/geolocation/win7_location_api_win.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2010 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 CHROME_BROWSER_GEOLOCATION_WIN7_LOCATION_API_WIN_H_
+#define CHROME_BROWSER_GEOLOCATION_WIN7_LOCATION_API_WIN_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <locationapi.h>
+#include <sensors.h>
+#include <vector>
+#include <Windows.h>
+
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "base/win_util.h"
+
+struct Geoposition;
+
+// PropVariantToDouble
+typedef HRESULT (WINAPI* PropVariantToDoubleFunction)
+ (REFPROPVARIANT propvarIn, DOUBLE *pdblRet);
+
+class Win7LocationApi {
+ public:
+ // Public for testing. See Create() below for normal usage.
+ Win7LocationApi(HINSTANCE prop_library,
+ PropVariantToDoubleFunction PropVariantToDouble_function,
+ ILocation* locator);
+ virtual ~Win7LocationApi();
+
+ // Attempts to load propsys.dll, initialise |location_| and requests the user
+ // for access to location information. Creates and returns ownership of an
+ // instance of Win7LocationApi if all succeed.
+ static Win7LocationApi* Create();
+ // Gives the best available position.
+ // Returns false if no valid position is available.
+ virtual void GetPosition(Geoposition* position);
+ // Changes the "accuracy" needed. Affects power levels of devices.
+ virtual bool SetHighAccuracy(bool acc);
+
+ private:
+ // Provides the best position fix if one is available.
+ // Does this by requesting a location report and querying it to obtain
+ // location information.
+ virtual bool GetPositionIfFixed(Geoposition* position);
+
+ // ILocation object that lets us communicate with the Location and
+ // Sensors platform.
+ CComPtr<ILocation> locator_;
+ // Holds the opened propsys.dll library that is passed on construction.
+ // This class is responsible for closing it.
+ HINSTANCE prop_lib_;
+ PropVariantToDoubleFunction PropVariantToDouble_function_;
+
+ DISALLOW_COPY_AND_ASSIGN(Win7LocationApi);
+};
+
+#endif // CHROME_BROWSER_GEOLOCATION_WIN7_LOCATION_API_WIN_H_
diff --git a/chrome/browser/geolocation/win7_location_provider_unittest_win.cc b/chrome/browser/geolocation/win7_location_provider_unittest_win.cc
new file mode 100644
index 0000000..2b5c3c3
--- /dev/null
+++ b/chrome/browser/geolocation/win7_location_provider_unittest_win.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2010 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 "chrome/browser/chrome_thread.h"
+#include "chrome/browser/geolocation/win7_location_provider_win.h"
+#include "chrome/browser/geolocation/win7_location_api_win.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+struct Geoposition;
+
+using testing::_;
+using testing::AtLeast;
+using testing::DoDefault;
+using testing::Invoke;
+using testing::Return;
+
+
+class MockWin7LocationApi : public Win7LocationApi {
+ public:
+ static MockWin7LocationApi* CreateMock() {
+ return new MockWin7LocationApi();
+ }
+
+ // Used to signal when the destructor is called.
+ MOCK_METHOD0(Die, void());
+ // Win7LocationApi
+ MOCK_METHOD1(GetPosition, void(Geoposition*));
+ MOCK_METHOD1(SetHighAccuracy, bool(bool));
+
+ virtual ~MockWin7LocationApi() {
+ Die();
+ }
+
+ void GetPositionValid(Geoposition* position) {
+ position->latitude = 4.5;
+ position->longitude = -34.1;
+ position->accuracy = 0.5;
+ position->timestamp = base::Time::FromDoubleT(200);
+ position->error_code = Geoposition::ERROR_CODE_NONE;
+ }
+ void GetPositionInvalid(Geoposition* position) {
+ position->latitude = 4.5;
+ position->longitude = -340000.1;
+ position->accuracy = 0.5;
+ position->timestamp = base::Time::FromDoubleT(200);
+ position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ }
+
+ private:
+ MockWin7LocationApi() : Win7LocationApi(NULL, NULL, NULL) {
+ ON_CALL(*this, GetPosition(_))
+ .WillByDefault(Invoke(this,
+ &MockWin7LocationApi::GetPositionValid));
+ ON_CALL(*this, SetHighAccuracy(true))
+ .WillByDefault(Return(true));
+ ON_CALL(*this, SetHighAccuracy(false))
+ .WillByDefault(Return(false));
+ }
+};
+
+class LocationProviderListenerLoopQuitter
+ : public LocationProviderBase::ListenerInterface {
+ public:
+ explicit LocationProviderListenerLoopQuitter(MessageLoop* message_loop)
+ : message_loop_to_quit_(message_loop) {
+ CHECK(message_loop_to_quit_ != NULL);
+ }
+ virtual void LocationUpdateAvailable(LocationProviderBase* provider) {
+ EXPECT_EQ(MessageLoop::current(), message_loop_to_quit_);
+ provider_ = provider;
+ message_loop_to_quit_->Quit();
+ }
+
+ MessageLoop* message_loop_to_quit_;
+ LocationProviderBase* provider_;
+};
+
+class GeolocationProviderWin7Tests : public testing::Test {
+ public:
+ GeolocationProviderWin7Tests(): location_listener_(&main_message_loop_) {
+ }
+
+ virtual void SetUp() {
+ api_ = MockWin7LocationApi::CreateMock();
+ provider_ = new Win7LocationProvider(api_);
+ provider_->RegisterListener(&location_listener_);
+ }
+ virtual void TearDown() {
+ provider_->UnregisterListener(&location_listener_);
+ provider_->StopProvider();
+ delete provider_;
+ main_message_loop_.RunAllPending();
+ }
+
+ protected:
+ MockWin7LocationApi* api_;
+ LocationProviderListenerLoopQuitter location_listener_;
+ MessageLoop main_message_loop_;
+ Win7LocationProvider* provider_;
+};
+
+TEST_F(GeolocationProviderWin7Tests, StartStop) {
+ EXPECT_CALL(*api_, SetHighAccuracy(true))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(provider_->StartProvider(true));
+ provider_->StopProvider();
+ EXPECT_CALL(*api_, SetHighAccuracy(false))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(provider_->StartProvider(false));
+}
+
+TEST_F(GeolocationProviderWin7Tests, GetValidPosition) {
+ EXPECT_CALL(*api_, GetPosition(_))
+ .Times(AtLeast(1));
+ EXPECT_CALL(*api_, SetHighAccuracy(true))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(provider_->StartProvider(true));
+ main_message_loop_.Run();
+ Geoposition position;
+ provider_->GetPosition(&position);
+ EXPECT_TRUE(position.IsValidFix());
+}
+
+TEST_F(GeolocationProviderWin7Tests, GetInvalidPosition) {
+ EXPECT_CALL(*api_, GetPosition(_))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Invoke(api_,
+ &MockWin7LocationApi::GetPositionInvalid));
+ EXPECT_CALL(*api_, SetHighAccuracy(true))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(provider_->StartProvider(true));
+ main_message_loop_.Run();
+ Geoposition position;
+ provider_->GetPosition(&position);
+ EXPECT_FALSE(position.IsValidFix());
+}
diff --git a/chrome/browser/geolocation/win7_location_provider_win.cc b/chrome/browser/geolocation/win7_location_provider_win.cc
new file mode 100644
index 0000000..aa400c4
--- /dev/null
+++ b/chrome/browser/geolocation/win7_location_provider_win.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2010 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 "chrome/browser/geolocation/win7_location_provider_win.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+
+namespace{
+const int kPollPeriodMovingMillis = 500;
+// Poll less frequently whilst stationary.
+const int kPollPeriodStationaryMillis = kPollPeriodMovingMillis * 3;
+// Reading must differ by more than this amount to be considered movement.
+const int kMovementThresholdMeters = 20;
+
+// This algorithm is reused from the corresponding code in the gears project
+// and is also used in gps_location_provider_linux.cc
+// The arbitrary delta is decreased (gears used 100 meters); if we need to
+// decrease it any further we'll likely want to do some smarter filtering to
+// remove GPS location jitter noise.
+bool PositionsDifferSiginificantly(const Geoposition& position_1,
+ const Geoposition& position_2) {
+ const bool pos_1_valid = position_1.IsValidFix();
+ if (pos_1_valid != position_2.IsValidFix())
+ return true;
+ if (!pos_1_valid) {
+ DCHECK(!position_2.IsValidFix());
+ return false;
+ }
+ double delta = std::sqrt(
+ std::pow(std::fabs(position_1.latitude - position_2.latitude), 2) +
+ std::pow(std::fabs(position_1.longitude - position_2.longitude), 2));
+ // Convert to meters. 1 minute of arc of latitude (or longitude at the
+ // equator) is 1 nautical mile or 1852m.
+ delta *= 60 * 1852;
+ return delta > kMovementThresholdMeters;
+}
+}
+
+Win7LocationProvider::Win7LocationProvider(Win7LocationApi* api)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
+ DCHECK(api != NULL);
+ api_.reset(api);
+}
+
+Win7LocationProvider::~Win7LocationProvider() {
+ api_.reset();
+}
+
+bool Win7LocationProvider::StartProvider(bool high_accuracy){
+ if (api_ == NULL)
+ return false;
+ api_->SetHighAccuracy(high_accuracy);
+ if (task_factory_.empty())
+ ScheduleNextPoll(0);
+ return true;
+}
+
+void Win7LocationProvider::StopProvider() {
+ task_factory_.RevokeAll();
+}
+
+void Win7LocationProvider::GetPosition(Geoposition* position) {
+ DCHECK(position);
+ *position = position_;
+}
+
+void Win7LocationProvider::UpdatePosition() {
+ ScheduleNextPoll(0);
+}
+
+void Win7LocationProvider::OnPermissionGranted(
+ const GURL& requesting_frame) {
+}
+
+void Win7LocationProvider::DoPollTask() {
+ Geoposition new_position;
+ api_->GetPosition(&new_position);
+ const bool differ = PositionsDifferSiginificantly(position_, new_position);
+ ScheduleNextPoll(differ ? kPollPeriodMovingMillis :
+ kPollPeriodStationaryMillis);
+ if (differ || new_position.error_code != Geoposition::ERROR_CODE_NONE) {
+ // Update if the new location is interesting or we have an error to report
+ position_ = new_position;
+ UpdateListeners();
+ }
+}
+
+void Win7LocationProvider::ScheduleNextPoll(int interval) {
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ task_factory_.NewRunnableMethod(&Win7LocationProvider::DoPollTask),
+ interval);
+}
+
+LocationProviderBase* NewSystemLocationProvider() {
+ Win7LocationApi* api = Win7LocationApi::Create();
+ if (api == NULL)
+ return NULL; // API not supported on this machine.
+ return new Win7LocationProvider(api);
+}
diff --git a/chrome/browser/geolocation/win7_location_provider_win.h b/chrome/browser/geolocation/win7_location_provider_win.h
new file mode 100644
index 0000000..7cc8d9c
--- /dev/null
+++ b/chrome/browser/geolocation/win7_location_provider_win.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2010 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 CHROME_BROWSER_GEOLOCATION_WIN7_LOCATION_PROVIDER_WIN_H_
+#define CHROME_BROWSER_GEOLOCATION_WIN7_LOCATION_PROVIDER_WIN_H_
+
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "chrome/browser/geolocation/location_provider.h"
+#include "chrome/browser/geolocation/win7_location_api_win.h"
+#include "chrome/common/geoposition.h"
+
+// Location provider for Windows 7 that uses the Location and Sensors platform
+// to obtain position fixes.
+// TODO(allanwoj): Remove polling and let the api signal when a new location.
+// TODO(allanwoj): Possibly derive this class and the linux gps provider class
+// from a single SystemLocationProvider class as their implementation is very
+// similar.
+class Win7LocationProvider : public LocationProviderBase {
+ public:
+ Win7LocationProvider(Win7LocationApi* api);
+ virtual ~Win7LocationProvider();
+
+ // LocationProvider.
+ virtual bool StartProvider(bool high_accuracy);
+ virtual void StopProvider();
+ virtual void GetPosition(Geoposition* position);
+ virtual void UpdatePosition();
+ virtual void OnPermissionGranted(const GURL& requesting_frame);
+
+ private:
+ // Task which runs in the child thread.
+ void DoPollTask();
+ // Will schedule a poll; i.e. enqueue DoPollTask deferred task.
+ void ScheduleNextPoll(int interval);
+
+ scoped_ptr<Win7LocationApi> api_;
+ Geoposition position_;
+ // Holder for the tasks which run on the thread; takes care of cleanup.
+ ScopedRunnableMethodFactory<Win7LocationProvider> task_factory_;
+};
+
+
+#endif // CHROME_BROWSER_GEOLOCATION_WIN7_LOCATION_PROVIDER_WIN_H_