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