1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/geolocation/win7_location_api_win.h"
7 #include "base/base_paths_win.h"
8 #include "base/command_line.h"
9 #include "base/file_path.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/path_service.h"
13 #include "content/public/common/content_switches.h"
14 #include "content/public/common/geoposition.h"
18 const double kKnotsToMetresPerSecondConversionFactor
= 0.5144;
20 void ConvertKnotsToMetresPerSecond(double* knots
) {
21 *knots
*= kKnotsToMetresPerSecondConversionFactor
;
24 HINSTANCE
LoadWin7Library(const string16
& lib_name
) {
26 PathService::Get(base::DIR_SYSTEM
, &sys_dir
);
27 return LoadLibrary(sys_dir
.Append(lib_name
).value().c_str());
31 Win7LocationApi::Win7LocationApi()
33 PropVariantToDouble_function_(0),
37 void Win7LocationApi::Init(HINSTANCE prop_library
,
38 PropVariantToDoubleFunction PropVariantToDouble_function
,
40 prop_lib_
= prop_library
;
41 PropVariantToDouble_function_
= PropVariantToDouble_function
;
45 Win7LocationApi::~Win7LocationApi() {
46 if (prop_lib_
!= NULL
)
47 FreeLibrary(prop_lib_
);
50 Win7LocationApi
* Win7LocationApi::Create() {
51 if (!CommandLine::ForCurrentProcess()
52 ->HasSwitch(switches::kExperimentalLocationFeatures
))
55 scoped_ptr
<Win7LocationApi
> result(new Win7LocationApi
);
57 string16 lib_needed
= L
"propsys.dll";
58 HINSTANCE prop_lib
= LoadWin7Library(lib_needed
);
61 // Get pointer to function.
62 PropVariantToDoubleFunction PropVariantToDouble_function
;
63 PropVariantToDouble_function
=
64 reinterpret_cast<PropVariantToDoubleFunction
>(
65 GetProcAddress(prop_lib
, "PropVariantToDouble"));
66 if (!PropVariantToDouble_function
) {
67 FreeLibrary(prop_lib
);
70 // Create the ILocation object that receives location reports.
72 CComPtr
<ILocation
> locator
;
73 result_type
= CoCreateInstance(
74 CLSID_Location
, NULL
, CLSCTX_INPROC
, IID_PPV_ARGS(&locator
));
75 if (!SUCCEEDED(result_type
)) {
76 FreeLibrary(prop_lib
);
79 IID reports_needed
[] = { IID_ILatLongReport
};
80 result_type
= locator
->RequestPermissions(NULL
, reports_needed
, 1, TRUE
);
81 result
->Init(prop_lib
, PropVariantToDouble_function
, locator
);
82 return result
.release();
85 Win7LocationApi
* Win7LocationApi::CreateForTesting(
86 PropVariantToDoubleFunction PropVariantToDouble_function
,
88 Win7LocationApi
* result
= new Win7LocationApi
;
89 result
->Init(NULL
, PropVariantToDouble_function
, locator
);
93 void Win7LocationApi::GetPosition(Geoposition
* position
) {
95 position
->error_code
= Geoposition::ERROR_CODE_POSITION_UNAVAILABLE
;
98 // Try to get a position fix
99 if (!GetPositionIfFixed(position
))
101 position
->error_code
= Geoposition::ERROR_CODE_NONE
;
102 if (!position
->Validate()) {
103 // GetPositionIfFixed returned true, yet we've not got a valid fix.
104 // This shouldn't happen; something went wrong in the conversion.
105 NOTREACHED() << "Invalid position from GetPositionIfFixed: lat,long "
106 << position
->latitude
<< "," << position
->longitude
107 << " accuracy " << position
->accuracy
<< " time "
108 << position
->timestamp
.ToDoubleT();
109 position
->error_code
= Geoposition::ERROR_CODE_POSITION_UNAVAILABLE
;
110 position
->error_message
= "Bad fix from Win7 provider";
114 bool Win7LocationApi::GetPositionIfFixed(Geoposition
* position
) {
116 CComPtr
<ILocationReport
> location_report
;
117 CComPtr
<ILatLongReport
> lat_long_report
;
118 result_type
= locator_
->GetReport(IID_ILatLongReport
, &location_report
);
119 // Checks to see if location access is allowed.
120 if (result_type
== E_ACCESSDENIED
)
121 position
->error_code
= Geoposition::ERROR_CODE_PERMISSION_DENIED
;
122 // Checks for any other errors while requesting a location report.
123 if (!SUCCEEDED(result_type
))
125 result_type
= location_report
->QueryInterface(&lat_long_report
);
126 if (!SUCCEEDED(result_type
))
128 result_type
= lat_long_report
->GetLatitude(&position
->latitude
);
129 if (!SUCCEEDED(result_type
))
131 result_type
= lat_long_report
->GetLongitude(&position
->longitude
);
132 if (!SUCCEEDED(result_type
))
134 result_type
= lat_long_report
->GetErrorRadius(&position
->accuracy
);
135 if (!SUCCEEDED(result_type
) || position
->accuracy
<= 0)
138 result_type
= lat_long_report
->GetAltitude(&temp_dbl
);
139 if (SUCCEEDED(result_type
))
140 position
->altitude
= temp_dbl
;
141 result_type
= lat_long_report
->GetAltitudeError(&temp_dbl
);
142 if (SUCCEEDED(result_type
))
143 position
->altitude_accuracy
= temp_dbl
;
145 PropVariantInit(&heading
);
146 result_type
= lat_long_report
->GetValue(
147 SENSOR_DATA_TYPE_TRUE_HEADING_DEGREES
, &heading
);
148 if (SUCCEEDED(result_type
))
149 PropVariantToDouble_function_(heading
, &position
->heading
);
151 PropVariantInit(&speed
);
152 result_type
= lat_long_report
->GetValue(
153 SENSOR_DATA_TYPE_SPEED_KNOTS
, &speed
);
154 if (SUCCEEDED(result_type
)) {
155 PropVariantToDouble_function_(speed
, &position
->speed
);
156 ConvertKnotsToMetresPerSecond(&position
->speed
);
158 position
->timestamp
= base::Time::Now();
162 bool Win7LocationApi::SetHighAccuracy(bool acc
) {
164 result_type
= locator_
->SetDesiredAccuracy(IID_ILatLongReport
,
165 acc
? LOCATION_DESIRED_ACCURACY_HIGH
:
166 LOCATION_DESIRED_ACCURACY_DEFAULT
);
167 return SUCCEEDED(result_type
);
170 } // namespace content