DeviceSensorsTest.java revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2014 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
5package org.chromium.content.browser;
6
7import android.content.Context;
8import android.hardware.Sensor;
9import android.hardware.SensorEventListener;
10import android.hardware.SensorManager;
11import android.os.Handler;
12import android.test.AndroidTestCase;
13import android.test.suitebuilder.annotation.SmallTest;
14
15import java.util.HashSet;
16import java.util.Set;
17
18/**
19 * Test suite for DeviceSensors.
20 */
21public class DeviceSensorsTest extends AndroidTestCase {
22
23    private DeviceSensorsForTests mDeviceSensors;
24    private MockSensorManager mMockSensorManager;
25
26    @Override
27    public void setUp() throws Exception {
28        super.setUp();
29        mMockSensorManager = new MockSensorManager();
30        mDeviceSensors = DeviceSensorsForTests.getInstance(getContext());
31        mDeviceSensors.setSensorManagerProxy(mMockSensorManager);
32    }
33
34    @SmallTest
35    public void testRegisterSensorsDeviceMotion() {
36        boolean start = mDeviceSensors.start(0, DeviceSensors.DEVICE_MOTION, 100);
37
38        assertTrue(start);
39        assertTrue("should contain all motion sensors",
40                mDeviceSensors.mActiveSensors.containsAll(
41                        DeviceSensors.DEVICE_MOTION_SENSORS));
42        assertTrue(mDeviceSensors.mDeviceMotionIsActive);
43        assertFalse(mDeviceSensors.mDeviceOrientationIsActive);
44        assertFalse(mDeviceSensors.mDeviceLightIsActive);
45
46        assertEquals(DeviceSensors.DEVICE_MOTION_SENSORS.size(),
47                mMockSensorManager.mNumRegistered);
48        assertEquals(0, mMockSensorManager.mNumUnRegistered);
49        assertEquals(DeviceSensors.DEVICE_MOTION_SENSORS.size(),
50                mDeviceSensors.getNumberActiveDeviceMotionSensors());
51    }
52
53    @SmallTest
54    public void testRegisterSensorsDeviceOrientation() {
55        boolean start = mDeviceSensors.start(0, DeviceSensors.DEVICE_ORIENTATION, 100);
56
57        assertTrue(start);
58        assertTrue("should contain all orientation sensors",
59                mDeviceSensors.mActiveSensors.containsAll(
60                        DeviceSensors.DEVICE_ORIENTATION_SENSORS));
61        assertFalse(mDeviceSensors.mDeviceMotionIsActive);
62        assertFalse(mDeviceSensors.mDeviceLightIsActive);
63        assertTrue(mDeviceSensors.mDeviceOrientationIsActive);
64
65        assertEquals(DeviceSensors.DEVICE_ORIENTATION_SENSORS.size(),
66                mMockSensorManager.mNumRegistered);
67        assertEquals(0, mMockSensorManager.mNumUnRegistered);
68    }
69
70    @SmallTest
71    public void testRegisterSensorsDeviceMotionAndOrientation() {
72        boolean startOrientation = mDeviceSensors.start(0, DeviceSensors.DEVICE_ORIENTATION, 100);
73        boolean startMotion = mDeviceSensors.start(0, DeviceSensors.DEVICE_MOTION, 100);
74
75        assertTrue(startOrientation);
76        assertTrue(startMotion);
77        assertTrue("should contain all motion sensors",
78                mDeviceSensors.mActiveSensors.containsAll(
79                        DeviceSensors.DEVICE_MOTION_SENSORS));
80        assertTrue("should contain all orientation sensors",
81                mDeviceSensors.mActiveSensors.containsAll(
82                        DeviceSensors.DEVICE_ORIENTATION_SENSORS));
83
84        Set<Integer> union = new HashSet<Integer>(
85            DeviceSensors.DEVICE_ORIENTATION_SENSORS);
86        union.addAll(DeviceSensors.DEVICE_MOTION_SENSORS);
87
88        assertEquals(union.size(), mDeviceSensors.mActiveSensors.size());
89        assertTrue(mDeviceSensors.mDeviceMotionIsActive);
90        assertTrue(mDeviceSensors.mDeviceOrientationIsActive);
91        assertFalse(mDeviceSensors.mDeviceLightIsActive);
92        assertEquals(union.size(), mMockSensorManager.mNumRegistered);
93        assertEquals(0, mMockSensorManager.mNumUnRegistered);
94        assertEquals(DeviceSensors.DEVICE_MOTION_SENSORS.size(),
95                mDeviceSensors.getNumberActiveDeviceMotionSensors());
96    }
97
98    @SmallTest
99    public void testRegisterSensorsDeviceLight() {
100        boolean start = mDeviceSensors.start(0, DeviceSensors.DEVICE_LIGHT, 100);
101
102        assertTrue(start);
103        assertTrue(mDeviceSensors.mDeviceLightIsActive);
104        assertFalse(mDeviceSensors.mDeviceMotionIsActive);
105        assertFalse(mDeviceSensors.mDeviceOrientationIsActive);
106
107        assertEquals(DeviceSensors.DEVICE_LIGHT_SENSORS.size(),
108                mMockSensorManager.mNumRegistered);
109        assertEquals(0, mMockSensorManager.mNumUnRegistered);
110    }
111
112    @SmallTest
113    public void testUnregisterSensorsDeviceMotion() {
114        mDeviceSensors.start(0, DeviceSensors.DEVICE_MOTION, 100);
115        mDeviceSensors.stop(DeviceSensors.DEVICE_MOTION);
116
117        assertTrue("should contain no sensors",
118                mDeviceSensors.mActiveSensors.isEmpty());
119        assertFalse(mDeviceSensors.mDeviceMotionIsActive);
120        assertFalse(mDeviceSensors.mDeviceOrientationIsActive);
121        assertFalse(mDeviceSensors.mDeviceLightIsActive);
122        assertEquals(DeviceSensors.DEVICE_MOTION_SENSORS.size(),
123                mMockSensorManager.mNumUnRegistered);
124        assertEquals(0, mDeviceSensors.getNumberActiveDeviceMotionSensors());
125    }
126
127    @SmallTest
128    public void testUnregisterSensorsDeviceOrientation() {
129        mDeviceSensors.start(0, DeviceSensors.DEVICE_ORIENTATION, 100);
130        mDeviceSensors.stop(DeviceSensors.DEVICE_ORIENTATION);
131
132        assertTrue("should contain no sensors",
133                mDeviceSensors.mActiveSensors.isEmpty());
134        assertFalse(mDeviceSensors.mDeviceMotionIsActive);
135        assertFalse(mDeviceSensors.mDeviceOrientationIsActive);
136        assertFalse(mDeviceSensors.mDeviceLightIsActive);
137        assertEquals(DeviceSensors.DEVICE_ORIENTATION_SENSORS.size(),
138                mMockSensorManager.mNumUnRegistered);
139    }
140
141    @SmallTest
142    public void testUnRegisterSensorsDeviceMotionAndOrientation() {
143        mDeviceSensors.start(0, DeviceSensors.DEVICE_ORIENTATION, 100);
144        mDeviceSensors.start(0, DeviceSensors.DEVICE_MOTION, 100);
145        mDeviceSensors.stop(DeviceSensors.DEVICE_MOTION);
146
147        assertTrue("should contain all orientation sensors",
148                mDeviceSensors.mActiveSensors.containsAll(
149                        DeviceSensors.DEVICE_ORIENTATION_SENSORS));
150
151        Set<Integer> diff = new HashSet<Integer>(DeviceSensors.DEVICE_MOTION_SENSORS);
152        diff.removeAll(DeviceSensors.DEVICE_ORIENTATION_SENSORS);
153
154        assertEquals(diff.size(), mMockSensorManager.mNumUnRegistered);
155
156        mDeviceSensors.stop(DeviceSensors.DEVICE_ORIENTATION);
157
158        assertTrue("should contain no sensors", mDeviceSensors.mActiveSensors.isEmpty());
159        assertEquals(diff.size() + DeviceSensors.DEVICE_ORIENTATION_SENSORS.size(),
160                mMockSensorManager.mNumUnRegistered);
161        assertEquals(0, mDeviceSensors.getNumberActiveDeviceMotionSensors());
162    }
163
164    @SmallTest
165    public void testUnregisterSensorsLight() {
166        mDeviceSensors.start(0, DeviceSensors.DEVICE_LIGHT, 100);
167        mDeviceSensors.stop(DeviceSensors.DEVICE_LIGHT);
168
169        assertTrue("should contain no sensors", mDeviceSensors.mActiveSensors.isEmpty());
170        assertFalse(mDeviceSensors.mDeviceMotionIsActive);
171        assertFalse(mDeviceSensors.mDeviceOrientationIsActive);
172        assertFalse(mDeviceSensors.mDeviceLightIsActive);
173    }
174
175    @SmallTest
176    public void testSensorChangedgotLight() {
177        boolean startLight = mDeviceSensors.start(0, DeviceSensors.DEVICE_LIGHT, 100);
178
179        assertTrue(startLight);
180        assertTrue(mDeviceSensors.mDeviceLightIsActive);
181
182        float[] values = {200};
183        mDeviceSensors.sensorChanged(Sensor.TYPE_LIGHT, values);
184        mDeviceSensors.verifyCalls("gotLight");
185        mDeviceSensors.verifyValue(200);
186    }
187
188    @SmallTest
189    public void testSensorChangedgotOrientation() {
190        boolean startOrientation = mDeviceSensors.start(0, DeviceSensors.DEVICE_ORIENTATION, 100);
191
192        assertTrue(startOrientation);
193        assertTrue(mDeviceSensors.mDeviceOrientationIsActive);
194
195        float alpha = (float) Math.PI / 4;
196        float[] values = {0, 0, (float) Math.sin(alpha / 2), (float) Math.cos(alpha / 2), -1};
197        mDeviceSensors.sensorChanged(Sensor.TYPE_ROTATION_VECTOR, values);
198        mDeviceSensors.verifyCalls("gotOrientation");
199        mDeviceSensors.verifyValuesEpsilon(Math.toDegrees(alpha), 0, 0);
200    }
201
202    @SmallTest
203    public void testSensorChangedgotAccelerationIncludingGravity() {
204        mDeviceSensors.start(0, DeviceSensors.DEVICE_MOTION, 100);
205
206        float[] values = {1, 2, 3};
207        mDeviceSensors.sensorChanged(Sensor.TYPE_ACCELEROMETER, values);
208        mDeviceSensors.verifyCalls("gotAccelerationIncludingGravity");
209        mDeviceSensors.verifyValues(1, 2, 3);
210    }
211
212    @SmallTest
213    public void testSensorChangedgotAcceleration() {
214        mDeviceSensors.start(0, DeviceSensors.DEVICE_MOTION, 100);
215
216        float[] values = {1, 2, 3};
217        mDeviceSensors.sensorChanged(Sensor.TYPE_LINEAR_ACCELERATION, values);
218        mDeviceSensors.verifyCalls("gotAcceleration");
219        mDeviceSensors.verifyValues(1, 2, 3);
220    }
221
222    @SmallTest
223    public void testSensorChangedgotRotationRate() {
224        mDeviceSensors.start(0, DeviceSensors.DEVICE_MOTION, 100);
225
226        float[] values = {1, 2, 3};
227        mDeviceSensors.sensorChanged(Sensor.TYPE_GYROSCOPE, values);
228        mDeviceSensors.verifyCalls("gotRotationRate");
229        mDeviceSensors.verifyValues(1, 2, 3);
230    }
231
232    @SmallTest
233    public void testSensorChangedgotOrientationAndAcceleration() {
234        boolean startOrientation = mDeviceSensors.start(0, DeviceSensors.DEVICE_ORIENTATION, 100);
235        boolean startMotion = mDeviceSensors.start(0, DeviceSensors.DEVICE_MOTION, 100);
236
237        assertTrue(startOrientation);
238        assertTrue(startMotion);
239        assertTrue(mDeviceSensors.mDeviceMotionIsActive);
240        assertTrue(mDeviceSensors.mDeviceOrientationIsActive);
241
242        float alpha = (float) Math.PI / 4;
243        float[] values = {0, 0, (float) Math.sin(alpha / 2), (float) Math.cos(alpha / 2), -1};
244        mDeviceSensors.sensorChanged(Sensor.TYPE_ROTATION_VECTOR, values);
245        mDeviceSensors.verifyCalls("gotOrientation");
246        mDeviceSensors.verifyValuesEpsilon(Math.toDegrees(alpha), 0, 0);
247
248        float[] values2 = {1, 2, 3};
249        mDeviceSensors.sensorChanged(Sensor.TYPE_ACCELEROMETER, values2);
250        mDeviceSensors.verifyCalls("gotOrientation" + "gotAccelerationIncludingGravity");
251        mDeviceSensors.verifyValues(1, 2, 3);
252    }
253
254
255    // Tests for correct Device Orientation angles.
256
257    @SmallTest
258    public void testOrientationAnglesFromRotationMatrixIdentity() {
259        float[] gravity = {0, 0, 1};
260        float[] magnetic = {0, 1, 0};
261        double[] expectedAngles = {0, 0, 0};
262
263        verifyOrientationAngles(gravity, magnetic, expectedAngles);
264    }
265
266    @SmallTest
267    public void testOrientationAnglesFromRotationMatrix45DegreesX() {
268        float[] gravity = {0, (float) Math.sin(Math.PI / 4), (float) Math.cos(Math.PI / 4)};
269        float[] magnetic = {0, 1, 0};
270        double[] expectedAngles = {0, Math.PI / 4, 0};
271
272        verifyOrientationAngles(gravity, magnetic, expectedAngles);
273    }
274
275    @SmallTest
276    public void testOrientationAnglesFromRotationMatrix45DegreesY() {
277        float[] gravity = {-(float) Math.sin(Math.PI / 4), 0, (float) Math.cos(Math.PI / 4)};
278        float[] magnetic = {0, 1, 0};
279        double[] expectedAngles = {0, 0, Math.PI / 4};
280
281        verifyOrientationAngles(gravity, magnetic, expectedAngles);
282    }
283
284    @SmallTest
285    public void testOrientationAnglesFromRotationMatrix45DegreesZ() {
286        float[] gravity = {0, 0, 1};
287        float[] magnetic = {(float) Math.sin(Math.PI / 4), (float) Math.cos(Math.PI / 4), 0};
288        double[] expectedAngles = {Math.PI / 4, 0, 0};
289
290        verifyOrientationAngles(gravity, magnetic, expectedAngles);
291    }
292
293    @SmallTest
294    public void testOrientationAnglesFromRotationMatrixGimbalLock() {
295        float[] gravity = {0, 1, 0};
296        float[] magnetic = {(float) Math.sin(Math.PI / 4), 0, -(float) Math.cos(Math.PI / 4)};
297        double[] expectedAngles = {Math.PI / 4, Math.PI / 2, 0};  // favor yaw instead of roll
298
299        verifyOrientationAngles(gravity, magnetic, expectedAngles);
300    }
301
302    @SmallTest
303    public void testOrientationAnglesFromRotationMatrixPitchGreaterThan90() {
304        final double largePitchAngle = Math.PI / 2 + Math.PI / 4;
305        float[] gravity = {0, (float) Math.cos(largePitchAngle - Math.PI / 2),
306                -(float) Math.sin(largePitchAngle - Math.PI / 2)};
307        float[] magnetic = {0, 0, -1};
308        double[] expectedAngles = {0, largePitchAngle, 0};
309
310        verifyOrientationAngles(gravity, magnetic, expectedAngles);
311    }
312
313    @SmallTest
314    public void testOrientationAnglesFromRotationMatrixRoll90() {
315        float[] gravity = {-1, 0, 0};
316        float[] magnetic = {0, 1, 0};
317        double[] expectedAngles = {Math.PI, -Math.PI, -Math.PI / 2};
318
319        verifyOrientationAngles(gravity, magnetic, expectedAngles);
320    }
321
322    /**
323     * Helper method for verifying angles obtained from rotation matrix.
324     *
325     * @param gravity
326     *        gravity vector in the device frame
327     * @param magnetic
328     *        magnetic field vector in the device frame
329     * @param expectedAngles
330     *        expectedAngles[0] rotation angle in radians around the Z-axis
331     *        expectedAngles[1] rotation angle in radians around the X-axis
332     *        expectedAngles[2] rotation angle in radians around the Y-axis
333     */
334    private void verifyOrientationAngles(float[] gravity, float[] magnetic,
335            double[] expectedAngles) {
336        float[] r = new float[9];
337        double[] values = new double[3];
338        SensorManager.getRotationMatrix(r, null, gravity, magnetic);
339        mDeviceSensors.computeDeviceOrientationFromRotationMatrix(r, values);
340
341        assertEquals(expectedAngles.length, values.length);
342        final double epsilon = 0.001;
343        for (int i = 0; i < expectedAngles.length; ++i) {
344            assertEquals(expectedAngles[i], values[i], epsilon);
345        }
346
347    }
348
349    // -- End Tests for correct Device Orientation angles.
350
351    private static class DeviceSensorsForTests extends DeviceSensors {
352
353        private double mValue1 = 0;
354        private double mValue2 = 0;
355        private double mValue3 = 0;
356        private String mCalls = "";
357
358        private DeviceSensorsForTests(Context context) {
359            super(context);
360        }
361
362        static DeviceSensorsForTests getInstance(Context context) {
363            return new DeviceSensorsForTests(context);
364        }
365
366        private void verifyValue(double v1) {
367            assertEquals(v1, mValue1);
368        }
369
370        private void verifyValues(double v1, double v2, double v3) {
371            assertEquals(v1, mValue1);
372            assertEquals(v2, mValue2);
373            assertEquals(v3, mValue3);
374        }
375
376        private void verifyValuesEpsilon(double v1, double v2, double v3) {
377            assertEquals(v1, mValue1, 0.1);
378            assertEquals(v2, mValue2, 0.1);
379            assertEquals(v3, mValue3, 0.1);
380        }
381
382        private void verifyCalls(String names) {
383            assertEquals(mCalls, names);
384        }
385
386        @Override
387        protected void gotLight(double light) {
388            mValue1 = light;
389            mCalls = mCalls.concat("gotLight");
390        }
391
392        @Override
393        protected void gotOrientation(double alpha, double beta, double gamma) {
394            mValue1 = alpha;
395            mValue2 = beta;
396            mValue3 = gamma;
397            mCalls = mCalls.concat("gotOrientation");
398        }
399
400        @Override
401        protected void gotAcceleration(double x, double y, double z) {
402            mValue1 = x;
403            mValue2 = y;
404            mValue3 = z;
405            mCalls = mCalls.concat("gotAcceleration");
406        }
407
408        @Override
409        protected void gotAccelerationIncludingGravity(double x, double y, double z) {
410            mValue1 = x;
411            mValue2 = y;
412            mValue3 = z;
413            mCalls = mCalls.concat("gotAccelerationIncludingGravity");
414        }
415
416        @Override
417        protected void gotRotationRate(double alpha, double beta, double gamma) {
418            mValue1 = alpha;
419            mValue2 = beta;
420            mValue3 = gamma;
421            mCalls = mCalls.concat("gotRotationRate");
422        }
423    }
424
425    private static class MockSensorManager implements
426            DeviceSensors.SensorManagerProxy {
427
428        private int mNumRegistered = 0;
429        private int mNumUnRegistered = 0;
430
431        private MockSensorManager() {
432        }
433
434        @Override
435        public boolean registerListener(SensorEventListener listener, int sensorType, int rate,
436                Handler handler) {
437            mNumRegistered++;
438            return true;
439        }
440
441        @Override
442        public void unregisterListener(SensorEventListener listener, int sensorType) {
443            mNumUnRegistered++;
444        }
445    }
446}
447