blob: b692f0fba4a8bd1bd3de7b218e1788824c937f96 [file] [log] [blame]
package android.hardware.cts.helpers.sensorverification;
import junit.framework.Assert;
import android.hardware.Sensor;
import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* A {@link ISensorVerification} which verifies that there are no missing events. This is done by
* checking the last received sensor timestamp and checking that it is within 1.8 * the expected
* period.
*/
public class EventGapVerification extends AbstractSensorVerification {
public static final String PASSED_KEY = "missing_event_passed";
// Fail if no events are delivered within 1.8 times the expected interval
private static final double THRESHOLD = 1.8;
// Number of indices to print in assert message before truncating
private static final int TRUNCATE_MESSAGE_LENGTH = 3;
// Number of events to truncate (discard) from the initial events received
private static final int TRUNCATE_EVENTS_COUNT = 1;
private final int mExpectedDelayUs;
private final List<IndexedEventPair> mEventGaps = new LinkedList<IndexedEventPair>();
private TestSensorEvent mPreviousEvent = null;
private int mIndex = 0;
/**
* Construct a {@link EventGapVerification}
*
* @param expectedDelayUs the expected period in us.
*/
public EventGapVerification(int expectedDelayUs) {
mExpectedDelayUs = expectedDelayUs;
}
/**
* Get the default {@link EventGapVerification}.
*
* @param environment the test environment
* @return the verification or null if the verification is not a continuous mode sensor.
*/
public static EventGapVerification getDefault(TestSensorEnvironment environment) {
if (environment.getSensor().getReportingMode() != Sensor.REPORTING_MODE_CONTINUOUS) {
return null;
}
return new EventGapVerification(environment.getExpectedSamplingPeriodUs());
}
/**
* {@inheritDoc}
*/
@Override
public void verify(TestSensorEnvironment environment, SensorStats stats) {
if (environment.isSensorSamplingRateOverloaded()) {
// the verification is not reliable on environments under load
stats.addValue(PASSED_KEY, "skipped (under load)");
return;
}
final int count = mEventGaps.size();
stats.addValue(PASSED_KEY, count == 0);
stats.addValue(SensorStats.EVENT_GAP_COUNT_KEY, count);
stats.addValue(SensorStats.EVENT_GAP_POSITIONS_KEY, getIndexArray(mEventGaps));
if (count > 0) {
StringBuilder sb = new StringBuilder();
sb.append(count).append(" events gaps: ");
for (int i = 0; i < Math.min(count, TRUNCATE_MESSAGE_LENGTH); i++) {
IndexedEventPair info = mEventGaps.get(i);
sb.append(String.format("position=%d, delta_time=%dns; ", info.index,
info.event.timestamp - info.previousEvent.timestamp));
}
if (count > TRUNCATE_MESSAGE_LENGTH) {
sb.append(count - TRUNCATE_MESSAGE_LENGTH).append(" more; ");
}
sb.append(String.format("(expected <%dns)",
TimeUnit.NANOSECONDS.convert((int) (THRESHOLD * mExpectedDelayUs),
TimeUnit.MICROSECONDS)));
Assert.fail(sb.toString());
}
}
/**
* {@inheritDoc}
*/
@Override
public EventGapVerification clone() {
return new EventGapVerification(mExpectedDelayUs);
}
/**
* {@inheritDoc}
*/
@Override
protected void addSensorEventInternal(TestSensorEvent event) {
if (mIndex >= TRUNCATE_EVENTS_COUNT) {
if (mPreviousEvent != null) {
long deltaNs = event.timestamp - mPreviousEvent.timestamp;
long deltaUs = TimeUnit.MICROSECONDS.convert(deltaNs, TimeUnit.NANOSECONDS);
if (deltaUs > mExpectedDelayUs * THRESHOLD) {
mEventGaps.add(new IndexedEventPair(mIndex, event, mPreviousEvent));
}
}
mPreviousEvent = event;
}
mIndex++;
}
}