blob: 3e70e75513620971b9fef48dfdbb257b71ae63a8 [file] [log] [blame]
Eric Rowe7b44fee2014-03-18 18:16:50 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.hardware.cts.helpers;
18
destradaaa0b3bbc2014-09-03 14:08:00 -070019import junit.framework.Assert;
20
Aravind Akelladbc95c52015-06-09 10:22:16 -070021import android.content.Context;
Eric Rowe7b44fee2014-03-18 18:16:50 -070022import android.hardware.Sensor;
23import android.hardware.SensorEvent;
24import android.hardware.SensorEventListener2;
destradaa4458c692014-10-15 12:42:29 -070025import android.os.Handler;
26import android.os.Looper;
destradaafd031b92014-10-10 10:45:51 -070027import android.os.SystemClock;
Aravind Akelladbc95c52015-06-09 10:22:16 -070028import android.os.PowerManager;
29import android.os.PowerManager.WakeLock;
30import android.util.Log;
Eric Rowe7b44fee2014-03-18 18:16:50 -070031
destradaa24289b52014-10-20 11:41:00 -070032import java.io.BufferedWriter;
33import java.io.File;
34import java.io.FileWriter;
35import java.io.IOException;
destradaa4458c692014-10-15 12:42:29 -070036import java.util.ArrayList;
destradaa24289b52014-10-20 11:41:00 -070037import java.util.Arrays;
destradaacbb8c002014-12-12 17:31:16 -080038import java.util.Collections;
39import java.util.List;
Eric Rowe7b44fee2014-03-18 18:16:50 -070040import java.util.concurrent.CountDownLatch;
41import java.util.concurrent.TimeUnit;
destradaacbb8c002014-12-12 17:31:16 -080042import java.util.concurrent.atomic.AtomicInteger;
Eric Rowe7b44fee2014-03-18 18:16:50 -070043
44/**
45 * A {@link SensorEventListener2} which performs operations such as waiting for a specific number of
46 * events or for a specific time, or waiting for a flush to complete. This class performs
47 * verifications and will throw {@link AssertionError}s if there are any errors. It may also wrap
48 * another {@link SensorEventListener2}.
49 */
50public class TestSensorEventListener implements SensorEventListener2 {
51 public static final String LOG_TAG = "TestSensorEventListener";
destradaa24289b52014-10-20 11:41:00 -070052
destradaa4458c692014-10-15 12:42:29 -070053 private static final long EVENT_TIMEOUT_US = TimeUnit.SECONDS.toMicros(5);
54 private static final long FLUSH_TIMEOUT_US = TimeUnit.SECONDS.toMicros(10);
55
Han, He5b7f5832015-03-06 16:37:33 +080056 private final ArrayList<TestSensorEvent> mCollectedEvents = new ArrayList<>();
Aravind Akelladbc95c52015-06-09 10:22:16 -070057 private final ArrayList<Long> mTimeStampFlushCompleteEvents = new ArrayList<>();
destradaacbb8c002014-12-12 17:31:16 -080058 private final List<CountDownLatch> mEventLatches = new ArrayList<>();
59 private final List<CountDownLatch> mFlushLatches = new ArrayList<>();
60 private final AtomicInteger mEventsReceivedOutsideHandler = new AtomicInteger();
Eric Rowe7b44fee2014-03-18 18:16:50 -070061
destradaa4458c692014-10-15 12:42:29 -070062 private final Handler mHandler;
destradaacbb8c002014-12-12 17:31:16 -080063 private final TestSensorEnvironment mEnvironment;
Aravind Akelladbc95c52015-06-09 10:22:16 -070064 private final PowerManager.WakeLock mTestSensorEventListenerWakeLock;
Eric Rowe7b44fee2014-03-18 18:16:50 -070065
destradaacbb8c002014-12-12 17:31:16 -080066 /**
67 * @deprecated Use {@link TestSensorEventListener(TestSensorEnvironment)}.
68 */
69 @Deprecated
70 public TestSensorEventListener() {
71 this(null /* environment */);
72 }
Eric Rowe7b44fee2014-03-18 18:16:50 -070073
74 /**
75 * Construct a {@link TestSensorEventListener}.
76 */
destradaacbb8c002014-12-12 17:31:16 -080077 public TestSensorEventListener(TestSensorEnvironment environment) {
78 this(environment, null /* handler */);
destradaa4458c692014-10-15 12:42:29 -070079 }
80
81 /**
destradaacbb8c002014-12-12 17:31:16 -080082 * Construct a {@link TestSensorEventListener}.
destradaa4458c692014-10-15 12:42:29 -070083 */
destradaacbb8c002014-12-12 17:31:16 -080084 public TestSensorEventListener(TestSensorEnvironment environment, Handler handler) {
destradaab7f89492014-09-19 14:23:04 -070085 mEnvironment = environment;
destradaacbb8c002014-12-12 17:31:16 -080086 mHandler = handler;
Aravind Akelladbc95c52015-06-09 10:22:16 -070087 PowerManager pm = (PowerManager) environment.getContext().getSystemService(
88 Context.POWER_SERVICE);
89 mTestSensorEventListenerWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
90 "TestSensorEventListenerWakeLock");
Eric Rowebaefaac2014-03-31 17:41:38 -070091 }
92
93 /**
Eric Rowe7b44fee2014-03-18 18:16:50 -070094 * {@inheritDoc}
95 */
96 @Override
97 public void onSensorChanged(SensorEvent event) {
destradaacbb8c002014-12-12 17:31:16 -080098 long timestampNs = SystemClock.elapsedRealtimeNanos();
destradaa4458c692014-10-15 12:42:29 -070099 checkHandler();
destradaacbb8c002014-12-12 17:31:16 -0800100 synchronized (mCollectedEvents) {
101 mCollectedEvents.add(new TestSensorEvent(event, timestampNs));
destradaafd031b92014-10-10 10:45:51 -0700102 }
destradaa4458c692014-10-15 12:42:29 -0700103 synchronized (mEventLatches) {
104 for (CountDownLatch latch : mEventLatches) {
105 latch.countDown();
Aravind Akelladbc95c52015-06-09 10:22:16 -0700106 if (latch.getCount() == 0 && !mTestSensorEventListenerWakeLock.isHeld()) {
107 mTestSensorEventListenerWakeLock.acquire();
108 }
destradaa4458c692014-10-15 12:42:29 -0700109 }
Eric Rowe7b44fee2014-03-18 18:16:50 -0700110 }
Eric Rowe7b44fee2014-03-18 18:16:50 -0700111 }
112
113 /**
114 * {@inheritDoc}
115 */
116 @Override
117 public void onAccuracyChanged(Sensor sensor, int accuracy) {
destradaa4458c692014-10-15 12:42:29 -0700118 checkHandler();
Eric Rowe7b44fee2014-03-18 18:16:50 -0700119 }
120
121 /**
Aravind Akella490e9b82015-01-29 17:41:07 -0800122 * @param eventCount
123 * @return A CountDownLatch initialzed with eventCount and decremented as sensor events arrive
124 * for this listerner.
125 */
126 public CountDownLatch getLatchForSensorEvents(int eventCount) {
127 CountDownLatch latch = new CountDownLatch(eventCount);
128 synchronized (mEventLatches) {
129 mEventLatches.add(latch);
130 }
131 return latch;
132 }
133
134 /**
135 * @return A CountDownLatch initialzed with 1 and decremented as a flush complete arrives
136 * for this listerner.
137 */
138 public CountDownLatch getLatchForFlushCompleteEvent() {
139 CountDownLatch latch = new CountDownLatch(1);
140 synchronized (mFlushLatches) {
141 mFlushLatches.add(latch);
142 }
143 return latch;
144 }
145
146 /**
Eric Rowe7b44fee2014-03-18 18:16:50 -0700147 * {@inheritDoc}
148 */
149 @Override
150 public void onFlushCompleted(Sensor sensor) {
destradaa4458c692014-10-15 12:42:29 -0700151 checkHandler();
Aravind Akelladbc95c52015-06-09 10:22:16 -0700152 long timestampNs = SystemClock.elapsedRealtimeNanos();
153 synchronized (mTimeStampFlushCompleteEvents) {
154 mTimeStampFlushCompleteEvents.add(timestampNs);
155 }
destradaa4458c692014-10-15 12:42:29 -0700156 synchronized (mFlushLatches) {
157 for (CountDownLatch latch : mFlushLatches) {
158 latch.countDown();
159 }
160 }
Eric Rowe7b44fee2014-03-18 18:16:50 -0700161 }
162
163 /**
destradaacbb8c002014-12-12 17:31:16 -0800164 * @return The handler (if any) associated with the instance.
165 */
166 public Handler getHandler() {
167 return mHandler;
168 }
169
170 /**
171 * @return A list of {@link TestSensorEvent}s collected by the listener.
172 */
173 public List<TestSensorEvent> getCollectedEvents() {
174 synchronized (mCollectedEvents){
Han, He5b7f5832015-03-06 16:37:33 +0800175 List<TestSensorEvent> collectedEventsList = (List)mCollectedEvents.clone();
176 return Collections.unmodifiableList(collectedEventsList);
destradaacbb8c002014-12-12 17:31:16 -0800177 }
178 }
179
180 /**
181 * Clears the internal list of collected {@link TestSensorEvent}s.
182 */
183 public void clearEvents() {
184 synchronized (mCollectedEvents) {
185 mCollectedEvents.clear();
186 }
187 }
188
destradaa24289b52014-10-20 11:41:00 -0700189
190 /**
191 * Utility method to log the collected events to a file.
192 * It will overwrite the file if it already exists, the file is created in a relative directory
193 * named 'events' under the sensor test directory (part of external storage).
194 */
Aravind Akelladbc95c52015-06-09 10:22:16 -0700195 public void logCollectedEventsToFile(String fileName, long deviceWakeUpTimeMs)
196 throws IOException {
destradaa24289b52014-10-20 11:41:00 -0700197 StringBuilder builder = new StringBuilder();
198 builder.append("Sensor='").append(mEnvironment.getSensor()).append("', ");
199 builder.append("SamplingRateOverloaded=")
200 .append(mEnvironment.isSensorSamplingRateOverloaded()).append(", ");
201 builder.append("RequestedSamplingPeriod=")
202 .append(mEnvironment.getRequestedSamplingPeriodUs()).append("us, ");
203 builder.append("MaxReportLatency=")
204 .append(mEnvironment.getMaxReportLatencyUs()).append("us");
destradaa24289b52014-10-20 11:41:00 -0700205 synchronized (mCollectedEvents) {
Aravind Akelladbc95c52015-06-09 10:22:16 -0700206 int i = 0, j = 0;
207 while (i < mCollectedEvents.size() && j < mTimeStampFlushCompleteEvents.size()) {
208 if (mCollectedEvents.get(i).receivedTimestamp <
209 mTimeStampFlushCompleteEvents.get(j)) {
210 TestSensorEvent event = mCollectedEvents.get(i);
211 if (deviceWakeUpTimeMs != -1 && deviceWakeUpTimeMs <
212 event.receivedTimestamp/1000000) {
213 builder.append("\n");
214 builder.append("AP wake-up time=").append(deviceWakeUpTimeMs).append("ms");
215 deviceWakeUpTimeMs = -1;
216 }
217 builder.append("\n");
218 builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
219 builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
220 append("ms, ");
221 builder.append("Accuracy=").append(event.accuracy).append(", ");
222 builder.append("Values=").append(Arrays.toString(event.values));
223 ++i;
224 } else {
225 builder.append("\n");
226 builder.append("ReceivedTimestamp=")
227 .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
Aravind Akella0eb60922015-07-23 14:10:02 -0700228 .append("ms Flush complete Event");
Aravind Akelladbc95c52015-06-09 10:22:16 -0700229 ++j;
230 }
231 }
232 for (;i < mCollectedEvents.size(); ++i) {
233 TestSensorEvent event = mCollectedEvents.get(i);
234 if (deviceWakeUpTimeMs != -1 && deviceWakeUpTimeMs <
235 event.receivedTimestamp/1000000) {
236 builder.append("\n");
237 builder.append("AP wake-up time=").append(deviceWakeUpTimeMs).append("ms");
238 deviceWakeUpTimeMs = -1;
239 }
destradaa24289b52014-10-20 11:41:00 -0700240 builder.append("\n");
Aravind Akelladbc95c52015-06-09 10:22:16 -0700241 builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
242 builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
243 append("ms, ");
destradaa24289b52014-10-20 11:41:00 -0700244 builder.append("Accuracy=").append(event.accuracy).append(", ");
245 builder.append("Values=").append(Arrays.toString(event.values));
246 }
Aravind Akelladbc95c52015-06-09 10:22:16 -0700247 for (;j < mTimeStampFlushCompleteEvents.size(); ++j) {
248 builder.append("\n");
249 builder.append("ReceivedTimestamp=")
250 .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
251 .append("ms Flush complete Event");
252 }
destradaa24289b52014-10-20 11:41:00 -0700253 }
254
255 File eventsDirectory = SensorCtsHelper.getSensorTestDataDirectory("events/");
256 File logFile = new File(eventsDirectory, fileName);
257 FileWriter fileWriter = new FileWriter(logFile, false /* append */);
258 try (BufferedWriter writer = new BufferedWriter(fileWriter)) {
259 writer.write(builder.toString());
260 }
261 }
262
destradaacbb8c002014-12-12 17:31:16 -0800263 /**
Eric Rowe7b44fee2014-03-18 18:16:50 -0700264 * Wait for {@link #onFlushCompleted(Sensor)} to be called.
265 *
destradaaa0b3bbc2014-09-03 14:08:00 -0700266 * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
Eric Rowe7b44fee2014-03-18 18:16:50 -0700267 */
Aravind Akelladbc95c52015-06-09 10:22:16 -0700268 public void waitForFlushComplete(CountDownLatch latch,
269 boolean clearCollectedEvents) throws InterruptedException {
270 if (clearCollectedEvents) {
271 clearEvents();
272 }
destradaa4458c692014-10-15 12:42:29 -0700273 try {
274 String message = SensorCtsHelper.formatAssertionMessage(
275 "WaitForFlush",
276 mEnvironment,
277 "timeout=%dus",
278 FLUSH_TIMEOUT_US);
279 Assert.assertTrue(message, latch.await(FLUSH_TIMEOUT_US, TimeUnit.MICROSECONDS));
280 } finally {
281 synchronized (mFlushLatches) {
282 mFlushLatches.remove(latch);
283 }
284 }
Eric Rowe7b44fee2014-03-18 18:16:50 -0700285 }
286
287 /**
288 * Collect a specific number of {@link TestSensorEvent}s.
289 *
destradaaa0b3bbc2014-09-03 14:08:00 -0700290 * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
Eric Rowe7b44fee2014-03-18 18:16:50 -0700291 */
Aravind Akelladbc95c52015-06-09 10:22:16 -0700292 public void waitForEvents(CountDownLatch latch, int eventCount,
293 boolean clearCollectedEvents) throws InterruptedException {
294 if (clearCollectedEvents) {
295 clearEvents();
296 }
Eric Rowe7b44fee2014-03-18 18:16:50 -0700297 try {
destradaa4458c692014-10-15 12:42:29 -0700298 long samplingPeriodUs = mEnvironment.getMaximumExpectedSamplingPeriodUs();
299 // timeout is 2 * event count * expected period + batch timeout + default wait
300 // we multiply by two as not to raise an error in this function even if the events are
301 // streaming at a lower rate than expected, as long as it's not streaming twice as slow
302 // as expected
303 long timeoutUs = (2 * eventCount * samplingPeriodUs)
destradaab7f89492014-09-19 14:23:04 -0700304 + mEnvironment.getMaxReportLatencyUs()
destradaafd031b92014-10-10 10:45:51 -0700305 + EVENT_TIMEOUT_US;
Aravind Akella490e9b82015-01-29 17:41:07 -0800306 boolean success = latch.await(timeoutUs, TimeUnit.MICROSECONDS);
destradaa4458c692014-10-15 12:42:29 -0700307 if (!success) {
308 String message = SensorCtsHelper.formatAssertionMessage(
309 "WaitForEvents",
310 mEnvironment,
311 "requested=%d, received=%d, timeout=%dus",
312 eventCount,
Aravind Akella490e9b82015-01-29 17:41:07 -0800313 eventCount - latch.getCount(),
destradaa4458c692014-10-15 12:42:29 -0700314 timeoutUs);
315 Assert.fail(message);
316 }
Eric Rowe7b44fee2014-03-18 18:16:50 -0700317 } finally {
destradaa4458c692014-10-15 12:42:29 -0700318 synchronized (mEventLatches) {
Aravind Akella490e9b82015-01-29 17:41:07 -0800319 mEventLatches.remove(latch);
destradaa4458c692014-10-15 12:42:29 -0700320 }
Eric Rowe7b44fee2014-03-18 18:16:50 -0700321 }
322 }
323
324 /**
325 * Collect {@link TestSensorEvent} for a specific duration.
326 */
destradaafd031b92014-10-10 10:45:51 -0700327 public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
Eric Rowe7b44fee2014-03-18 18:16:50 -0700328 SensorCtsHelper.sleep(duration, timeUnit);
329 }
destradaa4458c692014-10-15 12:42:29 -0700330
331 /**
332 * Asserts that sensor events arrived in the proper thread if a {@link Handler} was associated
333 * with the current instance.
334 *
335 * If no events were received this assertion will be evaluated to {@code true}.
336 */
337 public void assertEventsReceivedInHandler() {
destradaacbb8c002014-12-12 17:31:16 -0800338 int eventsOutsideHandler = mEventsReceivedOutsideHandler.get();
339 String message = String.format(
340 "Events arrived outside the associated Looper. Expected=0, Found=%d",
341 eventsOutsideHandler);
342 Assert.assertEquals(message, 0 /* expected */, eventsOutsideHandler);
destradaa4458c692014-10-15 12:42:29 -0700343 }
344
Aravind Akelladbc95c52015-06-09 10:22:16 -0700345 public void releaseWakeLock() {
346 if (mTestSensorEventListenerWakeLock.isHeld()) {
347 mTestSensorEventListenerWakeLock.release();
348 }
349 }
350
destradaacbb8c002014-12-12 17:31:16 -0800351 /**
352 * Keeps track of the number of events that arrived in a different {@link Looper} than the one
353 * associated with the {@link TestSensorEventListener}.
354 */
destradaa4458c692014-10-15 12:42:29 -0700355 private void checkHandler() {
destradaacbb8c002014-12-12 17:31:16 -0800356 if (mHandler != null && mHandler.getLooper() != Looper.myLooper()) {
357 mEventsReceivedOutsideHandler.incrementAndGet();
destradaa4458c692014-10-15 12:42:29 -0700358 }
359 }
Eric Rowe7b44fee2014-03-18 18:16:50 -0700360}