Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(699)

Side by Side Diff: device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorProviderTest.java

Issue 2284613002: [sensors] Android platform adaptation for Generic Sensor API (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixes for Tim's comments. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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.doNothing;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.never;
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.SensorReadBuffer;
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.Field;
44 import java.lang.reflect.Modifier;
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 PlatformSensorProviderTest {
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 @Before
69 public void setUp() {
70 MockitoAnnotations.initMocks(this);
71 // Remove all mock sensors before the test.
72 mMockSensors.clear();
73 doReturn(mSensorManager).when(mContext).getSystemService(Context.SENSOR_ SERVICE);
74 doAnswer(new Answer<List<Sensor>>() {
75 @Override
76 public List<Sensor> answer(final InvocationOnMock invocation) throws Throwable {
77 return getMockSensors((int) (Integer) (invocation.getArguments() )[0]);
78 }
79 })
timvolodine 2016/09/07 14:51:06 is the indentation here correct? (looks a bit weir
Ted C 2016/09/07 18:12:24 I would do: doAnswer( new Answer<List<Sen
shalamov 2016/09/07 18:49:18 Thanks, I will format it manually.
shalamov 2016/09/08 13:40:49 Done.
80 .when(mSensorManager)
81 .getSensorList(anyInt());
82 doReturn(mSensorManager).when(mPlatformSensorProvider).getSensorManager( );
83 doReturn(new Handler()).when(mPlatformSensorProvider).getHandler();
84 // By default, allow successful registration of SensorEventListeners.
85 doReturn(true)
86 .when(mSensorManager)
87 .registerListener(any(SensorEventListener.class), any(Sensor.cla ss), anyInt(),
88 any(Handler.class));
89 doNothing().when(mPlatformSensorProvider).sensorStarted(any(PlatformSens or.class));
90 doNothing().when(mPlatformSensorProvider).sensorStopped(any(PlatformSens or.class));
91 }
92
93 /**
94 * Test that PlatformSensorProvider cannot create sensors if sensor manager is null.
95 */
96 @Test
97 @Feature({"PlatformSensorProvider"})
98 public void testNullSensorManager() {
99 doReturn(null).when(mContext).getSystemService(Context.SENSOR_SERVICE);
100 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext );
101 PlatformSensor sensor = provider.createSensor(SensorType.AMBIENT_LIGHT);
102 assertNull(sensor);
103 }
104
105 /**
106 * Test that PlatformSensorProvider cannot create sensors that are not suppo rted.
107 */
108 @Test
109 @Feature({"PlatformSensorProvider"})
110 public void testSensorNotSupported() {
111 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext );
112 PlatformSensor sensor = provider.createSensor(SensorType.AMBIENT_LIGHT);
113 assertNull(sensor);
114 }
115
116 /**
117 * Test that PlatformSensorProvider maps device::SensorType to android.hardw are.Sensor.TYPE_*.
118 */
119 @Test
120 @Feature({"PlatformSensorProvider"})
121 public void testSensorTypeMappings() {
122 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext );
123 provider.createSensor(SensorType.AMBIENT_LIGHT);
124 verify(mSensorManager).getSensorList(Sensor.TYPE_LIGHT);
125 provider.createSensor(SensorType.ACCELEROMETER);
126 verify(mSensorManager).getSensorList(Sensor.TYPE_ACCELEROMETER);
127 provider.createSensor(SensorType.LINEAR_ACCELERATION);
128 verify(mSensorManager).getSensorList(Sensor.TYPE_LINEAR_ACCELERATION);
129 provider.createSensor(SensorType.GYROSCOPE);
130 verify(mSensorManager).getSensorList(Sensor.TYPE_GYROSCOPE);
131 provider.createSensor(SensorType.MAGNETOMETER);
132 verify(mSensorManager).getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
133 }
134
135 /**
136 * Test that PlatformSensorProvider can create sensors that are supported.
137 */
138 @Test
139 @Feature({"PlatformSensorProvider"})
140 public void testSensorSupported() {
141 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_LIGHT,
142 SensorType.AMBIENT_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE);
143 assertNotNull(sensor);
144 }
145
146 /**
147 * Test that PlatformSensor notifies PlatformSensorProvider when it starts ( stops) polling,
148 * and SensorEventListener is registered (unregistered) to sensor manager.
149 */
150 @Test
151 @Feature({"PlatformSensor"})
152 public void testSensorStartStop() {
153 addMockSensor(50000, Sensor.TYPE_ACCELEROMETER, Sensor.REPORTING_MODE_CO NTINUOUS);
154 PlatformSensor sensor =
155 PlatformSensor.create(Sensor.TYPE_ACCELEROMETER, 3, mPlatformSen sorProvider);
156 assertNotNull(sensor);
157
158 sensor.startSensor(5);
159 sensor.stopSensor();
160
161 // Multiple start invocations.
162 sensor.startSensor(1);
163 sensor.startSensor(2);
164 sensor.startSensor(3);
165 // Same frequency, should not restart sensor
166 sensor.startSensor(3);
167
168 // Started polling with 5, 1, 2 and 3 Hz frequency.
169 verify(mPlatformSensorProvider, times(4)).getHandler();
170 verify(mPlatformSensorProvider, times(4)).sensorStarted(sensor);
171 verify(mSensorManager, times(4))
172 .registerListener(any(SensorEventListener.class), any(Sensor.cla ss), anyInt(),
173 any(Handler.class));
174
175 sensor.stopSensor();
176 sensor.stopSensor();
177 verify(mPlatformSensorProvider, times(3)).sensorStopped(sensor);
178 verify(mSensorManager, times(4))
179 .unregisterListener(any(SensorEventListener.class), any(Sensor.c lass));
180 }
181
182 /**
183 * Test that PlatformSensorProvider is notified when PlatformSensor starts a nd in case of
184 * failure, tells PlatformSensorProvider that the sensor is stopped, so that polling thread
185 * can be stopped.
186 */
187 @Test
188 @Feature({"PlatformSensor"})
189 public void testSensorStartFails() {
190 addMockSensor(50000, Sensor.TYPE_ACCELEROMETER, Sensor.REPORTING_MODE_CO NTINUOUS);
191 PlatformSensor sensor =
192 PlatformSensor.create(Sensor.TYPE_ACCELEROMETER, 3, mPlatformSen sorProvider);
193 assertNotNull(sensor);
194
195 doReturn(false)
196 .when(mSensorManager)
197 .registerListener(any(SensorEventListener.class), any(Sensor.cla ss), anyInt(),
198 any(Handler.class));
199
200 sensor.startSensor(5);
201 verify(mPlatformSensorProvider, times(1)).sensorStarted(sensor);
202 verify(mPlatformSensorProvider, times(1)).sensorStopped(sensor);
203 verify(mPlatformSensorProvider, times(1)).getHandler();
204 }
205
206 /**
207 * Test that PlatformSensor correctly checks supported configuration.
208 */
209 @Test
210 @Feature({"PlatformSensor"})
211 public void testSensorConfiguration() {
212 // 5Hz min delay
213 PlatformSensor sensor = createPlatformSensor(200000, Sensor.TYPE_ACCELER OMETER,
214 SensorType.ACCELEROMETER, Sensor.REPORTING_MODE_CONTINUOUS);
215 assertEquals(true, sensor.checkSensorConfiguration(5));
216 assertEquals(false, sensor.checkSensorConfiguration(6));
217 }
218
219 /**
220 * Test that PlatformSensor correctly returns its reporting mode.
221 */
222 @Test
223 @Feature({"PlatformSensor"})
224 public void testSensorOnChangeReportingMode() {
225 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_LIGHT,
226 SensorType.AMBIENT_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE);
227 assertEquals(ReportingMode.ON_CHANGE, sensor.getReportingMode());
228 }
229
230 /**
231 * Test that PlatformSensor doesn't notify client about sensor reading chang es when
232 * sensor reporting mode is ReportingMode.CONTINUOUS.
233 */
234 @Test
235 @Feature({"PlatformSensor"})
236 public void testSensorNotifierIsNotCalled()
237 throws NoSuchFieldException, IllegalAccessException {
238 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_ACCELERO METER,
239 SensorType.ACCELEROMETER, Sensor.REPORTING_MODE_CONTINUOUS);
240 PlatformSensorNotifier mockNotifier = mock(PlatformSensorNotifier.class) ;
241 initPlatformSensor(sensor, SensorReadBuffer.READ_BUFFER_SIZE, mockNotifi er);
242 SensorEvent event = createFakeEvent(3);
243 sensor.onSensorChanged(event);
244 verify(mockNotifier, never()).sensorReadingChanged();
245 }
246
247 /**
248 * Test that shared buffer is correctly populated from SensorEvent.
249 */
250 @Test
251 @Feature({"PlatformSensor"})
252 public void testSensorBufferFromEvent() throws NoSuchFieldException, Illegal AccessException {
253 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_LIGHT,
254 SensorType.AMBIENT_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE);
255 PlatformSensorNotifier mockNotifier = mock(PlatformSensorNotifier.class) ;
256 initPlatformSensor(sensor, SensorReadBuffer.READ_BUFFER_SIZE, mockNotifi er);
257 SensorEvent event = createFakeEvent(1);
258 sensor.onSensorChanged(event);
259 verify(mockNotifier, times(1)).sensorReadingChanged();
260 // Verify that timestamp correctly stored in buffer.
261 assertEquals(MILLISECONDS_IN_NANOSECOND * PLATFORM_SENSOR_TIMESTAMP,
262 mSharedBuffer.getDouble(), MILLISECONDS_IN_NANOSECOND);
263 // Verify illuminance value is correctly stored in buffer and precision is not lost.
264 assertEquals(1.0d + MILLISECONDS_IN_NANOSECOND, mSharedBuffer.getDouble( ),
265 MILLISECONDS_IN_NANOSECOND);
266 }
267
268 /**
269 * Test that PlatformSensor notifies client when there is an error.
270 */
271 @Test
272 @Feature({"PlatformSensor"})
273 public void testSensorInvalidReadingSize() throws NoSuchFieldException, Ille galAccessException {
274 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_ACCELERO METER,
275 SensorType.ACCELEROMETER, Sensor.REPORTING_MODE_CONTINUOUS);
276 PlatformSensorNotifier mockNotifier = mock(PlatformSensorNotifier.class) ;
277 initPlatformSensor(sensor, SensorReadBuffer.READ_BUFFER_SIZE, mockNotifi er);
278 // Accelerometer requires 3 reading values x,y and z, create fake event with 1 reading
279 // value.
280 SensorEvent event = createFakeEvent(1);
281 sensor.onSensorChanged(event);
282 verify(mockNotifier, times(1)).sensorError();
283 }
284
285 /**
286 * Test that PlatformSensor notifies client when there is an error.
287 */
288 @Test
289 @Feature({"PlatformSensor"})
290 public void testSensorInvalidBufferSize() throws NoSuchFieldException, Illeg alAccessException {
291 PlatformSensor sensor = createPlatformSensor(50000, Sensor.TYPE_ACCELERO METER,
292 SensorType.ACCELEROMETER, Sensor.REPORTING_MODE_CONTINUOUS);
293 PlatformSensorNotifier mockNotifier = mock(PlatformSensorNotifier.class) ;
294 // Create buffer that doesn't have enough capacity to hold sensor readin g values.
295 initPlatformSensor(sensor, 2, mockNotifier);
296 SensorEvent event = createFakeEvent(3);
297 sensor.onSensorChanged(event);
298 verify(mockNotifier, times(1)).sensorError();
299 }
300
301 /**
302 * Test that multiple PlatformSensor instances correctly register (unregiste r) to
303 * sensor manager and notify PlatformSensorProvider when they start (stop) p olling for data.
304 */
305 @Test
306 @Feature({"PlatformSensor"})
307 public void testMultipleSensorTypeInstances() {
308 addMockSensor(200000, Sensor.TYPE_LIGHT, Sensor.REPORTING_MODE_ON_CHANGE );
309 addMockSensor(50000, Sensor.TYPE_ACCELEROMETER, Sensor.REPORTING_MODE_CO NTINUOUS);
310
311 PlatformSensor lightSensor =
312 PlatformSensor.create(Sensor.TYPE_LIGHT, 1, mPlatformSensorProvi der);
313 assertNotNull(lightSensor);
314
315 PlatformSensor accelerometerSensor =
316 PlatformSensor.create(Sensor.TYPE_ACCELEROMETER, 3, mPlatformSen sorProvider);
317 assertNotNull(accelerometerSensor);
318
319 lightSensor.startSensor(3);
320 accelerometerSensor.startSensor(10);
321 lightSensor.stopSensor();
322 accelerometerSensor.stopSensor();
323
324 verify(mPlatformSensorProvider, times(2)).getHandler();
325 verify(mPlatformSensorProvider, times(1)).sensorStarted(lightSensor);
326 verify(mPlatformSensorProvider, times(1)).sensorStarted(accelerometerSen sor);
327 verify(mPlatformSensorProvider, times(1)).sensorStopped(lightSensor);
328 verify(mPlatformSensorProvider, times(1)).sensorStopped(accelerometerSen sor);
329 verify(mSensorManager, times(2))
330 .registerListener(any(SensorEventListener.class), any(Sensor.cla ss), anyInt(),
331 any(Handler.class));
332 verify(mSensorManager, times(2))
333 .unregisterListener(any(SensorEventListener.class), any(Sensor.c lass));
timvolodine 2016/09/07 14:51:06 Regarding multiple sensors I was actually hoping f
shalamov 2016/09/07 18:49:18 Mockito / JUnit tests are run on 'testing thread',
timvolodine 2016/09/08 12:35:06 Would a simpler approach to just check "mSensorsTh
shalamov 2016/09/08 13:40:49 Done.
334 }
335
336 private SensorEvent createFakeEvent(int readingValuesNum)
337 throws NoSuchFieldException, IllegalAccessException {
338 SensorEvent mockEvent = mock(SensorEvent.class);
Ted C 2016/09/07 18:12:24 This seems more complicated than it needs to be.
shalamov 2016/09/07 18:49:18 That's what I tried in the beginning, but it looks
Ted C 2016/09/07 20:08:12 Oh android...can you use reflection to just make t
shalamov 2016/09/08 13:40:49 Done.
339 mockEvent.timestamp = PLATFORM_SENSOR_TIMESTAMP;
340 float values[] = new float[readingValuesNum];
341 for (int i = 0; i < readingValuesNum; ++i) {
342 values[i] = (float) (i + 1.0f + MILLISECONDS_IN_NANOSECOND);
343 }
344
345 Field valuesField = SensorEvent.class.getDeclaredField("values");
346 valuesField.setAccessible(true);
347 Field modifiersField = Field.class.getDeclaredField("modifiers");
348 modifiersField.setAccessible(true);
349 modifiersField.setInt(valuesField, valuesField.getModifiers() & ~Modifie r.FINAL);
350 valuesField.set(mockEvent, values);
351 return mockEvent;
352 }
353
354 private void initPlatformSensor(
355 PlatformSensor sensor, long readingSize, PlatformSensorNotifier noti fier) {
356 mSharedBuffer = ByteBuffer.allocate((int) readingSize);
357 mSharedBuffer.order(ByteOrder.nativeOrder());
358 sensor.initPlatformSensorAndroid(notifier, PLATFORM_SENSOR_ANDROID, mSha redBuffer);
359 }
360
361 private void addMockSensor(long minDelayUsec, int sensorType, int reportingM ode) {
362 List<Sensor> mockSensorList = new ArrayList<Sensor>();
363 Sensor mockSensor = mock(Sensor.class);
364 doReturn((int) minDelayUsec).when(mockSensor).getMinDelay();
365 doReturn(reportingMode).when(mockSensor).getReportingMode();
366 doReturn(sensorType).when(mockSensor).getType();
367 mockSensorList.add(mockSensor);
368 mMockSensors.put(sensorType, mockSensorList);
369 }
370
371 private List<Sensor> getMockSensors(int sensorType) {
372 if (mMockSensors.indexOfKey(sensorType) >= 0) {
373 return mMockSensors.get(sensorType);
374 }
375 return new ArrayList<Sensor>();
376 }
377
378 private PlatformSensor createPlatformSensor(
379 long minDelayUsec, int androidSensorType, int mojoSensorType, int re portingMode) {
380 addMockSensor(minDelayUsec, androidSensorType, reportingMode);
381 PlatformSensorProvider provider = PlatformSensorProvider.create(mContext );
382 return provider.createSensor(mojoSensorType);
383 }
384 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698