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