OLD | NEW |
(Empty) | |
| 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 package org.chromium.device.sensors; |
| 6 |
| 7 import static org.junit.Assert.assertEquals; |
| 8 import static org.junit.Assert.assertNotNull; |
| 9 import static org.junit.Assert.assertNull; |
| 10 import static org.mockito.ArgumentMatchers.any; |
| 11 import static org.mockito.ArgumentMatchers.anyInt; |
| 12 import static org.mockito.Mockito.doAnswer; |
| 13 import static org.mockito.Mockito.doReturn; |
| 14 import static org.mockito.Mockito.mock; |
| 15 import static org.mockito.Mockito.never; |
| 16 import static org.mockito.Mockito.spy; |
| 17 import static org.mockito.Mockito.times; |
| 18 import static org.mockito.Mockito.verify; |
| 19 |
| 20 import android.content.Context; |
| 21 import android.hardware.Sensor; |
| 22 import android.hardware.SensorEvent; |
| 23 import android.hardware.SensorEventListener; |
| 24 import android.hardware.SensorManager; |
| 25 import android.os.Handler; |
| 26 import android.util.SparseArray; |
| 27 |
| 28 import org.chromium.base.test.util.Feature; |
| 29 import org.chromium.mojom.device.mojom.ReportingMode; |
| 30 import org.chromium.mojom.device.mojom.SensorInitParams; |
| 31 import org.chromium.mojom.device.mojom.SensorType; |
| 32 import org.chromium.testing.local.LocalRobolectricTestRunner; |
| 33 |
| 34 import org.junit.Before; |
| 35 import org.junit.Test; |
| 36 import org.junit.runner.RunWith; |
| 37 import org.mockito.Mock; |
| 38 import org.mockito.MockitoAnnotations; |
| 39 import org.mockito.invocation.InvocationOnMock; |
| 40 import org.mockito.stubbing.Answer; |
| 41 import org.robolectric.annotation.Config; |
| 42 |
| 43 import java.lang.reflect.Constructor; |
| 44 import java.lang.reflect.InvocationTargetException; |
| 45 import java.nio.ByteBuffer; |
| 46 import java.nio.ByteOrder; |
| 47 import java.util.ArrayList; |
| 48 import java.util.List; |
| 49 |
| 50 /** |
| 51 * Unit tests for PlatformSensor and PlatformSensorProvider. |
| 52 */ |
| 53 @RunWith(LocalRobolectricTestRunner.class) |
| 54 @Config(manifest = Config.NONE) |
| 55 public class PlatformSensorAndProviderTest { |
| 56 @Mock |
| 57 private Context mContext; |
| 58 @Mock |
| 59 private SensorManager mSensorManager; |
| 60 @Mock |
| 61 private PlatformSensorProvider mPlatformSensorProvider; |
| 62 private ByteBuffer mSharedBuffer; |
| 63 private final SparseArray<List<Sensor>> mMockSensors = new SparseArray<>(); |
| 64 private static final long PLATFORM_SENSOR_ANDROID = 123456789L; |
| 65 private static final long PLATFORM_SENSOR_TIMESTAMP = 314159265358979L; |
| 66 private static final double MILLISECONDS_IN_NANOSECOND = 0.000001d; |
| 67 |
| 68 /** |
| 69 * Class that overrides thread management callbacks for testing purposes. |
| 70 */ |
| 71 private static class TestPlatformSensorProvider extends PlatformSensorProvid
er { |
| 72 public TestPlatformSensorProvider(Context context) { |
| 73 super(context); |
| 74 } |
| 75 |
| 76 @Override |
| 77 public Handler getHandler() { |
| 78 return new Handler(); |
| 79 } |
| 80 |
| 81 @Override |
| 82 protected void startSensorThread() {} |
| 83 |
| 84 @Override |
| 85 protected void stopSensorThread() {} |
| 86 } |
| 87 |
| 88 /** |
| 89 * Class that overrides native callbacks for testing purposes. |
| 90 */ |
| 91 private static class TestPlatformSensor extends PlatformSensor { |
| 92 public TestPlatformSensor( |
| 93 Sensor sensor, int readingCount, PlatformSensorProvider provider
) { |
| 94 super(sensor, readingCount, provider); |
| 95 } |
| 96 |
| 97 @Override |
| 98 protected void sensorReadingChanged() {} |
| 99 @Override |
| 100 protected void sensorError() {} |
| 101 } |
| 102 |
| 103 @Before |
| 104 public void setUp() { |
| 105 MockitoAnnotations.initMocks(this); |
| 106 // Remove all mock sensors before the test. |
| 107 mMockSensors.clear(); |
| 108 doReturn(mSensorManager).when(mContext).getSystemService(Context.SENSOR_
SERVICE); |
| 109 doAnswer( |
| 110 new Answer<List<Sensor>>() { |
| 111 @Override |
| 112 public List<Sensor> answer(final InvocationOnMock invocation
) |
| 113 throws Throwable { |
| 114 return getMockSensors((int) (Integer) (invocation.getArg
uments())[0]); |
| 115 } |
| 116 }) |
| 117 .when(mSensorManager) |
| 118 .getSensorList(anyInt()); |
| 119 doReturn(mSensorManager).when(mPlatformSensorProvider).getSensorManager(
); |
| 120 doReturn(new Handler()).when(mPlatformSensorProvider).getHandler(); |
| 121 // By default, allow successful registration of SensorEventListeners. |
| 122 doReturn(true) |
| 123 .when(mSensorManager) |
| 124 .registerListener(any(SensorEventListener.class), any(Sensor.cla
ss), anyInt(), |
| 125 any(Handler.class)); |
| 126 } |
| 127 |
| 128 /** |
| 129 * Test that PlatformSensorProvider cannot create sensors if sensor manager
is null. |
| 130 */ |
| 131 @Test |
| 132 @Feature({"PlatformSensorProvider"}) |
| 133 public void testNullSensorManager() { |
| 134 doReturn(null).when(mContext).getSystemService(Context.SENSOR_SERVICE); |
| 135 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext
); |
| 136 PlatformSensor sensor = provider.createSensor(SensorType.AMBIENT_LIGHT); |
| 137 assertNull(sensor); |
| 138 } |
| 139 |
| 140 /** |
| 141 * Test that PlatformSensorProvider cannot create sensors that are not suppo
rted. |
| 142 */ |
| 143 @Test |
| 144 @Feature({"PlatformSensorProvider"}) |
| 145 public void testSensorNotSupported() { |
| 146 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext
); |
| 147 PlatformSensor sensor = provider.createSensor(SensorType.AMBIENT_LIGHT); |
| 148 assertNull(sensor); |
| 149 } |
| 150 |
| 151 /** |
| 152 * Test that PlatformSensorProvider maps device::SensorType to android.hardw
are.Sensor.TYPE_*. |
| 153 */ |
| 154 @Test |
| 155 @Feature({"PlatformSensorProvider"}) |
| 156 public void testSensorTypeMappings() { |
| 157 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext
); |
| 158 provider.createSensor(SensorType.AMBIENT_LIGHT); |
| 159 verify(mSensorManager).getSensorList(Sensor.TYPE_LIGHT); |
| 160 provider.createSensor(SensorType.ACCELEROMETER); |
| 161 verify(mSensorManager).getSensorList(Sensor.TYPE_ACCELEROMETER); |
| 162 provider.createSensor(SensorType.LINEAR_ACCELERATION); |
| 163 verify(mSensorManager).getSensorList(Sensor.TYPE_LINEAR_ACCELERATION); |
| 164 provider.createSensor(SensorType.GYROSCOPE); |
| 165 verify(mSensorManager).getSensorList(Sensor.TYPE_GYROSCOPE); |
| 166 provider.createSensor(SensorType.MAGNETOMETER); |
| 167 verify(mSensorManager).getSensorList(Sensor.TYPE_MAGNETIC_FIELD); |
| 168 } |
| 169 |
| 170 /** |
| 171 * Test that PlatformSensorProvider can create sensors that are supported. |
| 172 */ |
| 173 @Test |
| 174 @Feature({"PlatformSensorProvider"}) |
| 175 public void testSensorSupported() { |
| 176 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_LIGHT, |
| 177 SensorType.AMBIENT_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE); |
| 178 assertNotNull(sensor); |
| 179 } |
| 180 |
| 181 /** |
| 182 * Test that PlatformSensor notifies PlatformSensorProvider when it starts (
stops) polling, |
| 183 * and SensorEventListener is registered (unregistered) to sensor manager. |
| 184 */ |
| 185 @Test |
| 186 @Feature({"PlatformSensor"}) |
| 187 public void testSensorStartStop() { |
| 188 addMockSensor(50000, Sensor.TYPE_ACCELEROMETER, Sensor.REPORTING_MODE_CO
NTINUOUS); |
| 189 PlatformSensor sensor = |
| 190 PlatformSensor.create(Sensor.TYPE_ACCELEROMETER, 3, mPlatformSen
sorProvider); |
| 191 assertNotNull(sensor); |
| 192 |
| 193 sensor.startSensor(5); |
| 194 sensor.stopSensor(); |
| 195 |
| 196 // Multiple start invocations. |
| 197 sensor.startSensor(1); |
| 198 sensor.startSensor(2); |
| 199 sensor.startSensor(3); |
| 200 // Same frequency, should not restart sensor |
| 201 sensor.startSensor(3); |
| 202 |
| 203 // Started polling with 5, 1, 2 and 3 Hz frequency. |
| 204 verify(mPlatformSensorProvider, times(4)).getHandler(); |
| 205 verify(mPlatformSensorProvider, times(4)).sensorStarted(sensor); |
| 206 verify(mSensorManager, times(4)) |
| 207 .registerListener(any(SensorEventListener.class), any(Sensor.cla
ss), anyInt(), |
| 208 any(Handler.class)); |
| 209 |
| 210 sensor.stopSensor(); |
| 211 sensor.stopSensor(); |
| 212 verify(mPlatformSensorProvider, times(3)).sensorStopped(sensor); |
| 213 verify(mSensorManager, times(4)) |
| 214 .unregisterListener(any(SensorEventListener.class), any(Sensor.c
lass)); |
| 215 } |
| 216 |
| 217 /** |
| 218 * Test that PlatformSensorProvider is notified when PlatformSensor starts a
nd in case of |
| 219 * failure, tells PlatformSensorProvider that the sensor is stopped, so that
polling thread |
| 220 * can be stopped. |
| 221 */ |
| 222 @Test |
| 223 @Feature({"PlatformSensor"}) |
| 224 public void testSensorStartFails() { |
| 225 addMockSensor(50000, Sensor.TYPE_ACCELEROMETER, Sensor.REPORTING_MODE_CO
NTINUOUS); |
| 226 PlatformSensor sensor = |
| 227 PlatformSensor.create(Sensor.TYPE_ACCELEROMETER, 3, mPlatformSen
sorProvider); |
| 228 assertNotNull(sensor); |
| 229 |
| 230 doReturn(false) |
| 231 .when(mSensorManager) |
| 232 .registerListener(any(SensorEventListener.class), any(Sensor.cla
ss), anyInt(), |
| 233 any(Handler.class)); |
| 234 |
| 235 sensor.startSensor(5); |
| 236 verify(mPlatformSensorProvider, times(1)).sensorStarted(sensor); |
| 237 verify(mPlatformSensorProvider, times(1)).sensorStopped(sensor); |
| 238 verify(mPlatformSensorProvider, times(1)).getHandler(); |
| 239 } |
| 240 |
| 241 /** |
| 242 * Test that PlatformSensor correctly checks supported configuration. |
| 243 */ |
| 244 @Test |
| 245 @Feature({"PlatformSensor"}) |
| 246 public void testSensorConfiguration() { |
| 247 // 5Hz min delay |
| 248 PlatformSensor sensor = createPlatformSensor(200000, Sensor.TYPE_ACCELER
OMETER, |
| 249 SensorType.ACCELEROMETER, Sensor.REPORTING_MODE_CONTINUOUS); |
| 250 assertEquals(true, sensor.checkSensorConfiguration(5)); |
| 251 assertEquals(false, sensor.checkSensorConfiguration(6)); |
| 252 } |
| 253 |
| 254 /** |
| 255 * Test that PlatformSensor correctly returns its reporting mode. |
| 256 */ |
| 257 @Test |
| 258 @Feature({"PlatformSensor"}) |
| 259 public void testSensorOnChangeReportingMode() { |
| 260 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_LIGHT, |
| 261 SensorType.AMBIENT_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE); |
| 262 assertEquals(ReportingMode.ON_CHANGE, sensor.getReportingMode()); |
| 263 } |
| 264 |
| 265 /** |
| 266 * Test that PlatformSensor doesn't notify client about sensor reading chang
es when |
| 267 * sensor reporting mode is ReportingMode.CONTINUOUS. |
| 268 */ |
| 269 @Test |
| 270 @Feature({"PlatformSensor"}) |
| 271 public void testSensorNotifierIsNotCalled() { |
| 272 TestPlatformSensor sensor = createTestPlatformSensor( |
| 273 50000, Sensor.TYPE_ACCELEROMETER, 3, Sensor.REPORTING_MODE_CONTI
NUOUS); |
| 274 initPlatformSensor(sensor, SensorInitParams.READ_BUFFER_SIZE); |
| 275 TestPlatformSensor spySensor = spy(sensor); |
| 276 SensorEvent event = createFakeEvent(3); |
| 277 assertNotNull(event); |
| 278 spySensor.onSensorChanged(event); |
| 279 verify(spySensor, never()).sensorReadingChanged(); |
| 280 } |
| 281 |
| 282 /** |
| 283 * Test that shared buffer is correctly populated from SensorEvent. |
| 284 */ |
| 285 @Test |
| 286 @Feature({"PlatformSensor"}) |
| 287 public void testSensorBufferFromEvent() { |
| 288 TestPlatformSensor sensor = createTestPlatformSensor( |
| 289 50000, Sensor.TYPE_LIGHT, 1, Sensor.REPORTING_MODE_ON_CHANGE); |
| 290 initPlatformSensor(sensor, SensorInitParams.READ_BUFFER_SIZE); |
| 291 TestPlatformSensor spySensor = spy(sensor); |
| 292 SensorEvent event = createFakeEvent(1); |
| 293 assertNotNull(event); |
| 294 spySensor.onSensorChanged(event); |
| 295 verify(spySensor, times(1)).sensorReadingChanged(); |
| 296 // Verify that timestamp correctly stored in buffer. |
| 297 assertEquals(MILLISECONDS_IN_NANOSECOND * PLATFORM_SENSOR_TIMESTAMP, |
| 298 mSharedBuffer.getDouble(), MILLISECONDS_IN_NANOSECOND); |
| 299 // Verify illuminance value is correctly stored in buffer and precision
is not lost. |
| 300 assertEquals(1.0d + MILLISECONDS_IN_NANOSECOND, mSharedBuffer.getDouble(
), |
| 301 MILLISECONDS_IN_NANOSECOND); |
| 302 } |
| 303 |
| 304 /** |
| 305 * Test that PlatformSensor notifies client when there is an error. |
| 306 */ |
| 307 @Test |
| 308 @Feature({"PlatformSensor"}) |
| 309 public void testSensorInvalidReadingSize() { |
| 310 TestPlatformSensor sensor = createTestPlatformSensor( |
| 311 50000, Sensor.TYPE_ACCELEROMETER, 3, Sensor.REPORTING_MODE_CONTI
NUOUS); |
| 312 initPlatformSensor(sensor, SensorInitParams.READ_BUFFER_SIZE); |
| 313 TestPlatformSensor spySensor = spy(sensor); |
| 314 // Accelerometer requires 3 reading values x,y and z, create fake event
with 1 reading |
| 315 // value. |
| 316 SensorEvent event = createFakeEvent(1); |
| 317 assertNotNull(event); |
| 318 spySensor.onSensorChanged(event); |
| 319 verify(spySensor, times(1)).sensorError(); |
| 320 } |
| 321 |
| 322 /** |
| 323 * Test that PlatformSensor notifies client when there is an error. |
| 324 */ |
| 325 @Test |
| 326 @Feature({"PlatformSensor"}) |
| 327 public void testSensorInvalidBufferSize() { |
| 328 TestPlatformSensor sensor = createTestPlatformSensor( |
| 329 50000, Sensor.TYPE_ACCELEROMETER, 3, Sensor.REPORTING_MODE_CONTI
NUOUS); |
| 330 // Create buffer that doesn't have enough capacity to hold sensor readin
g values. |
| 331 initPlatformSensor(sensor, 2); |
| 332 TestPlatformSensor spySensor = spy(sensor); |
| 333 SensorEvent event = createFakeEvent(3); |
| 334 assertNotNull(event); |
| 335 spySensor.onSensorChanged(event); |
| 336 verify(spySensor, times(1)).sensorError(); |
| 337 } |
| 338 |
| 339 /** |
| 340 * Test that multiple PlatformSensor instances correctly register (unregiste
r) to |
| 341 * sensor manager and notify PlatformSensorProvider when they start (stop) p
olling for data. |
| 342 */ |
| 343 @Test |
| 344 @Feature({"PlatformSensor"}) |
| 345 public void testMultipleSensorTypeInstances() { |
| 346 addMockSensor(200000, Sensor.TYPE_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE
); |
| 347 addMockSensor(50000, Sensor.TYPE_ACCELEROMETER, Sensor.REPORTING_MODE_CO
NTINUOUS); |
| 348 |
| 349 TestPlatformSensorProvider spyProvider = spy(new TestPlatformSensorProvi
der(mContext)); |
| 350 PlatformSensor lightSensor = PlatformSensor.create(Sensor.TYPE_LIGHT, 1,
spyProvider); |
| 351 assertNotNull(lightSensor); |
| 352 |
| 353 PlatformSensor accelerometerSensor = |
| 354 PlatformSensor.create(Sensor.TYPE_ACCELEROMETER, 3, spyProvider)
; |
| 355 assertNotNull(accelerometerSensor); |
| 356 |
| 357 lightSensor.startSensor(3); |
| 358 accelerometerSensor.startSensor(10); |
| 359 lightSensor.stopSensor(); |
| 360 accelerometerSensor.stopSensor(); |
| 361 |
| 362 verify(spyProvider, times(2)).getHandler(); |
| 363 verify(spyProvider, times(1)).sensorStarted(lightSensor); |
| 364 verify(spyProvider, times(1)).sensorStarted(accelerometerSensor); |
| 365 verify(spyProvider, times(1)).sensorStopped(lightSensor); |
| 366 verify(spyProvider, times(1)).sensorStopped(accelerometerSensor); |
| 367 verify(spyProvider, times(1)).startSensorThread(); |
| 368 verify(spyProvider, times(1)).stopSensorThread(); |
| 369 verify(mSensorManager, times(2)) |
| 370 .registerListener(any(SensorEventListener.class), any(Sensor.cla
ss), anyInt(), |
| 371 any(Handler.class)); |
| 372 verify(mSensorManager, times(2)) |
| 373 .unregisterListener(any(SensorEventListener.class), any(Sensor.c
lass)); |
| 374 } |
| 375 |
| 376 /** |
| 377 * Creates fake event. The SensorEvent constructor is not accessible outside
android.hardware |
| 378 * package, therefore, java reflection is used to make constructor accessibl
e to construct |
| 379 * SensorEvent instance. |
| 380 */ |
| 381 private SensorEvent createFakeEvent(int readingValuesNum) { |
| 382 try { |
| 383 Constructor<SensorEvent> sensorEventConstructor = |
| 384 SensorEvent.class.getDeclaredConstructor(Integer.TYPE); |
| 385 sensorEventConstructor.setAccessible(true); |
| 386 SensorEvent event = sensorEventConstructor.newInstance(readingValues
Num); |
| 387 event.timestamp = PLATFORM_SENSOR_TIMESTAMP; |
| 388 for (int i = 0; i < readingValuesNum; ++i) { |
| 389 event.values[i] = (float) (i + 1.0f + MILLISECONDS_IN_NANOSECOND
); |
| 390 } |
| 391 return event; |
| 392 } catch (InvocationTargetException | NoSuchMethodException | Instantiati
onException |
| 393 | IllegalAccessException e) { |
| 394 return null; |
| 395 } |
| 396 } |
| 397 |
| 398 private void initPlatformSensor(PlatformSensor sensor, long readingSize) { |
| 399 mSharedBuffer = ByteBuffer.allocate((int) readingSize); |
| 400 mSharedBuffer.order(ByteOrder.nativeOrder()); |
| 401 sensor.initPlatformSensorAndroid(PLATFORM_SENSOR_ANDROID, mSharedBuffer)
; |
| 402 } |
| 403 |
| 404 private void addMockSensor(long minDelayUsec, int sensorType, int reportingM
ode) { |
| 405 List<Sensor> mockSensorList = new ArrayList<Sensor>(); |
| 406 mockSensorList.add(createMockSensor(minDelayUsec, sensorType, reportingM
ode)); |
| 407 mMockSensors.put(sensorType, mockSensorList); |
| 408 } |
| 409 |
| 410 private Sensor createMockSensor(long minDelayUsec, int sensorType, int repor
tingMode) { |
| 411 Sensor mockSensor = mock(Sensor.class); |
| 412 doReturn((int) minDelayUsec).when(mockSensor).getMinDelay(); |
| 413 doReturn(reportingMode).when(mockSensor).getReportingMode(); |
| 414 doReturn(sensorType).when(mockSensor).getType(); |
| 415 return mockSensor; |
| 416 } |
| 417 |
| 418 private List<Sensor> getMockSensors(int sensorType) { |
| 419 if (mMockSensors.indexOfKey(sensorType) >= 0) { |
| 420 return mMockSensors.get(sensorType); |
| 421 } |
| 422 return new ArrayList<Sensor>(); |
| 423 } |
| 424 |
| 425 private PlatformSensor createPlatformSensor( |
| 426 long minDelayUsec, int androidSensorType, int mojoSensorType, int re
portingMode) { |
| 427 addMockSensor(minDelayUsec, androidSensorType, reportingMode); |
| 428 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext
); |
| 429 return provider.createSensor(mojoSensorType); |
| 430 } |
| 431 |
| 432 private TestPlatformSensor createTestPlatformSensor( |
| 433 long minDelayUsec, int androidSensorType, int readingCount, int repo
rtingMode) { |
| 434 return new TestPlatformSensor( |
| 435 createMockSensor(minDelayUsec, androidSensorType, reportingMode)
, readingCount, |
| 436 mPlatformSensorProvider); |
| 437 } |
| 438 } |
OLD | NEW |