1 // Copyright 2016 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.
4
5 #include <SensorsApi.h>
6 #include <sensors.h>
7 #include <wrl/implements.h>
8
9 #include "base/bind.h"
10 #include "base/numerics/math_constants.h"
11 #include "base/run_loop.h"
12 #include "base/test/task_environment.h"
13 #include "base/win/propvarutil.h"
14 #include "base/win/scoped_com_initializer.h"
15 #include "base/win/scoped_propvariant.h"
16 #include "services/device/generic_sensor/fake_platform_sensor_and_provider.h"
17 #include "services/device/generic_sensor/generic_sensor_consts.h"
18 #include "services/device/generic_sensor/platform_sensor_provider_win.h"
19 #include "services/device/generic_sensor/platform_sensor_util.h"
20 #include "services/device/public/mojom/sensor_provider.mojom.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "ui/gfx/geometry/angle_conversions.h"
24
25 using ::testing::_;
26 using ::testing::Invoke;
27 using ::testing::IsNull;
28 using ::testing::NiceMock;
29 using ::testing::NotNull;
30 using ::testing::WithArgs;
31
32 namespace device {
33
34 using mojom::SensorType;
35
36 // Mock class for ISensorManager COM interface.
37 class MockISensorManager
38 : public Microsoft::WRL::RuntimeClass<
39 Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
40 ISensorManager> {
41 public:
42 // ISensorManager interface
43 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
44 GetSensorsByCategory,
45 HRESULT(REFSENSOR_CATEGORY_ID category,
46 ISensorCollection** sensors_found));
47 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
48 GetSensorsByType,
49 HRESULT(REFSENSOR_TYPE_ID sensor_id,
50 ISensorCollection** sensors_found));
51 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
52 GetSensorByID,
53 HRESULT(REFSENSOR_ID sensor_id, ISensor** sensor));
54 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
55 SetEventSink,
56 HRESULT(ISensorManagerEvents* event_sink));
57 MOCK_METHOD3_WITH_CALLTYPE(STDMETHODCALLTYPE,
58 RequestPermissions,
59 HRESULT(HWND parent,
60 ISensorCollection* sensors,
61 BOOL is_modal));
62
63 protected:
64 ~MockISensorManager() override = default;
65 };
66
67 // Mock class for ISensorCollection COM interface.
68 class MockISensorCollection
69 : public Microsoft::WRL::RuntimeClass<
70 Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
71 ISensorCollection> {
72 public:
73 // ISensorCollection interface
74 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
75 GetAt,
76 HRESULT(ULONG index, ISensor** sensor));
77 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
78 GetCount,
79 HRESULT(ULONG* count));
80 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, Add, HRESULT(ISensor* sensor));
81 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
82 Remove,
83 HRESULT(ISensor* sensor));
84 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
85 RemoveByID,
86 HRESULT(REFSENSOR_ID sensor_id));
87 MOCK_METHOD0_WITH_CALLTYPE(STDMETHODCALLTYPE, Clear, HRESULT());
88
89 protected:
90 ~MockISensorCollection() override = default;
91 };
92
93 // Mock class for ISensor COM interface.
94 class MockISensor
95 : public Microsoft::WRL::RuntimeClass<
96 Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
97 ISensor> {
98 public:
99 // ISensor interface
100 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, GetID, HRESULT(SENSOR_ID* id));
101 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
102 GetCategory,
103 HRESULT(SENSOR_CATEGORY_ID* category));
104 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
105 GetType,
106 HRESULT(SENSOR_TYPE_ID* type));
107 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
108 GetFriendlyName,
109 HRESULT(BSTR* name));
110 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
111 GetProperty,
112 HRESULT(REFPROPERTYKEY key,
113 PROPVARIANT* property));
114 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
115 GetProperties,
116 HRESULT(IPortableDeviceKeyCollection* keys,
117 IPortableDeviceValues** properties));
118 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
119 GetSupportedDataFields,
120 HRESULT(IPortableDeviceKeyCollection** data));
121 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
122 SetProperties,
123 HRESULT(IPortableDeviceValues* properties,
124 IPortableDeviceValues** results));
125 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
126 SupportsDataField,
127 HRESULT(REFPROPERTYKEY key,
128 VARIANT_BOOL* is_supported));
129 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
130 GetState,
131 HRESULT(SensorState* state));
132 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
133 GetData,
134 HRESULT(ISensorDataReport** data_report));
135 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
136 SupportsEvent,
137 HRESULT(REFGUID event_guid,
138 VARIANT_BOOL* is_supported));
139 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
140 GetEventInterest,
141 HRESULT(GUID** values, ULONG* count));
142 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
143 SetEventInterest,
144 HRESULT(GUID* values, ULONG count));
145 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
146 SetEventSink,
147 HRESULT(ISensorEvents* pEvents));
148
149 protected:
150 ~MockISensor() override = default;
151 };
152
153 // Mock class for ISensorDataReport COM interface.
154 class MockISensorDataReport
155 : public Microsoft::WRL::RuntimeClass<
156 Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
157 ISensorDataReport> {
158 public:
159 // ISensorDataReport interface
160 MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
161 GetTimestamp,
162 HRESULT(SYSTEMTIME* timestamp));
163 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
164 GetSensorValue,
165 HRESULT(REFPROPERTYKEY key, PROPVARIANT* value));
166 MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE,
167 GetSensorValues,
168 HRESULT(IPortableDeviceKeyCollection* keys,
169 IPortableDeviceValues** values));
170
171 protected:
172 ~MockISensorDataReport() override = default;
173 };
174
175 // Class that provides test harness support for generic sensor adaptation for
176 // Windows platform. Testing is mainly done by mocking main COM interfaces that
177 // are used to communicate with Sensors API.
178 // MockISensorManager - mocks ISensorManager and responsible for fetching
179 // list of supported sensors.
180 // MockISensorCollection - mocks collection of ISensor objects.
181 // MockISensor - mocks ISensor intrface.
182 // MockISensorDataReport - mocks IDataReport interface that is used to deliver
183 // data in OnDataUpdated event.
184 class PlatformSensorAndProviderTestWin : public ::testing::Test {
185 public:
PlatformSensorAndProviderTestWin()186 PlatformSensorAndProviderTestWin()
187 : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
188
SetUp()189 void SetUp() override {
190 sensor_ = Microsoft::WRL::Make<NiceMock<MockISensor>>();
191 sensor_collection_ =
192 Microsoft::WRL::Make<NiceMock<MockISensorCollection>>();
193 sensor_manager_ = Microsoft::WRL::Make<NiceMock<MockISensorManager>>();
194 Microsoft::WRL::ComPtr<ISensorManager> manager;
195 sensor_manager_->QueryInterface(IID_PPV_ARGS(&manager));
196
197 // Overrides default ISensorManager with mocked interface.
198 provider_ = std::make_unique<PlatformSensorProviderWin>();
199 provider_->SetSensorManagerForTesting(std::move(manager));
200 }
201
202 protected:
SensorCreated(scoped_refptr<PlatformSensor> sensor)203 void SensorCreated(scoped_refptr<PlatformSensor> sensor) {
204 platform_sensor_ = sensor;
205 run_loop_->Quit();
206 }
207
208 // Sensor creation is asynchronous, therefore inner loop is used to wait for
209 // PlatformSensorProvider::CreateSensorCallback completion.
CreateSensor(mojom::SensorType type)210 scoped_refptr<PlatformSensor> CreateSensor(mojom::SensorType type) {
211 run_loop_ = std::make_unique<base::RunLoop>();
212 provider_->CreateSensor(
213 type, base::BindOnce(&PlatformSensorAndProviderTestWin::SensorCreated,
214 base::Unretained(this)));
215 run_loop_->Run();
216 scoped_refptr<PlatformSensor> sensor;
217 sensor.swap(platform_sensor_);
218 run_loop_ = nullptr;
219 return sensor;
220 }
221
222 // Listening the sensor is asynchronous, therefore inner loop is used to wait
223 // for SetEventSink to be called.
StartListening(scoped_refptr<PlatformSensor> sensor,PlatformSensor::Client * client,const PlatformSensorConfiguration & config)224 bool StartListening(scoped_refptr<PlatformSensor> sensor,
225 PlatformSensor::Client* client,
226 const PlatformSensorConfiguration& config) {
227 run_loop_ = std::make_unique<base::RunLoop>();
228 bool ret = sensor->StartListening(client, config);
229 if (ret)
230 run_loop_->Run();
231 run_loop_ = nullptr;
232 return ret;
233 }
234
QuitInnerLoop()235 void QuitInnerLoop() { run_loop_->Quit(); }
236
SetUnsupportedSensor(REFSENSOR_TYPE_ID sensor)237 void SetUnsupportedSensor(REFSENSOR_TYPE_ID sensor) {
238 EXPECT_CALL(*(sensor_manager_.Get()), GetSensorsByType(sensor, _))
239 .WillRepeatedly(
240 Invoke([](REFSENSOR_TYPE_ID type, ISensorCollection** collection) {
241 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
242 }));
243 }
244
245 // Sets sensor with REFSENSOR_TYPE_ID |sensor| to be supported by mocked
246 // ISensorMager and it will be present in ISensorCollection.
SetSupportedSensor(REFSENSOR_TYPE_ID sensor)247 void SetSupportedSensor(REFSENSOR_TYPE_ID sensor) {
248 // Returns mock ISensorCollection.
249 EXPECT_CALL(*(sensor_manager_.Get()), GetSensorsByType(sensor, _))
250 .WillOnce(Invoke(
251 [this](REFSENSOR_TYPE_ID type, ISensorCollection** collection) {
252 sensor_collection_->QueryInterface(
253 __uuidof(ISensorCollection),
254 reinterpret_cast<void**>(collection));
255 return S_OK;
256 }));
257
258 // Returns number of ISensor objects in ISensorCollection, at the moment
259 // only one ISensor interface instance is suported.
260 EXPECT_CALL(*(sensor_collection_.Get()), GetCount(_))
261 .WillOnce(Invoke([](ULONG* count) {
262 *count = 1;
263 return S_OK;
264 }));
265
266 // Returns ISensor interface instance at index 0.
267 EXPECT_CALL(*(sensor_collection_.Get()), GetAt(0, _))
268 .WillOnce(Invoke([this](ULONG index, ISensor** sensor) {
269 sensor_->QueryInterface(__uuidof(ISensor),
270 reinterpret_cast<void**>(sensor));
271 return S_OK;
272 }));
273
274 // Handles |SetEventSink| call that is used to subscribe to sensor events
275 // through ISensorEvents interface. ISensorEvents is stored and attached to
276 // |sensor_events_| that is used later to generate fake error, state and
277 // data change events.
278 ON_CALL(*(sensor_.Get()), SetEventSink(NotNull()))
279 .WillByDefault(Invoke([this](ISensorEvents* events) {
280 events->AddRef();
281 sensor_events_.Attach(events);
282 if (this->run_loop_) {
283 task_environment_.GetMainThreadTaskRunner()->PostTask(
284 FROM_HERE,
285 base::BindOnce(&PlatformSensorAndProviderTestWin::QuitInnerLoop,
286 base::Unretained(this)));
287 }
288 return S_OK;
289 }));
290
291 // When |SetEventSink| is called with nullptr, it means that client is no
292 // longer interested in sensor events and ISensorEvents can be released.
293 ON_CALL(*(sensor_.Get()), SetEventSink(IsNull()))
294 .WillByDefault(Invoke([this](ISensorEvents* events) {
295 sensor_events_.Reset();
296 if (this->run_loop_) {
297 task_environment_.GetMainThreadTaskRunner()->PostTask(
298 FROM_HERE,
299 base::BindOnce(&PlatformSensorAndProviderTestWin::QuitInnerLoop,
300 base::Unretained(this)));
301 }
302 return S_OK;
303 }));
304 }
305
306 // Sets minimal reporting frequency for the mock sensor.
SetSupportedReportingFrequency(int frequency)307 void SetSupportedReportingFrequency(int frequency) {
308 ON_CALL(*(sensor_.Get()),
309 GetProperty(SENSOR_PROPERTY_MIN_REPORT_INTERVAL, _))
310 .WillByDefault(
311 Invoke([frequency](REFPROPERTYKEY key, PROPVARIANT* pProperty) {
312 pProperty->vt = VT_UI4;
313 pProperty->ulVal = 0;
314 if (frequency != 0) {
315 pProperty->ulVal =
316 (1.0 / frequency) * base::Time::kMillisecondsPerSecond;
317 }
318 return S_OK;
319 }));
320 }
321
322 // Generates OnLeave event, e.g. when sensor is disconnected.
GenerateLeaveEvent()323 void GenerateLeaveEvent() {
324 if (!sensor_events_)
325 return;
326 sensor_events_->OnLeave(SENSOR_ID());
327 }
328
329 // Generates OnStateChangedLeave event.
GenerateStateChangeEvent(SensorState state)330 void GenerateStateChangeEvent(SensorState state) {
331 if (!sensor_events_)
332 return;
333 sensor_events_->OnStateChanged(sensor_.Get(), state);
334 }
335
336 struct PropertyKeyCompare {
operator ()device::PlatformSensorAndProviderTestWin::PropertyKeyCompare337 bool operator()(REFPROPERTYKEY a, REFPROPERTYKEY b) const {
338 if (a.fmtid == b.fmtid)
339 return a.pid < b.pid;
340 return false;
341 }
342 };
343
344 using SensorData =
345 std::map<PROPERTYKEY, const PROPVARIANT*, PropertyKeyCompare>;
346
347 // Generates OnDataUpdated event and creates ISensorDataReport with fake
348 // |value| for property with |key|.
GenerateDataUpdatedEvent(const SensorData & values)349 void GenerateDataUpdatedEvent(const SensorData& values) {
350 if (!sensor_events_)
351 return;
352
353 auto mock_report = Microsoft::WRL::Make<NiceMock<MockISensorDataReport>>();
354 Microsoft::WRL::ComPtr<ISensorDataReport> data_report;
355 mock_report.As(&data_report);
356
357 EXPECT_CALL(*(mock_report.Get()), GetTimestamp(_))
358 .WillOnce(Invoke([](SYSTEMTIME* timestamp) {
359 GetSystemTime(timestamp);
360 return S_OK;
361 }));
362
363 EXPECT_CALL(*(mock_report.Get()), GetSensorValue(_, _))
364 .WillRepeatedly(WithArgs<0, 1>(
365 Invoke([&values](REFPROPERTYKEY key, PROPVARIANT* variant) {
366 auto it = values.find(key);
367 if (it == values.end())
368 return E_FAIL;
369
370 PropVariantCopy(variant, it->second);
371 return S_OK;
372 })));
373
374 sensor_events_->OnDataUpdated(sensor_.Get(), data_report.Get());
375 }
376
377 base::win::ScopedCOMInitializer com_initializer_;
378 base::test::TaskEnvironment task_environment_;
379 Microsoft::WRL::ComPtr<MockISensorManager> sensor_manager_;
380 Microsoft::WRL::ComPtr<MockISensorCollection> sensor_collection_;
381 Microsoft::WRL::ComPtr<MockISensor> sensor_;
382 std::unique_ptr<PlatformSensorProviderWin> provider_;
383 Microsoft::WRL::ComPtr<ISensorEvents> sensor_events_;
384 scoped_refptr<PlatformSensor> platform_sensor_;
385 // Inner run loop used to wait for async sensor creation callback.
386 std::unique_ptr<base::RunLoop> run_loop_;
387 };
388
RoundAccelerometerValue(double value)389 double RoundAccelerometerValue(double value) {
390 return RoundToMultiple(value, kAccelerometerRoundingMultiple);
391 }
392
RoundGyroscopeValue(double value)393 double RoundGyroscopeValue(double value) {
394 return RoundToMultiple(value, kGyroscopeRoundingMultiple);
395 }
396
397 // Tests that PlatformSensorManager returns null sensor when sensor
398 // is not implemented.
TEST_F(PlatformSensorAndProviderTestWin,SensorIsNotImplemented)399 TEST_F(PlatformSensorAndProviderTestWin, SensorIsNotImplemented) {
400 EXPECT_CALL(*(sensor_manager_.Get()),
401 GetSensorsByType(SENSOR_TYPE_PRESSURE, _))
402 .Times(0);
403 EXPECT_FALSE(CreateSensor(SensorType::PRESSURE));
404 }
405
406 // Tests that PlatformSensorManager returns null sensor when sensor
407 // is implemented, but not supported by the hardware.
TEST_F(PlatformSensorAndProviderTestWin,SensorIsNotSupported)408 TEST_F(PlatformSensorAndProviderTestWin, SensorIsNotSupported) {
409 EXPECT_CALL(*(sensor_manager_.Get()),
410 GetSensorsByType(SENSOR_TYPE_AMBIENT_LIGHT, _))
411 .WillOnce(Invoke([](REFSENSOR_TYPE_ID, ISensorCollection** result) {
412 *result = nullptr;
413 return E_FAIL;
414 }));
415
416 EXPECT_FALSE(CreateSensor(SensorType::AMBIENT_LIGHT));
417 }
418
419 // Tests that PlatformSensorManager returns correct sensor when sensor
420 // is supported by the hardware.
TEST_F(PlatformSensorAndProviderTestWin,SensorIsSupported)421 TEST_F(PlatformSensorAndProviderTestWin, SensorIsSupported) {
422 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
423 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
424 EXPECT_TRUE(sensor);
425 EXPECT_EQ(SensorType::AMBIENT_LIGHT, sensor->GetType());
426 }
427
428 // Tests that PlatformSensor::StartListening fails when provided reporting
429 // frequency is above hardware capabilities.
TEST_F(PlatformSensorAndProviderTestWin,StartFails)430 TEST_F(PlatformSensorAndProviderTestWin, StartFails) {
431 SetSupportedReportingFrequency(1);
432 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
433
434 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
435 EXPECT_TRUE(sensor);
436
437 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
438 PlatformSensorConfiguration configuration(10);
439 EXPECT_FALSE(sensor->StartListening(client.get(), configuration));
440 }
441
442 // Tests that PlatformSensor::StartListening succeeds and notification about
443 // modified sensor reading is sent to the PlatformSensor::Client interface.
TEST_F(PlatformSensorAndProviderTestWin,SensorStarted)444 TEST_F(PlatformSensorAndProviderTestWin, SensorStarted) {
445 SetSupportedReportingFrequency(10);
446 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
447
448 EXPECT_CALL(*(sensor_.Get()), SetEventSink(NotNull())).Times(1);
449 EXPECT_CALL(*(sensor_.Get()), SetEventSink(IsNull())).Times(1);
450 EXPECT_CALL(*(sensor_.Get()), SetProperties(NotNull(), _))
451 .WillRepeatedly(Invoke(
452 [](IPortableDeviceValues* props, IPortableDeviceValues** result) {
453 ULONG value = 0;
454 HRESULT hr = props->GetUnsignedIntegerValue(
455 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, &value);
456 EXPECT_TRUE(SUCCEEDED(hr));
457 // 10Hz is 100msec
458 EXPECT_THAT(value, 100);
459 return hr;
460 }));
461
462 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
463 EXPECT_TRUE(sensor);
464
465 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
466 PlatformSensorConfiguration configuration(10);
467 EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
468
469 EXPECT_CALL(*client, OnSensorReadingChanged(sensor->GetType())).Times(1);
470 base::win::ScopedPropVariant pvLux;
471 InitPropVariantFromDouble(3.14, pvLux.Receive());
472 GenerateDataUpdatedEvent({{SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX, pvLux.ptr()}});
473 base::RunLoop().RunUntilIdle();
474 EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
475 }
476
477 // Tests that OnSensorError is called when sensor is disconnected.
TEST_F(PlatformSensorAndProviderTestWin,SensorRemoved)478 TEST_F(PlatformSensorAndProviderTestWin, SensorRemoved) {
479 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
480 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
481 EXPECT_TRUE(sensor);
482
483 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
484 PlatformSensorConfiguration configuration(10);
485 EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
486 EXPECT_CALL(*client, OnSensorError()).Times(1);
487
488 GenerateLeaveEvent();
489 base::RunLoop().RunUntilIdle();
490 }
491
492 // Tests that OnSensorError is called when sensor is in an error state.
TEST_F(PlatformSensorAndProviderTestWin,SensorStateChangedToError)493 TEST_F(PlatformSensorAndProviderTestWin, SensorStateChangedToError) {
494 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
495 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
496 EXPECT_TRUE(sensor);
497
498 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
499 PlatformSensorConfiguration configuration(10);
500 EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
501 EXPECT_CALL(*client, OnSensorError()).Times(1);
502
503 GenerateStateChangeEvent(SENSOR_STATE_ERROR);
504 base::RunLoop().RunUntilIdle();
505 }
506
507 // Tests that OnSensorError is not called when sensor is in a ready state.
TEST_F(PlatformSensorAndProviderTestWin,SensorStateChangedToReady)508 TEST_F(PlatformSensorAndProviderTestWin, SensorStateChangedToReady) {
509 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
510 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
511 EXPECT_TRUE(sensor);
512
513 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
514 PlatformSensorConfiguration configuration(10);
515 EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
516 EXPECT_CALL(*client, OnSensorError()).Times(0);
517
518 GenerateStateChangeEvent(SENSOR_STATE_READY);
519 base::RunLoop().RunUntilIdle();
520 }
521
522 // Tests that GetMaximumSupportedFrequency provides correct value.
TEST_F(PlatformSensorAndProviderTestWin,GetMaximumSupportedFrequency)523 TEST_F(PlatformSensorAndProviderTestWin, GetMaximumSupportedFrequency) {
524 SetSupportedReportingFrequency(20);
525 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
526 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
527 EXPECT_TRUE(sensor);
528 EXPECT_THAT(sensor->GetMaximumSupportedFrequency(), 20);
529 }
530
531 // Tests that GetMaximumSupportedFrequency returns fallback value.
TEST_F(PlatformSensorAndProviderTestWin,GetMaximumSupportedFrequencyFallback)532 TEST_F(PlatformSensorAndProviderTestWin, GetMaximumSupportedFrequencyFallback) {
533 SetSupportedReportingFrequency(0);
534 SetSupportedSensor(SENSOR_TYPE_AMBIENT_LIGHT);
535 auto sensor = CreateSensor(SensorType::AMBIENT_LIGHT);
536 EXPECT_TRUE(sensor);
537 EXPECT_THAT(sensor->GetMaximumSupportedFrequency(), 5);
538 }
539
540 // Tests that Accelerometer readings are correctly converted.
TEST_F(PlatformSensorAndProviderTestWin,CheckAccelerometerReadingConversion)541 TEST_F(PlatformSensorAndProviderTestWin, CheckAccelerometerReadingConversion) {
542 mojo::ScopedSharedBufferHandle handle = provider_->CloneSharedBufferHandle();
543 mojo::ScopedSharedBufferMapping mapping = handle->MapAtOffset(
544 sizeof(SensorReadingSharedBuffer),
545 SensorReadingSharedBuffer::GetOffset(SensorType::ACCELEROMETER));
546
547 SetSupportedSensor(SENSOR_TYPE_ACCELEROMETER_3D);
548 auto sensor = CreateSensor(SensorType::ACCELEROMETER);
549 EXPECT_TRUE(sensor);
550
551 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
552 PlatformSensorConfiguration configuration(10);
553 EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
554 EXPECT_CALL(*client, OnSensorReadingChanged(sensor->GetType())).Times(1);
555
556 double x_accel = 0.25;
557 double y_accel = -0.25;
558 double z_accel = -0.5;
559
560 base::win::ScopedPropVariant pvX, pvY, pvZ;
561 InitPropVariantFromDouble(x_accel, pvX.Receive());
562 InitPropVariantFromDouble(y_accel, pvY.Receive());
563 InitPropVariantFromDouble(z_accel, pvZ.Receive());
564
565 GenerateDataUpdatedEvent({{SENSOR_DATA_TYPE_ACCELERATION_X_G, pvX.ptr()},
566 {SENSOR_DATA_TYPE_ACCELERATION_Y_G, pvY.ptr()},
567 {SENSOR_DATA_TYPE_ACCELERATION_Z_G, pvZ.ptr()}});
568
569 base::RunLoop().RunUntilIdle();
570 SensorReadingSharedBuffer* buffer =
571 static_cast<SensorReadingSharedBuffer*>(mapping.get());
572 EXPECT_THAT(buffer->reading.accel.x,
573 RoundAccelerometerValue(-x_accel * base::kMeanGravityDouble));
574 EXPECT_THAT(buffer->reading.accel.y,
575 RoundAccelerometerValue(-y_accel * base::kMeanGravityDouble));
576 EXPECT_THAT(buffer->reading.accel.z,
577 RoundAccelerometerValue(-z_accel * base::kMeanGravityDouble));
578 EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
579 }
580
581 // Tests that Gyroscope readings are correctly converted.
TEST_F(PlatformSensorAndProviderTestWin,CheckGyroscopeReadingConversion)582 TEST_F(PlatformSensorAndProviderTestWin, CheckGyroscopeReadingConversion) {
583 mojo::ScopedSharedBufferHandle handle = provider_->CloneSharedBufferHandle();
584 mojo::ScopedSharedBufferMapping mapping = handle->MapAtOffset(
585 sizeof(SensorReadingSharedBuffer),
586 SensorReadingSharedBuffer::GetOffset(SensorType::GYROSCOPE));
587
588 SetSupportedSensor(SENSOR_TYPE_GYROMETER_3D);
589 auto sensor = CreateSensor(SensorType::GYROSCOPE);
590 EXPECT_TRUE(sensor);
591
592 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
593 PlatformSensorConfiguration configuration(10);
594 EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
595 EXPECT_CALL(*client, OnSensorReadingChanged(sensor->GetType())).Times(1);
596
597 double x_ang_accel = 0.0;
598 double y_ang_accel = -1.8;
599 double z_ang_accel = -98.7;
600
601 base::win::ScopedPropVariant pvX, pvY, pvZ;
602 InitPropVariantFromDouble(x_ang_accel, pvX.Receive());
603 InitPropVariantFromDouble(y_ang_accel, pvY.Receive());
604 InitPropVariantFromDouble(z_ang_accel, pvZ.Receive());
605
606 GenerateDataUpdatedEvent(
607 {{SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND, pvX.ptr()},
608 {SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND, pvY.ptr()},
609 {SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND, pvZ.ptr()}});
610
611 base::RunLoop().RunUntilIdle();
612 SensorReadingSharedBuffer* buffer =
613 static_cast<SensorReadingSharedBuffer*>(mapping.get());
614 EXPECT_THAT(buffer->reading.gyro.x,
615 RoundGyroscopeValue(gfx::DegToRad(x_ang_accel)));
616 EXPECT_THAT(buffer->reading.gyro.y,
617 RoundGyroscopeValue(gfx::DegToRad(y_ang_accel)));
618 EXPECT_THAT(buffer->reading.gyro.z,
619 RoundGyroscopeValue(gfx::DegToRad(z_ang_accel)));
620 EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
621 }
622
623 // Tests that Magnetometer readings are correctly converted.
TEST_F(PlatformSensorAndProviderTestWin,CheckMagnetometerReadingConversion)624 TEST_F(PlatformSensorAndProviderTestWin, CheckMagnetometerReadingConversion) {
625 mojo::ScopedSharedBufferHandle handle = provider_->CloneSharedBufferHandle();
626 mojo::ScopedSharedBufferMapping mapping = handle->MapAtOffset(
627 sizeof(SensorReadingSharedBuffer),
628 SensorReadingSharedBuffer::GetOffset(SensorType::MAGNETOMETER));
629
630 SetSupportedSensor(SENSOR_TYPE_COMPASS_3D);
631 auto sensor = CreateSensor(SensorType::MAGNETOMETER);
632 EXPECT_TRUE(sensor);
633
634 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
635 PlatformSensorConfiguration configuration(10);
636 EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
637 EXPECT_CALL(*client, OnSensorReadingChanged(sensor->GetType())).Times(1);
638
639 double x_magn_field = 112.0;
640 double y_magn_field = -162.0;
641 double z_magn_field = 457.0;
642
643 base::win::ScopedPropVariant pvX, pvY, pvZ;
644 InitPropVariantFromDouble(x_magn_field, pvX.Receive());
645 InitPropVariantFromDouble(y_magn_field, pvY.Receive());
646 InitPropVariantFromDouble(z_magn_field, pvZ.Receive());
647
648 GenerateDataUpdatedEvent(
649 {{SENSOR_DATA_TYPE_MAGNETIC_FIELD_STRENGTH_X_MILLIGAUSS, pvX.ptr()},
650 {SENSOR_DATA_TYPE_MAGNETIC_FIELD_STRENGTH_Y_MILLIGAUSS, pvY.ptr()},
651 {SENSOR_DATA_TYPE_MAGNETIC_FIELD_STRENGTH_Z_MILLIGAUSS, pvZ.ptr()}});
652
653 base::RunLoop().RunUntilIdle();
654 SensorReadingSharedBuffer* buffer =
655 static_cast<SensorReadingSharedBuffer*>(mapping.get());
656 EXPECT_THAT(buffer->reading.magn.x, x_magn_field * kMicroteslaInMilligauss);
657 EXPECT_THAT(buffer->reading.magn.y, y_magn_field * kMicroteslaInMilligauss);
658 EXPECT_THAT(buffer->reading.magn.z, z_magn_field * kMicroteslaInMilligauss);
659 EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
660 }
661
662 // Tests that AbsoluteOrientationEulerAngles sensor readings are correctly
663 // provided.
TEST_F(PlatformSensorAndProviderTestWin,CheckDeviceOrientationEulerAnglesReadingConversion)664 TEST_F(PlatformSensorAndProviderTestWin,
665 CheckDeviceOrientationEulerAnglesReadingConversion) {
666 mojo::ScopedSharedBufferHandle handle = provider_->CloneSharedBufferHandle();
667 mojo::ScopedSharedBufferMapping mapping =
668 handle->MapAtOffset(sizeof(SensorReadingSharedBuffer),
669 SensorReadingSharedBuffer::GetOffset(
670 SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES));
671
672 SetSupportedSensor(SENSOR_TYPE_INCLINOMETER_3D);
673 auto sensor = CreateSensor(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES);
674 EXPECT_TRUE(sensor);
675
676 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
677 PlatformSensorConfiguration configuration(10);
678 EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
679 EXPECT_CALL(*client, OnSensorReadingChanged(sensor->GetType())).Times(1);
680
681 double x = 10;
682 double y = 20;
683 double z = 30;
684
685 base::win::ScopedPropVariant pvX, pvY, pvZ;
686 InitPropVariantFromDouble(x, pvX.Receive());
687 InitPropVariantFromDouble(y, pvY.Receive());
688 InitPropVariantFromDouble(z, pvZ.Receive());
689
690 GenerateDataUpdatedEvent({{SENSOR_DATA_TYPE_TILT_X_DEGREES, pvX.ptr()},
691 {SENSOR_DATA_TYPE_TILT_Y_DEGREES, pvY.ptr()},
692 {SENSOR_DATA_TYPE_TILT_Z_DEGREES, pvZ.ptr()}});
693
694 base::RunLoop().RunUntilIdle();
695 SensorReadingSharedBuffer* buffer =
696 static_cast<SensorReadingSharedBuffer*>(mapping.get());
697
698 EXPECT_THAT(buffer->reading.orientation_euler.x, x);
699 EXPECT_THAT(buffer->reading.orientation_euler.y, y);
700 EXPECT_THAT(buffer->reading.orientation_euler.z, z);
701 EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
702 }
703
704 // Tests that AbsoluteOrientationQuaternion sensor readings are correctly
705 // provided.
TEST_F(PlatformSensorAndProviderTestWin,CheckDeviceOrientationQuaternionReadingConversion)706 TEST_F(PlatformSensorAndProviderTestWin,
707 CheckDeviceOrientationQuaternionReadingConversion) {
708 mojo::ScopedSharedBufferHandle handle = provider_->CloneSharedBufferHandle();
709 mojo::ScopedSharedBufferMapping mapping =
710 handle->MapAtOffset(sizeof(SensorReadingSharedBuffer),
711 SensorReadingSharedBuffer::GetOffset(
712 SensorType::ABSOLUTE_ORIENTATION_QUATERNION));
713
714 SetSupportedSensor(SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION);
715 auto sensor = CreateSensor(SensorType::ABSOLUTE_ORIENTATION_QUATERNION);
716 EXPECT_TRUE(sensor);
717
718 auto client = std::make_unique<NiceMock<MockPlatformSensorClient>>(sensor);
719 PlatformSensorConfiguration configuration(10);
720 EXPECT_TRUE(StartListening(sensor, client.get(), configuration));
721 EXPECT_CALL(*client, OnSensorReadingChanged(sensor->GetType())).Times(1);
722
723 // The axis (unit vector) around which to rotate.
724 const double axis[3] = {1.0 / std::sqrt(3), 1.0 / std::sqrt(3),
725 -1.0 / std::sqrt(3)};
726
727 // Create the unit quaternion manually.
728 const double theta = 2.0943951023931953; // 120 degrees in radians.
729 const float quat_elements[4] = {
730 axis[0] * std::sin(theta / 2.0), axis[1] * std::sin(theta / 2.0),
731 axis[2] * std::sin(theta / 2.0), std::cos(theta / 2.0)};
732
733 base::win::ScopedPropVariant pvQuat;
734
735 // The SENSOR_DATA_TYPE_QUATERNION property has [VT_VECTOR | VT_UI1] type.
736 // https://msdn.microsoft.com/en-us/library/windows/hardware/dn265187(v=vs.85).aspx
737 // Helper functions e.g., InitVariantFromDoubleArray cannot be used for its
738 // intialization and the only way to initialize it, is to use
739 // InitPropVariantFromGUIDAsBuffer with quaternion format GUID.
740 InitPropVariantFromGUIDAsBuffer(SENSOR_DATA_TYPE_QUATERNION.fmtid,
741 pvQuat.Receive());
742 memcpy(pvQuat.get().caub.pElems, &quat_elements, sizeof(quat_elements));
743 GenerateDataUpdatedEvent({{SENSOR_DATA_TYPE_QUATERNION, pvQuat.ptr()}});
744
745 base::RunLoop().RunUntilIdle();
746 SensorReadingSharedBuffer* buffer =
747 static_cast<SensorReadingSharedBuffer*>(mapping.get());
748
749 const float epsilon = 1.0e-3;
750 EXPECT_NEAR(buffer->reading.orientation_quat.x, quat_elements[0], epsilon);
751 EXPECT_NEAR(buffer->reading.orientation_quat.y, quat_elements[1], epsilon);
752 EXPECT_NEAR(buffer->reading.orientation_quat.z, quat_elements[2], epsilon);
753 EXPECT_FLOAT_EQ(buffer->reading.orientation_quat.w, quat_elements[3]);
754 EXPECT_TRUE(sensor->StopListening(client.get(), configuration));
755 }
756
757 // Tests that when only the quaternion version of the absolute orientation
758 // sensor is available the provider falls back to using a fusion algorithm
759 // to provide the euler angles version.
TEST_F(PlatformSensorAndProviderTestWin,CheckDeviceOrientationEulerAnglesFallback)760 TEST_F(PlatformSensorAndProviderTestWin,
761 CheckDeviceOrientationEulerAnglesFallback) {
762 SetUnsupportedSensor(SENSOR_TYPE_INCLINOMETER_3D);
763 SetSupportedSensor(SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION);
764
765 auto sensor = CreateSensor(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES);
766 EXPECT_TRUE(sensor);
767 }
768
769 // Tests that with neither absolute orientation sensor type available
770 // the fallback logic does not generate an infinite loop.
TEST_F(PlatformSensorAndProviderTestWin,CheckDeviceOrientationFallbackFailure)771 TEST_F(PlatformSensorAndProviderTestWin,
772 CheckDeviceOrientationFallbackFailure) {
773 SetUnsupportedSensor(SENSOR_TYPE_INCLINOMETER_3D);
774 SetUnsupportedSensor(SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION);
775
776 auto euler_angles_sensor =
777 CreateSensor(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES);
778 EXPECT_FALSE(euler_angles_sensor);
779 auto quaternion_sensor =
780 CreateSensor(SensorType::ABSOLUTE_ORIENTATION_QUATERNION);
781 EXPECT_FALSE(quaternion_sensor);
782 }
783
784 } // namespace device
785