Cherrypick the following CLs from LMP MR1
Cherrypick CLs from lmp-mr1 and fixed a typo in method name in
android.hardware.cts.SensorTest.
List of the CLs:
Move timestamp synchronization test cases to sensor test platform.
b/17643223
- Improves the logging of timestamp synchronization verifications
- Refactor batching tests to use sensor test platform
Original-Change-Id: Ic6924d5c794ddcf646f618f446cbda11b938d184
Refactor Sensor test platform Operations.
b/17838681
The refactoring is required in preparation to add support to save sensor events upon failure.
Original-Change-Id: I13ed41e3fa5393c61ccee766f0fdb9f4fd6aadd5
Fix handling of Sensor test platform exceptions.
b/18705736
Original-Change-Id: I82f4a4f18b52ff3ea263b3ff9f063e1c5459eca5
Refactor sensor test platform listeners.
b/17838681
The refactoring is required in preparation to add support to save sensor events upon failure.
Original-Change-Id: I5540451d70426fbbbe19a10b2a727b2e010c3838
Refactor SensorStats.
b/17838681
The refactoring is required in preparation to add support to save sensor events upon failure.
Original-Change-Id: I4661647b13296912fe89f5b20e01dad12553f72d
Save all sensor events when a verification fails.
b/17838681
It also prepares the sensor test platform for logging and maintaining a hierarchy of elements.
Most of the changes are only required to propagate the hierarchy information down to all the
elements of the sensor test platform.
Original-Change-Id: I08f750cfb426502240db584b5a1209481856c13c
Change-Id: Ia68a7d9952b7ac7bfd100cdf70dace494b17e7b3
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
index dfcf120..52b3dee 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
@@ -97,11 +97,11 @@
Sensor.TYPE_ACCELEROMETER,
SensorManager.SENSOR_DELAY_FASTEST);
TestSensorOperation verifyMeasurements =
- new TestSensorOperation(environment, 100 /* event count */);
+ TestSensorOperation.createOperation(environment, 100 /* event count */);
verifyMeasurements.addVerification(new MeanVerification(
expectations,
new float[]{1.95f, 1.95f, 1.95f} /* m / s^2 */));
- verifyMeasurements.execute();
+ verifyMeasurements.execute(getCurrentTestNode());
return null;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
index 6f0a7aa..7ef63d7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
@@ -22,9 +22,7 @@
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.cts.helpers.TestSensorEnvironment;
-import android.hardware.cts.helpers.sensoroperations.TestSensorFlushOperation;
import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
-import android.hardware.cts.helpers.sensoroperations.VerifiableSensorOperation;
import java.util.concurrent.TimeUnit;
@@ -128,7 +126,7 @@
int testDurationSec = maxBatchReportLatencySec + BATCHING_PADDING_TIME_S;
TestSensorOperation operation =
- new TestSensorOperation(environment, testDurationSec,TimeUnit.SECONDS);
+ TestSensorOperation.createOperation(environment, testDurationSec,TimeUnit.SECONDS);
return executeTest(operation);
}
@@ -145,15 +143,14 @@
maxBatchReportLatencyUs);
int flushDurationSec = maxBatchReportLatencySec / 2;
- TestSensorFlushOperation operation =
- new TestSensorFlushOperation(environment, flushDurationSec, TimeUnit.SECONDS);
+ TestSensorOperation operation = TestSensorOperation
+ .createFlushOperation(environment, flushDurationSec, TimeUnit.SECONDS);
return executeTest(operation);
}
- private String executeTest(VerifiableSensorOperation operation) throws InterruptedException {
+ private String executeTest(TestSensorOperation operation) throws InterruptedException {
operation.addDefaultVerifications();
- operation.setLogEvents(true);
- operation.execute();
+ operation.execute(getCurrentTestNode());
return null;
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
index 4b2a7f4..7be0fb1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
@@ -156,8 +156,8 @@
getApplicationContext(),
Sensor.TYPE_GYROSCOPE,
SensorManager.SENSOR_DELAY_FASTEST);
- TestSensorOperation sensorOperation =
- new TestSensorOperation(environment, ROTATION_COLLECTION_SEC, TimeUnit.SECONDS);
+ TestSensorOperation sensorOperation = TestSensorOperation
+ .createOperation(environment, ROTATION_COLLECTION_SEC, TimeUnit.SECONDS);
int gyroscopeAxes = environment.getSensorAxesCount();
int[] expectationsDeg = getExpectationsDeg(gyroscopeAxes, rotationAxis, expectationDeg);
@@ -167,7 +167,7 @@
sensorOperation.addVerification(integrationVerification);
try {
- sensorOperation.execute();
+ sensorOperation.execute(getCurrentTestNode());
} finally {
playSound();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
index 553147b..229a9dc 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
@@ -21,7 +21,6 @@
import android.hardware.Sensor;
import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener2;
import android.hardware.SensorManager;
import android.hardware.cts.helpers.SensorCalibratedUncalibratedVerifier;
import android.hardware.cts.helpers.SensorCtsHelper;
@@ -79,7 +78,7 @@
Sensor.TYPE_MAGNETIC_FIELD,
SensorManager.SENSOR_DELAY_FASTEST);
TestSensorOperation verifyNorm =
- new TestSensorOperation(environment, 100 /* event count */);
+ TestSensorOperation.createOperation(environment, 100 /* event count */);
float expectedMagneticFieldEarth =
(SensorManager.MAGNETIC_FIELD_EARTH_MAX + SensorManager.MAGNETIC_FIELD_EARTH_MIN) / 2;
@@ -88,7 +87,7 @@
verifyNorm.addVerification(new MagnitudeVerification(
expectedMagneticFieldEarth,
magneticFieldEarthThreshold));
- verifyNorm.execute();
+ verifyNorm.execute(getCurrentTestNode());
return null;
}
@@ -124,11 +123,11 @@
Sensor.TYPE_MAGNETIC_FIELD,
SensorManager.SENSOR_DELAY_FASTEST);
TestSensorOperation verifyStdDev =
- new TestSensorOperation(environment, 100 /* event count */);
+ TestSensorOperation.createOperation(environment, 100 /* event count */);
verifyStdDev.addVerification(new StandardDeviationVerification(
new float[]{2f, 2f, 2f} /* uT */));
- verifyStdDev.execute();
+ verifyStdDev.execute(getCurrentTestNode());
return null;
}
@@ -166,7 +165,12 @@
* A routine to help operators calibrate the magnetometer.
*/
private void calibrateMagnetometer() throws InterruptedException {
- SensorEventListener2 listener = new SensorEventListener2() {
+ TestSensorEnvironment environment = new TestSensorEnvironment(
+ getApplicationContext(),
+ Sensor.TYPE_MAGNETIC_FIELD,
+ SensorManager.SENSOR_DELAY_NORMAL);
+
+ TestSensorEventListener listener = new TestSensorEventListener(environment) {
@Override
public void onSensorChanged(SensorEvent event) {
clearText();
@@ -184,21 +188,11 @@
// TODO: automate finding out when the magnetometer is calibrated
logger.logInstructions(R.string.snsr_mag_calibration_complete);
}
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {}
-
- @Override
- public void onFlushCompleted(Sensor sensor) {}
};
- TestSensorEnvironment environment = new TestSensorEnvironment(
- getApplicationContext(),
- Sensor.TYPE_MAGNETIC_FIELD,
- SensorManager.SENSOR_DELAY_NORMAL);
TestSensorManager magnetometer = new TestSensorManager(environment);
try {
- magnetometer.registerListener(new TestSensorEventListener(listener));
+ magnetometer.registerListener(listener);
waitForUserToContinue();
} finally {
magnetometer.unregisterListener();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java
index 5bbaaf7..380b282 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java
@@ -26,6 +26,8 @@
import android.content.Context;
import android.hardware.cts.SensorTestCase;
+import android.hardware.cts.helpers.SensorTestPlatformException;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import java.util.Enumeration;
@@ -138,10 +140,24 @@
SensorTestCase sensorTestCase = (SensorTestCase) testCase;
sensorTestCase.setContext(mContext);
sensorTestCase.setEmulateSensorUnderLoad(false);
+ sensorTestCase.setCurrentTestNode(new TestNode(testCase));
// TODO: set delayed assertion provider
} else {
throw new IllegalStateException("TestCase must be an instance of SensorTestCase.");
}
super.run(testCase);
}
+
+ private class TestNode implements ISensorTestNode {
+ private final TestCase mTestCase;
+
+ public TestNode(TestCase testCase) {
+ mTestCase = testCase;
+ }
+
+ @Override
+ public String getName() throws SensorTestPlatformException {
+ return mTestCase.getClass().getSimpleName() + "_" + mTestCase.getName();
+ }
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
index a88abd0..8cf287a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
@@ -19,6 +19,8 @@
import com.android.cts.verifier.sensors.reporting.SensorTestDetails;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
+
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -35,6 +37,7 @@
private volatile int mTestPassedCounter;
private volatile int mTestSkippedCounter;
private volatile int mTestFailedCounter;
+ private volatile ISensorTestNode mCurrentTestNode;
/**
* {@inheritDoc}
@@ -63,8 +66,12 @@
mTestFailedCounter);
}
+ protected ISensorTestNode getCurrentTestNode() {
+ return mCurrentTestNode;
+ }
+
private List<Method> findTestMethods() {
- ArrayList<Method> testMethods = new ArrayList<Method>();
+ ArrayList<Method> testMethods = new ArrayList<>();
for (Method method : mTestClass.getDeclaredMethods()) {
if (Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0
@@ -79,6 +86,7 @@
private SensorTestDetails executeTest(Method testMethod) throws InterruptedException {
String testMethodName = testMethod.getName();
String testName = String.format("%s#%s", getTestClassName(), testMethodName);
+ mCurrentTestNode = new TestNode(testMethod);
SensorTestDetails testDetails;
try {
@@ -112,4 +120,17 @@
return testDetails;
}
+
+ private class TestNode implements ISensorTestNode {
+ private final Method mTestMethod;
+
+ public TestNode(Method testMethod) {
+ mTestMethod = testMethod;
+ }
+
+ @Override
+ public String getName() {
+ return mTestClass.getSimpleName() + "_" + mTestMethod.getName();
+ }
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
index 687826c..7640cd7 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
@@ -20,9 +20,7 @@
import android.hardware.SensorManager;
import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.TestSensorEnvironment;
-import android.hardware.cts.helpers.sensoroperations.TestSensorFlushOperation;
import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
-import android.hardware.cts.helpers.sensoroperations.VerifiableSensorOperation;
import android.hardware.cts.helpers.sensorverification.ISensorVerification;
import java.util.concurrent.TimeUnit;
@@ -263,7 +261,7 @@
rateUs,
maxBatchReportLatencyUs);
TestSensorOperation operation =
- new TestSensorOperation(environment, testDurationSec, TimeUnit.SECONDS);
+ TestSensorOperation.createOperation(environment, testDurationSec, TimeUnit.SECONDS);
executeTest(environment, operation, false /* flushExpected */);
}
@@ -279,23 +277,23 @@
shouldEmulateSensorUnderLoad(),
rateUs,
maxBatchReportLatencyUs);
- TestSensorFlushOperation operation =
- new TestSensorFlushOperation(environment, flushDurationSec, TimeUnit.SECONDS);
+ TestSensorOperation operation = TestSensorOperation
+ .createFlushOperation(environment, flushDurationSec, TimeUnit.SECONDS);
executeTest(environment, operation, true /* flushExpected */);
}
private void executeTest(
TestSensorEnvironment environment,
- VerifiableSensorOperation operation,
+ TestSensorOperation operation,
boolean flushExpected) throws Throwable {
operation.addDefaultVerifications();
- operation.setLogEvents(true);
try {
- operation.execute();
+ operation.execute(getCurrentTestNode());
} finally {
- SensorStats.logStats(TAG, operation.getStats());
+ SensorStats stats = operation.getStats();
+ stats.log(TAG);
String sensorRate;
if (environment.getRequestedSamplingPeriodUs() == SensorManager.SENSOR_DELAY_FASTEST) {
@@ -311,7 +309,7 @@
sensorRate,
batching,
flush);
- SensorStats.logStatsToFile(fileName, operation.getStats());
+ stats.logToFile(fileName);
}
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
index 50cb12d..8c3fb7a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
@@ -18,13 +18,11 @@
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
-import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.sensoroperations.ParallelSensorOperation;
import android.hardware.cts.helpers.sensoroperations.RepeatingSensorOperation;
import android.hardware.cts.helpers.sensoroperations.SequentialSensorOperation;
import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
-import android.hardware.cts.helpers.sensoroperations.VerifiableSensorOperation;
import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
import java.util.Random;
@@ -81,7 +79,7 @@
shouldEmulateSensorUnderLoad(),
SensorManager.SENSOR_DELAY_FASTEST);
TestSensorOperation continuousOperation =
- new TestSensorOperation(environment, 100 /* eventCount */);
+ TestSensorOperation.createOperation(environment, 100 /* eventCount */);
continuousOperation.addVerification(new EventOrderingVerification());
operation.add(new RepeatingSensorOperation(continuousOperation, ITERATIONS));
@@ -93,12 +91,12 @@
sensor.getMinDelay(),
MAX_REPORTING_LATENCY_US);
TestSensorOperation batchingOperation =
- new TestSensorOperation(batchingEnvironment, 100 /* eventCount */);
+ TestSensorOperation.createOperation(batchingEnvironment, 100 /* eventCount */);
batchingOperation.addVerification(new EventOrderingVerification());
operation.add(new RepeatingSensorOperation(batchingOperation, ITERATIONS));
}
- operation.execute();
- SensorStats.logStats(TAG, operation.getStats());
+ operation.execute(getCurrentTestNode());
+ operation.getStats().log(TAG);
}
/**
@@ -145,7 +143,7 @@
generateSamplingRateInUs(sensorType),
generateReportLatencyInUs());
TestSensorOperation sensorOperation =
- new TestSensorOperation(environment, 100 /* eventCount */);
+ TestSensorOperation.createOperation(environment, 100 /* eventCount */);
sensorOperation.addVerification(new EventOrderingVerification());
sequentialOperation.add(sensorOperation);
}
@@ -153,8 +151,8 @@
}
}
- operation.execute();
- SensorStats.logStats(TAG, operation.getStats());
+ operation.execute(getCurrentTestNode());
+ operation.getStats().log(TAG);
}
/**
@@ -229,7 +227,7 @@
shouldEmulateSensorUnderLoad(),
SensorManager.SENSOR_DELAY_FASTEST);
TestSensorOperation tester =
- new TestSensorOperation(testerEnvironment, 100 /* event count */);
+ TestSensorOperation.createOperation(testerEnvironment, 100 /* event count */);
tester.addVerification(new EventOrderingVerification());
TestSensorEnvironment testeeEnvironment = new TestSensorEnvironment(
@@ -237,18 +235,18 @@
sensorTypeTestee,
shouldEmulateSensorUnderLoad(),
SensorManager.SENSOR_DELAY_FASTEST);
- VerifiableSensorOperation testee =
- new TestSensorOperation(testeeEnvironment, 100 /* event count */);
+ TestSensorOperation testee =
+ TestSensorOperation.createOperation(testeeEnvironment, 100 /* event count */);
testee.addVerification(new EventOrderingVerification());
ParallelSensorOperation operation = new ParallelSensorOperation();
operation.add(tester, testee);
- operation.execute();
- SensorStats.logStats(TAG, operation.getStats());
+ operation.execute(getCurrentTestNode());
+ operation.getStats().log(TAG);
testee = testee.clone();
- testee.execute();
- SensorStats.logStats(TAG, testee.getStats());
+ testee.execute(getCurrentTestNode());
+ testee.getStats().log(TAG);
}
/**
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index e8e0f252..90893ee 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -18,6 +18,8 @@
import com.android.cts.util.TimeoutReq;
+import junit.framework.Assert;
+
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
@@ -27,6 +29,16 @@
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
+import android.hardware.cts.helpers.SensorNotSupportedException;
+import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
+import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.TestSensorEventListener;
+import android.hardware.cts.helpers.TestSensorManager;
+import android.hardware.cts.helpers.sensoroperations.ParallelSensorOperation;
+import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
+import android.hardware.cts.helpers.sensorverification.EventGapVerification;
+import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
+import android.hardware.cts.helpers.sensorverification.EventTimestampSynchronizationVerification;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.PowerManager;
@@ -35,37 +47,52 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class SensorTest extends SensorTestCase {
- private SensorManager mSensorManager;
- private TriggerListener mTriggerListener;
- private SensorListener mSensorListener;
- private List<Sensor> mSensorList;
private static final String TAG = "SensorTest";
+
// Test only SDK defined sensors. Any sensors with type > 100 are ignored.
private static final int MAX_OFFICIAL_ANDROID_SENSOR_TYPE = 100;
- private static final long TIMEOUT_TOLERANCE_US = TimeUnit.SECONDS.toMicros(5);
- private static final double MIN_SAMPLING_FREQUENCY_MULTIPLIER_TOLERANCE = 0.9;
+
private PowerManager.WakeLock mWakeLock;
+ private SensorManager mSensorManager;
+ private NullTriggerEventListener mNullTriggerEventListener;
+ private NullSensorEventListener mNullSensorEventListener;
+ private List<Sensor> mSensorList;
@Override
protected void setUp() throws Exception {
- super.setUp();
- mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
- mTriggerListener = new TriggerListener();
- mSensorListener = new SensorListener();
- mSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
- PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
+ Context context = getContext();
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ mNullTriggerEventListener = new NullTriggerEventListener();
+ mNullSensorEventListener = new NullSensorEventListener();
+
+ mSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+ assertNotNull("SensorList was null.", mSensorList);
+ if (mSensorList.isEmpty()) {
+ // several devices will not have sensors, so we need to skip the tests in those cases
+ throw new SensorTestStateNotSupportedException(
+ "Sensors are not available in the system.");
+ }
+
+ mWakeLock.acquire();
}
+ @Override
+ protected void tearDown(){
+ if (mWakeLock != null && mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
public void testSensorOperations() {
// Because we can't know every sensors unit details, so we can't assert
// get values with specified values.
- List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
- assertNotNull(sensors);
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
boolean hasAccelerometer = getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_SENSOR_ACCELEROMETER);
@@ -150,7 +177,6 @@
}
assertTrue(sensors.get(0).getName() + " defined as non-wake-up sensor",
sensors.get(0).isWakeUpSensor());
- return;
}
// Some sensors like proximity, significant motion etc. are defined as wake-up sensors by
@@ -208,371 +234,137 @@
public void testRequestTriggerWithNonTriggerSensor() {
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- boolean result;
- if (sensor != null) {
- result = mSensorManager.requestTriggerSensor(mTriggerListener, sensor);
- assertFalse(result);
+ if (sensor == null) {
+ throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
}
+ boolean result = mSensorManager.requestTriggerSensor(mNullTriggerEventListener, sensor);
+ assertFalse(result);
}
public void testCancelTriggerWithNonTriggerSensor() {
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- boolean result;
- if (sensor != null) {
- result = mSensorManager.cancelTriggerSensor(mTriggerListener, sensor);
- assertFalse(result);
+ if (sensor == null) {
+ throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
}
+ boolean result = mSensorManager.cancelTriggerSensor(mNullTriggerEventListener, sensor);
+ assertFalse(result);
}
public void testRegisterWithTriggerSensor() {
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
- boolean result;
- if (sensor != null) {
- result = mSensorManager.registerListener(mSensorListener, sensor,
- SensorManager.SENSOR_DELAY_NORMAL);
- assertFalse(result);
+ if (sensor == null) {
+ throw new SensorNotSupportedException(Sensor.TYPE_SIGNIFICANT_MOTION);
}
+ boolean result = mSensorManager.registerListener(
+ mNullSensorEventListener,
+ sensor,
+ SensorManager.SENSOR_DELAY_NORMAL);
+ assertFalse(result);
}
public void testRegisterTwiceWithSameSensor() {
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- boolean result;
- if (sensor != null) {
- result = mSensorManager.registerListener(mSensorListener, sensor,
- SensorManager.SENSOR_DELAY_NORMAL);
- assertTrue(result);
- result = mSensorManager.registerListener(mSensorListener, sensor,
- SensorManager.SENSOR_DELAY_NORMAL);
- assertFalse(result);
+ if (sensor == null) {
+ throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
}
+
+ boolean result = mSensorManager.registerListener(mNullSensorEventListener, sensor,
+ SensorManager.SENSOR_DELAY_NORMAL);
+ assertTrue(result);
+
+ result = mSensorManager.registerListener(mNullSensorEventListener, sensor,
+ SensorManager.SENSOR_DELAY_NORMAL);
+ assertFalse(result);
}
- class SensorEventTimeStampListener implements SensorEventListener {
- SensorEventTimeStampListener(long eventReportLatencyNs, CountDownLatch latch) {
- mEventReportLatencyNs = eventReportLatencyNs;
- mPrevTimeStampNs = -1;
- mLatch = latch;
- numErrors = 0;
- }
-
- @Override
- public void onSensorChanged(SensorEvent event) {
- if (mPrevTimeStampNs == -1) {
- mPrevTimeStampNs = event.timestamp;
- return;
- }
- long currTimeStampNs = event.timestamp;
- if (currTimeStampNs <= mPrevTimeStampNs) {
- Log.w(TAG, "Timestamps not monotonically increasing curr_ts_ns=" +
- event.timestamp + " prev_ts_ns=" + mPrevTimeStampNs);
- numErrors++;
- mPrevTimeStampNs = currTimeStampNs;
- return;
- }
- mLatch.countDown();
-
- final long elapsedRealtimeNs = SystemClock.elapsedRealtimeNanos();
-
- if (elapsedRealtimeNs <= currTimeStampNs) {
- Log.w(TAG, "Timestamps into the future curr elapsedRealTimeNs=" + elapsedRealtimeNs
- + " current sensor ts_ns=" + currTimeStampNs);
- ++numErrors;
- } else if (elapsedRealtimeNs-currTimeStampNs > SYNC_TOLERANCE + mEventReportLatencyNs) {
- Log.w(TAG, "Timestamp sync error elapsedRealTimeNs=" + elapsedRealtimeNs +
- " curr_ts_ns=" + currTimeStampNs +
- " diff_ns=" + (elapsedRealtimeNs - currTimeStampNs) +
- " SYNC_TOLERANCE_NS=" + SYNC_TOLERANCE +
- " eventReportLatencyNs=" + mEventReportLatencyNs);
- ++numErrors;
- }
- mPrevTimeStampNs = currTimeStampNs;
- }
-
- public int getNumErrors() {
- return numErrors;
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- }
-
- private int numErrors;
- private long mEventReportLatencyNs;
- private long mPrevTimeStampNs;
- private final CountDownLatch mLatch;
- private final long SYNC_TOLERANCE = 500000000L; // 500 milli seconds approx.
- }
-
- // Register for each sensor and compare the timestamps of SensorEvents that you get with
- // elapsedRealTimeNano.
+ // TODO: remove when parametized tests are supported and EventTimestampSynchronization
+ // verification is added to default verifications
@TimeoutReq(minutes=60)
public void testSensorTimeStamps() throws Exception {
- final int numEvents = 2000;
- try {
- mWakeLock.acquire();
- int numErrors = 0;
- for (Sensor sensor : mSensorList) {
- // Skip OEM defined sensors and non continuous sensors.
- if (sensor.getReportingMode() != Sensor.REPORTING_MODE_CONTINUOUS) {
- continue;
- }
-
- for (int iterations = 0; iterations < 2; ++iterations) {
- // Test in both batch mode and non-batch mode for every sensor.
- long maxBatchReportLatencyNs = 10000000000L; // 10 secs
- if (iterations % 2 == 0) maxBatchReportLatencyNs = 0;
-
- final long samplingPeriodNs = (long)(TimeUnit.MICROSECONDS.toNanos(
- sensor.getMinDelay())/MIN_SAMPLING_FREQUENCY_MULTIPLIER_TOLERANCE);
- // If there is a FIFO and a wake-lock is held, events will be reported when
- // the batch timeout expires or when the FIFO is full which ever occurs
- // earlier.
- final long eventReportLatencyNs = Math.min(maxBatchReportLatencyNs,
- sensor.getFifoMaxEventCount() * samplingPeriodNs);
-
- final CountDownLatch eventsRemaining = new CountDownLatch(numEvents);
- SensorEventTimeStampListener listener = new SensorEventTimeStampListener(
- eventReportLatencyNs, eventsRemaining);
-
- Log.i(TAG, "Running timeStamp test on " + sensor.getName());
- boolean result = mSensorManager.registerListener(listener, sensor,
- SensorManager.SENSOR_DELAY_FASTEST,
- (int)maxBatchReportLatencyNs/1000);
- assertTrue("Sensor registerListener failed ", result);
-
- long timeToWaitUs = samplingPeriodNs/1000 + eventReportLatencyNs/1000 +
- TIMEOUT_TOLERANCE_US;
- long totalTimeWaitedUs = waitToCollectAllEvents(timeToWaitUs,
- (int)(eventReportLatencyNs/1000), eventsRemaining);
-
- mSensorManager.unregisterListener(listener);
- if (eventsRemaining.getCount() > 0) {
- failTimedOut(sensor.getName(), (double) totalTimeWaitedUs/1000,
- numEvents, (double) sensor.getMinDelay()/1000,
- eventsRemaining.getCount(),
- numEvents - eventsRemaining.getCount());
- }
- if (listener.getNumErrors() > 5) {
- fail("Check logcat. Timestamp test failed. numErrors=" +
- listener.getNumErrors() + " " + sensor.getName() +
- " maxBatchReportLatencyNs=" + maxBatchReportLatencyNs +
- " samplingPeriodNs=" + sensor.getMinDelay());
- numErrors += listener.getNumErrors();
- } else {
- Log.i(TAG, "TimeStamp test PASS'd on " + sensor.getName());
- }
- }
- }
- } finally {
- mWakeLock.release();
+ ArrayList<Throwable> errorsFound = new ArrayList<>();
+ for (Sensor sensor : mSensorList) {
+ // test both continuous and batching mode sensors
+ verifyLongActivation(sensor, 0 /* maxReportLatencyUs */, errorsFound);
+ verifyLongActivation(sensor, (int) TimeUnit.SECONDS.toMicros(10), errorsFound);
}
+ assertOnErrors(errorsFound);
}
- private void failTimedOut(String sensorName, double totalTimeWaitedMs, int numEvents,
- double minDelayMs, long eventsRemaining, long eventsReceived) {
- final String TIMED_OUT_FORMAT = "Timed out waiting for events from %s " +
- "waited for time=%.1fms to receive totalEvents=%d at samplingRate=%.1fHz" +
- " remainingEvents=%d received events=%d";
- fail(String.format(TIMED_OUT_FORMAT, sensorName, totalTimeWaitedMs, numEvents,
- 1000/minDelayMs, eventsRemaining, eventsReceived));
- }
-
- // Register for updates from each continuous mode sensor, wait for N events, call flush and
- // wait for flushCompleteEvent before unregistering for the sensor.
+ // TODO: remove when parameterized tests are supported (see SensorBatchingTests.java)
@TimeoutReq(minutes=20)
public void testBatchAndFlush() throws Exception {
- try {
- mWakeLock.acquire();
- for (Sensor sensor : mSensorList) {
- // Skip ONLY one-shot sensors.
- if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
- registerListenerCallFlush(sensor, null);
- }
- }
- } finally {
- mWakeLock.release();
+ ArrayList<Throwable> errorsFound = new ArrayList<>();
+ for (Sensor sensor : mSensorList) {
+ verifyRegisterListenerCallFlush(sensor, null /* handler */, errorsFound);
}
+ assertOnErrors(errorsFound);
}
- // Same as testBatchAndFlush but using Handler version of the API to register for sensors.
- // onSensorChanged is now called on a background thread.
+ /**
+ * Verifies that sensor events arrive in the given message queue (Handler).
+ */
@TimeoutReq(minutes=10)
public void testBatchAndFlushWithHandler() throws Exception {
- try {
- mWakeLock.acquire();
- HandlerThread handlerThread = new HandlerThread("sensorThread");
- handlerThread.start();
- Handler handler = new Handler(handlerThread.getLooper());
- for (Sensor sensor : mSensorList) {
- // Skip ONLY one-shot sensors.
- if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
- registerListenerCallFlush(sensor, handler);
- }
+ Sensor sensor = null;
+ for (Sensor s : mSensorList) {
+ if (s.getReportingMode() == Sensor.REPORTING_MODE_CONTINUOUS) {
+ sensor = s;
+ break;
}
- } finally {
- mWakeLock.release();
}
+ if (sensor == null) {
+ throw new SensorTestStateNotSupportedException(
+ "There are no Continuous sensors in the device.");
+ }
+
+ TestSensorEnvironment environment = new TestSensorEnvironment(
+ getContext(),
+ sensor,
+ SensorManager.SENSOR_DELAY_FASTEST,
+ (int) TimeUnit.SECONDS.toMicros(5));
+ TestSensorManager sensorManager = new TestSensorManager(environment);
+
+ HandlerThread handlerThread = new HandlerThread("sensorThread");
+ handlerThread.start();
+ Handler handler = new Handler(handlerThread.getLooper());
+ TestSensorEventListener listener = new TestSensorEventListener(environment, handler);
+
+ sensorManager.registerListener(listener);
+ listener.waitForEvents(1);
+ sensorManager.requestFlush();
+ listener.waitForFlushComplete();
+ listener.assertEventsReceivedInHandler();
}
- private void registerListenerCallFlush(Sensor sensor, Handler handler)
- throws InterruptedException {
- if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
- return;
- }
- final int numEvents = 500;
- final int rateUs = 0; // DELAY_FASTEST
- final int maxBatchReportLatencyUs = 10000000;
- final CountDownLatch eventsRemaining = new CountDownLatch(numEvents);
- final CountDownLatch flushReceived = new CountDownLatch(1);
- SensorEventListener2 listener = new SensorEventListener2() {
- @Override
- public void onSensorChanged(SensorEvent event) {
- eventsRemaining.countDown();
- }
+ // TODO: after L release move to SensorBatchingTests and run in all sensors with default
+ // verifications enabled
+ public void testBatchAndFlushWithMultipleSensors() throws Exception {
+ final int maxSensors = 3;
+ final int maxReportLatencyUs = (int) TimeUnit.SECONDS.toMicros(10);
+ int sensorsCount = mSensorList.size();
+ int numSensors = sensorsCount < maxSensors ? sensorsCount : maxSensors;
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- }
-
- @Override
- public void onFlushCompleted(Sensor sensor) {
- flushReceived.countDown();
- }
- };
- // Consider only continuous mode sensors for testing registerListener.
- // For on-change sensors, call registerListener() so that the listener is associated
- // with the sensor so that flush(listener) can be called on it.
- try {
- Log.i(TAG, "testBatch " + sensor.getName());
- boolean result = mSensorManager.registerListener(listener, sensor,
- rateUs, maxBatchReportLatencyUs, handler);
- assertTrue("registerListener failed " + sensor.getName(), result);
-
- // Wait for 500 events or N seconds before the test times out.
+ StringBuilder builder = new StringBuilder();
+ ParallelSensorOperation parallelSensorOperation = new ParallelSensorOperation();
+ for (int i = 0; i < sensorsCount && numSensors > 0; ++i) {
+ Sensor sensor = mSensorList.get(i);
+ // skip all non-continuous sensors
if (sensor.getReportingMode() == Sensor.REPORTING_MODE_CONTINUOUS) {
- // Wait for approximately the time required to generate these events + a tolerance
- // of 10 seconds.
- long timeToWaitUs =
- numEvents*(long)(sensor.getMinDelay()/MIN_SAMPLING_FREQUENCY_MULTIPLIER_TOLERANCE)
- + maxBatchReportLatencyUs + TIMEOUT_TOLERANCE_US;
-
- long totalTimeWaitedUs = waitToCollectAllEvents(timeToWaitUs,
- maxBatchReportLatencyUs, eventsRemaining);
- if (eventsRemaining.getCount() > 0) {
- failTimedOut(sensor.getName(), (double)totalTimeWaitedUs/1000, numEvents,
- (double)sensor.getMinDelay()/1000,
- eventsRemaining.getCount(), numEvents - eventsRemaining.getCount());
- }
- }
- Log.i(TAG, "testFlush " + sensor.getName());
- result = mSensorManager.flush(listener);
- assertTrue("flush failed " + sensor.getName(), result);
- boolean collectedAllEvents = flushReceived.await(TIMEOUT_TOLERANCE_US,
- TimeUnit.MICROSECONDS);
- if (!collectedAllEvents) {
- fail("Timed out waiting for flushCompleteEvent from " + sensor.getName() +
- " waitedFor="+ TIMEOUT_TOLERANCE_US/1000 + "ms");
- }
- Log.i(TAG, "testBatchAndFlush PASS " + sensor.getName());
- } finally {
- mSensorManager.unregisterListener(listener);
- }
- }
-
- // Wait till the CountDownLatch counts down to zero. If the events are not delivered within
- // timetoWaitUs, wait an additional maxReportLantencyUs and check if the sensor is streaming
- // data or not. If the sensor is not streaming at all, fail the test or else wait in increments
- // of maxReportLantencyUs to collect sensor events.
- private long waitToCollectAllEvents(long timeToWaitUs, int maxReportLatencyUs,
- CountDownLatch eventsRemaining)
- throws InterruptedException {
- boolean collectedAllEvents = false;
- long totalTimeWaitedUs = 0;
- long remainingEvents;
- final long INCREMENTAL_WAIT_US = maxReportLatencyUs + TimeUnit.SECONDS.toMicros(1);
- do {
- totalTimeWaitedUs += timeToWaitUs;
- remainingEvents = eventsRemaining.getCount();
- collectedAllEvents = eventsRemaining.await(timeToWaitUs, TimeUnit.MICROSECONDS);
- timeToWaitUs = INCREMENTAL_WAIT_US;
- } while (!collectedAllEvents &&
- (remainingEvents - eventsRemaining.getCount() >=(long)INCREMENTAL_WAIT_US/1000000));
- return totalTimeWaitedUs;
- }
-
- // Call registerListener for multiple sensors at a time and call flush.
- public void testBatchAndFlushWithMutipleSensors() throws Exception {
- final int MAX_SENSORS = 3;
- List<Sensor> sensorsToTest = new ArrayList<Sensor>();
- for (Sensor sensor : mSensorList) {
- if (sensor.getReportingMode() == Sensor.REPORTING_MODE_CONTINUOUS) {
- sensorsToTest.add(sensor);
- if (sensorsToTest.size() == MAX_SENSORS) break;
+ TestSensorEnvironment environment = new TestSensorEnvironment(
+ getContext(),
+ sensor,
+ shouldEmulateSensorUnderLoad(),
+ SensorManager.SENSOR_DELAY_FASTEST,
+ maxReportLatencyUs);
+ FlushExecutor executor = new FlushExecutor(environment, 500 /* eventCount */);
+ parallelSensorOperation.add(new TestSensorOperation(environment, executor));
+ --numSensors;
+ builder.append(sensor.getName()).append(", ");
}
}
- final int numSensorsToTest = sensorsToTest.size();
- if (numSensorsToTest == 0) {
- return;
- }
- final int numEvents = 500;
- int rateUs = 0; // DELAY_FASTEST
- final int maxBatchReportLatencyUs = 10000000;
- final CountDownLatch eventsRemaining = new CountDownLatch(numSensorsToTest * numEvents);
- final CountDownLatch flushReceived = new CountDownLatch(numSensorsToTest);
- SensorEventListener2 listener = new SensorEventListener2() {
- @Override
- public void onSensorChanged(SensorEvent event) {
- eventsRemaining.countDown();
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- }
-
- @Override
- public void onFlushCompleted(Sensor sensor) {
- flushReceived.countDown();
- }
- };
-
- try {
- mWakeLock.acquire();
- StringBuilder registeredSensors = new StringBuilder(30);
- for (Sensor sensor : sensorsToTest) {
- rateUs = Math.max(sensor.getMinDelay(), rateUs);
- boolean result = mSensorManager.registerListener(listener, sensor,
- SensorManager.SENSOR_DELAY_FASTEST, maxBatchReportLatencyUs);
- assertTrue("registerListener failed for " + sensor.getName(), result);
- registeredSensors.append(sensor.getName());
- registeredSensors.append(" ");
- }
-
- Log.i(TAG, "testBatchAndFlushWithMutipleSensors " + registeredSensors);
- long timeToWaitUs =
- numEvents*(long)(rateUs/MIN_SAMPLING_FREQUENCY_MULTIPLIER_TOLERANCE) +
- maxBatchReportLatencyUs + TIMEOUT_TOLERANCE_US;
-
- long totalTimeWaitedUs = waitToCollectAllEvents(timeToWaitUs, maxBatchReportLatencyUs,
- eventsRemaining);
- if (eventsRemaining.getCount() > 0) {
- failTimedOut(registeredSensors.toString(), (double)totalTimeWaitedUs/1000,
- numEvents, (double)rateUs/1000, eventsRemaining.getCount(),
- numEvents - eventsRemaining.getCount());
- }
- boolean result = mSensorManager.flush(listener);
- assertTrue("flush failed " + registeredSensors.toString(), result);
- boolean collectedFlushEvent =
- flushReceived.await(TIMEOUT_TOLERANCE_US, TimeUnit.MICROSECONDS);
- if (!collectedFlushEvent) {
- fail("Timed out waiting for flushCompleteEvent from " +
- registeredSensors.toString() + " waited for=" + timeToWaitUs/1000 + "ms");
- }
- Log.i(TAG, "testBatchAndFlushWithMutipleSensors PASS'd");
- } finally {
- mSensorManager.unregisterListener(listener);
- mWakeLock.release();
- }
+ Log.i(TAG, "Testing batch/flush for sensors: " + builder);
+ parallelSensorOperation.execute(getCurrentTestNode());
}
private void assertSensorValues(Sensor sensor) {
@@ -583,8 +375,8 @@
assertTrue("Max resolution must be positive. Resolution=" + sensor.getResolution() +
" " + sensor.getName(), sensor.getResolution() >= 0);
assertNotNull("Vendor name must not be null " + sensor.getName(), sensor.getVendor());
- assertTrue("Version must be positive version=" + sensor.getVersion() + " " +
- sensor.getName(), sensor.getVersion() > 0);
+ assertTrue("Version must be positive version=" + sensor.getVersion() + " " +
+ sensor.getName(), sensor.getVersion() > 0);
int fifoMaxEventCount = sensor.getFifoMaxEventCount();
int fifoReservedEventCount = sensor.getFifoReservedEventCount();
assertTrue(fifoMaxEventCount >= 0);
@@ -617,19 +409,142 @@
assertEquals(sensors, mSensorManager.getSensors());
}
- class TriggerListener extends TriggerEventListener {
- @Override
- public void onTrigger(TriggerEvent event) {
+ /**
+ * Verifies that a continuous sensor produces events that have timestamps synchronized with
+ * {@link SystemClock#elapsedRealtimeNanos()}.
+ */
+ private void verifyLongActivation(
+ Sensor sensor,
+ int maxReportLatencyUs,
+ ArrayList<Throwable> errorsFound) throws InterruptedException {
+ if (sensor.getReportingMode() != Sensor.REPORTING_MODE_CONTINUOUS) {
+ return;
+ }
+
+ try {
+ TestSensorEnvironment environment = new TestSensorEnvironment(
+ getContext(),
+ sensor,
+ shouldEmulateSensorUnderLoad(),
+ SensorManager.SENSOR_DELAY_FASTEST,
+ maxReportLatencyUs);
+ TestSensorOperation operation =
+ TestSensorOperation.createOperation(environment, 20, TimeUnit.SECONDS);
+ operation.addVerification(EventGapVerification.getDefault(environment));
+ operation.addVerification(EventOrderingVerification.getDefault(environment));
+ operation.addVerification(
+ EventTimestampSynchronizationVerification.getDefault(environment));
+
+ Log.i(TAG, "Running timestamp test on: " + sensor.getName());
+ operation.execute(getCurrentTestNode());
+ } catch (InterruptedException e) {
+ // propagate so the test can stop
+ throw e;
+ } catch (Throwable e) {
+ errorsFound.add(e);
+ Log.e(TAG, e.getMessage());
}
}
- class SensorListener implements SensorEventListener {
- @Override
- public void onSensorChanged(SensorEvent event) {
+ /**
+ * Verifies that a client can listen for events, and that
+ * {@link SensorManager#flush(SensorEventListener)} will trigger the appropriate notification
+ * for {@link SensorEventListener2#onFlushCompleted(Sensor)}.
+ */
+ private void verifyRegisterListenerCallFlush(
+ Sensor sensor,
+ Handler handler,
+ ArrayList<Throwable> errorsFound)
+ throws InterruptedException {
+ if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
+ return;
}
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ try {
+ TestSensorEnvironment environment = new TestSensorEnvironment(
+ getContext(),
+ sensor,
+ shouldEmulateSensorUnderLoad(),
+ SensorManager.SENSOR_DELAY_FASTEST,
+ (int) TimeUnit.SECONDS.toMicros(10));
+ FlushExecutor executor = new FlushExecutor(environment, 500 /* eventCount */);
+ TestSensorOperation operation = new TestSensorOperation(environment, executor, handler);
+
+ Log.i(TAG, "Running flush test on: " + sensor.getName());
+ operation.execute(getCurrentTestNode());
+ } catch (InterruptedException e) {
+ // propagate so the test can stop
+ throw e;
+ } catch (Throwable e) {
+ errorsFound.add(e);
+ Log.e(TAG, e.getMessage());
}
}
+
+ private void assertOnErrors(List<Throwable> errorsFound) {
+ if (!errorsFound.isEmpty()) {
+ StringBuilder builder = new StringBuilder();
+ for (Throwable error : errorsFound) {
+ builder.append(error.getMessage()).append("\n");
+ }
+ Assert.fail(builder.toString());
+ }
+ }
+
+ /**
+ * A delegate that drives the execution of Batch/Flush tests.
+ * It performs several operations in order:
+ * - registration
+ * - for continuous sensors it first ensures that the FIFO is filled
+ * - if events do not arrive on time, an assert will be triggered
+ * - requests flush of sensor data
+ * - waits for {@link SensorEventListener2#onFlushCompleted(Sensor)}
+ * - if the event does not arrive, an assert will be triggered
+ */
+ private class FlushExecutor implements TestSensorOperation.Executor {
+ private final TestSensorEnvironment mEnvironment;
+ private final int mEventCount;
+
+ public FlushExecutor(TestSensorEnvironment environment, int eventCount) {
+ mEnvironment = environment;
+ mEventCount = eventCount;
+ }
+
+ /**
+ * Consider only continuous mode sensors for testing register listener.
+ *
+ * For on-change sensors, we only use
+ * {@link TestSensorManager#registerListener(TestSensorEventListener)} to associate the
+ * listener with the sensor. So that {@link TestSensorManager#requestFlush()} can be
+ * invoked on it.
+ */
+ @Override
+ public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
+ throws InterruptedException {
+ int sensorReportingMode = mEnvironment.getSensor().getReportingMode();
+ try {
+ sensorManager.registerListener(listener);
+ if (sensorReportingMode == Sensor.REPORTING_MODE_CONTINUOUS) {
+ listener.waitForEvents(mEventCount);
+ }
+ sensorManager.requestFlush();
+ listener.waitForFlushComplete();
+ } finally {
+ sensorManager.unregisterListener();
+ }
+ }
+ }
+
+ private class NullTriggerEventListener extends TriggerEventListener {
+ @Override
+ public void onTrigger(TriggerEvent event) {}
+ }
+
+ private class NullSensorEventListener implements SensorEventListener {
+ @Override
+ public void onSensorChanged(SensorEvent event) {}
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java b/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
index 6454678..42b8d33 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
@@ -16,17 +16,11 @@
package android.hardware.cts;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-
-import android.app.Instrumentation;
-import android.cts.util.DeviceReportLog;
import android.hardware.Sensor;
-import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
import android.hardware.cts.helpers.TestSensorEnvironment;
-import android.hardware.cts.helpers.sensoroperations.ISensorOperation;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
+import android.hardware.cts.helpers.sensoroperations.SensorOperation;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -35,25 +29,30 @@
*/
public abstract class SensorTestCase extends AndroidTestCase {
// TODO: consolidate all log tags
- protected final String LOG_TAG = "TestRunner";
+ protected static final String LOG_TAG = "TestRunner";
/**
* By default tests need to run in a {@link TestSensorEnvironment} that assumes each sensor is
* running with a load of several listeners, requesting data at different rates.
*
- * In a better world the component acting as builder of {@link ISensorOperation} would compute
+ * In a better world the component acting as builder of {@link SensorOperation} would compute
* this value based on the tests composed.
*
* Ideally, each {@link Sensor} object would expose this information to clients.
*/
private volatile boolean mEmulateSensorUnderLoad = true;
+ /**
+ * By default the test class is the root of the test hierarchy.
+ */
+ private volatile ISensorTestNode mCurrentTestNode = new TestClassNode(getClass());
+
protected SensorTestCase() {}
@Override
- public void runTest() throws Throwable {
+ public void runBare() throws Throwable {
try {
- super.runTest();
+ super.runBare();
} catch (SensorTestStateNotSupportedException e) {
// the sensor state is not supported in the device, log a warning and skip the test
Log.w(LOG_TAG, e.getMessage());
@@ -68,33 +67,24 @@
return mEmulateSensorUnderLoad;
}
- /**
- * Utility method to log selected stats to a {@link ReportLog} object. The stats must be
- * a number or an array of numbers.
- */
- public static void logSelectedStatsToReportLog(Instrumentation instrumentation, int depth,
- String[] keys, SensorStats stats) {
- DeviceReportLog reportLog = new DeviceReportLog(depth);
+ public void setCurrentTestNode(ISensorTestNode value) {
+ mCurrentTestNode = value;
+ }
- for (String key : keys) {
- Object value = stats.getValue(key);
- if (value instanceof Integer) {
- reportLog.printValue(key, (Integer) value, ResultType.NEUTRAL, ResultUnit.NONE);
- } else if (value instanceof Double) {
- reportLog.printValue(key, (Double) value, ResultType.NEUTRAL, ResultUnit.NONE);
- } else if (value instanceof Float) {
- reportLog.printValue(key, (Float) value, ResultType.NEUTRAL, ResultUnit.NONE);
- } else if (value instanceof double[]) {
- reportLog.printArray(key, (double[]) value, ResultType.NEUTRAL, ResultUnit.NONE);
- } else if (value instanceof float[]) {
- float[] tmpFloat = (float[]) value;
- double[] tmpDouble = new double[tmpFloat.length];
- for (int i = 0; i < tmpDouble.length; i++) tmpDouble[i] = tmpFloat[i];
- reportLog.printArray(key, tmpDouble, ResultType.NEUTRAL, ResultUnit.NONE);
- }
+ protected ISensorTestNode getCurrentTestNode() {
+ return mCurrentTestNode;
+ }
+
+ private class TestClassNode implements ISensorTestNode {
+ private final Class<?> mTestClass;
+
+ public TestClassNode(Class<?> testClass) {
+ mTestClass = testClass;
}
- reportLog.printSummary("summary", 0, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.deliverReportToHost(instrumentation);
+ @Override
+ public String getName() {
+ return mTestClass.getSimpleName();
+ }
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java b/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
index 3bd4a03..42cbdfb 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
@@ -105,7 +105,7 @@
*/
public void testSensorProperties() {
// sensor type: [getMinDelay()]
- Map<Integer, Object[]> expectedProperties = new HashMap<Integer, Object[]>(3);
+ Map<Integer, Object[]> expectedProperties = new HashMap<>(3);
expectedProperties.put(Sensor.TYPE_ACCELEROMETER, new Object[]{10000});
expectedProperties.put(Sensor.TYPE_GYROSCOPE, new Object[]{10000});
expectedProperties.put(Sensor.TYPE_MAGNETIC_FIELD, new Object[]{100000});
@@ -541,25 +541,21 @@
sensorType,
shouldEmulateSensorUnderLoad(),
rateUs);
- TestSensorOperation op = new TestSensorOperation(environment, 5, TimeUnit.SECONDS);
+ TestSensorOperation op =
+ TestSensorOperation.createOperation(environment, 5, TimeUnit.SECONDS);
op.addDefaultVerifications();
- op.setLogEvents(true);
- try {
- op.execute();
- } finally {
- SensorStats.logStats(TAG, op.getStats());
- String sensorRate;
- if (rateUs == SensorManager.SENSOR_DELAY_FASTEST) {
- sensorRate = "fastest";
- } else {
- sensorRate = String.format("%.0fhz", environment.getFrequencyHz());
- }
+ try {
+ op.execute(getCurrentTestNode());
+ } finally {
+ SensorStats stats = op.getStats();
+ stats.log(TAG);
+
String fileName = String.format(
"single_%s_%s.txt",
SensorStats.getSanitizedSensorName(environment.getSensor()),
- sensorRate);
- SensorStats.logStatsToFile(fileName, op.getStats());
+ environment.getFrequencyString());
+ stats.logToFile(fileName);
}
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java
deleted file mode 100644
index ca7d133..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers;
-
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener2;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A {@link TestSensorEventListener} which collects events to be processed after the test is run.
- * This should only be used for short tests.
- */
-public class CollectingSensorEventListener extends TestSensorEventListener {
- private final ArrayList<TestSensorEvent> mSensorEventsList = new ArrayList<TestSensorEvent>();
-
- /**
- * Constructs a {@link CollectingSensorEventListener} with an additional
- * {@link SensorEventListener2}.
- */
- public CollectingSensorEventListener(SensorEventListener2 listener) {
- super(listener);
- }
-
- /**
- * Constructs a {@link CollectingSensorEventListener}.
- */
- public CollectingSensorEventListener() {
- this(null);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onSensorChanged(SensorEvent event) {
- super.onSensorChanged(event);
- synchronized (mSensorEventsList) {
- mSensorEventsList.add(new TestSensorEvent(event));
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Clears the event queue before starting.
- * </p>
- */
- @Override
- public void waitForEvents(int eventCount) throws InterruptedException {
- clearEvents();
- super.waitForEvents(eventCount);
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Clears the event queue before starting.
- * </p>
- */
- @Override
- public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
- clearEvents();
- super.waitForEvents(duration, timeUnit);
- }
-
- /**
- * Get the {@link TestSensorEvent} array from the event queue.
- */
- public List<TestSensorEvent> getEvents() {
- synchronized (mSensorEventsList) {
- return Collections.unmodifiableList(mSensorEventsList);
- }
- }
-
- /**
- * Clear the event queue.
- */
- public void clearEvents() {
- synchronized (mSensorEventsList) {
- mSensorEventsList.clear();
- }
- }
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java
index b3b8559..d3dcf37 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java
@@ -35,6 +35,8 @@
private final TestSensorManager mCalibratedSensorManager;
private final TestSensorManager mUncalibratedSensorManager;
+ private final TestSensorEventListener mCalibratedTestListener;
+ private final TestSensorEventListener mUncalibratedTestListener;
private final float mThreshold;
public SensorCalibratedUncalibratedVerifier(
@@ -43,6 +45,8 @@
float threshold) {
mCalibratedSensorManager = new TestSensorManager(calibratedEnvironment);
mUncalibratedSensorManager = new TestSensorManager(uncalibratedEnvironment);
+ mCalibratedTestListener = new TestSensorEventListener(calibratedEnvironment);
+ mUncalibratedTestListener = new TestSensorEventListener(uncalibratedEnvironment);
mThreshold = threshold;
}
@@ -50,10 +54,8 @@
* Executes the operation: it collects the data and run verifications on it.
*/
public void execute() throws Throwable {
- CollectingSensorEventListener calibratedTestListener = new CollectingSensorEventListener();
- CollectingSensorEventListener uncalibratedTestListener = new CollectingSensorEventListener();
- mCalibratedSensorManager.registerListener(calibratedTestListener);
- mUncalibratedSensorManager.registerListener(uncalibratedTestListener);
+ mCalibratedSensorManager.registerListener(mCalibratedTestListener);
+ mUncalibratedSensorManager.registerListener(mUncalibratedTestListener);
Thread.sleep(TimeUnit.SECONDS.toMillis(10));
@@ -61,8 +63,8 @@
mUncalibratedSensorManager.unregisterListener();
verifyMeasurements(
- calibratedTestListener.getEvents(),
- uncalibratedTestListener.getEvents(),
+ mCalibratedTestListener.getCollectedEvents(),
+ mUncalibratedTestListener.getCollectedEvents(),
mThreshold);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
index a79e5b1..490e965 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
@@ -192,7 +192,7 @@
TestSensorEnvironment environment,
String extras) {
return String.format(
- "%s | sensor='%s', samplingPeriodUs=%d, maxReportLatencyUs=%d | %s",
+ "%s | sensor='%s', samplingPeriod=%dus, maxReportLatency=%dus | %s",
label,
environment.getSensor().getName(),
environment.getRequestedSamplingPeriodUs(),
@@ -219,6 +219,25 @@
}
/**
+ * Sanitizes a string so it can be used in file names.
+ *
+ * @param value The string to sanitize.
+ * @return The sanitized string.
+ *
+ * @throws SensorTestPlatformException If the string cannot be sanitized.
+ */
+ public static String sanitizeStringForFileName(String value)
+ throws SensorTestPlatformException {
+ String sanitizedValue = value.replaceAll("[^a-zA-Z0-9_\\-]", "_");
+ if (sanitizedValue.matches("_*")) {
+ throw new SensorTestPlatformException(
+ "Unable to sanitize string '%s' for file name.",
+ value);
+ }
+ return sanitizedValue;
+ }
+
+ /**
* Ensures that the directory structure represented by the given {@link File} is created.
*/
private static File createDirectoryStructure(File directoryStructure) throws IOException {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
index 7be6c0c..8067aed 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
@@ -17,7 +17,7 @@
package android.hardware.cts.helpers;
import android.hardware.Sensor;
-import android.hardware.cts.helpers.sensoroperations.ISensorOperation;
+import android.hardware.cts.helpers.sensoroperations.SensorOperation;
import android.util.Log;
import java.io.BufferedWriter;
@@ -34,28 +34,29 @@
import java.util.Set;
/**
- * Class used to store stats related to {@link ISensorOperation}s. Sensor stats may be linked
+ * Class used to store stats related to {@link SensorOperation}s. Sensor stats may be linked
* together so that they form a tree.
*/
public class SensorStats {
public static final String DELIMITER = "__";
- public static final String FIRST_TIMESTAMP_KEY = "first_timestamp";
- public static final String LAST_TIMESTAMP_KEY = "last_timestamp";
public static final String ERROR = "error";
- public static final String EVENT_COUNT_KEY = "event_count";
public static final String EVENT_GAP_COUNT_KEY = "event_gap_count";
public static final String EVENT_GAP_POSITIONS_KEY = "event_gap_positions";
public static final String EVENT_OUT_OF_ORDER_COUNT_KEY = "event_out_of_order_count";
public static final String EVENT_OUT_OF_ORDER_POSITIONS_KEY = "event_out_of_order_positions";
+ public static final String EVENT_TIME_SYNCHRONIZATION_COUNT_KEY =
+ "event_time_synchronization_count";
+ public static final String EVENT_TIME_SYNCHRONIZATION_POSITIONS_KEY =
+ "event_time_synchronization_positions";
public static final String FREQUENCY_KEY = "frequency";
public static final String JITTER_95_PERCENTILE_PERCENT_KEY = "jitter_95_percentile_percent";
public static final String MEAN_KEY = "mean";
public static final String STANDARD_DEVIATION_KEY = "standard_deviation";
public static final String MAGNITUDE_KEY = "magnitude";
- private final Map<String, Object> mValues = new HashMap<String, Object>();
- private final Map<String, SensorStats> mSensorStats = new HashMap<String, SensorStats>();
+ private final Map<String, Object> mValues = new HashMap<>();
+ private final Map<String, SensorStats> mSensorStats = new HashMap<>();
/**
* Add a value.
@@ -72,7 +73,7 @@
/**
* Add a nested {@link SensorStats}. This is useful for keeping track of stats in a
- * {@link ISensorOperation} tree.
+ * {@link SensorOperation} tree.
*
* @param key the key
* @param stats the sub {@link SensorStats} object.
@@ -103,13 +104,13 @@
/**
* Flattens the map and all sub {@link SensorStats} objects. Keys will be flattened using
* {@value #DELIMITER}. For example, if a sub {@link SensorStats} is added with key
- * {@code "key1"} containing the key value pair {@code ("key2", "value")}, the flattened map
- * will contain the entry {@code ("key1__key2", "value")}.
+ * {@code "key1"} containing the key value pair {@code \("key2", "value"\)}, the flattened map
+ * will contain the entry {@code \("key1__key2", "value"\)}.
*
* @return a {@link Map} containing all stats from the value and sub {@link SensorStats}.
*/
public synchronized Map<String, Object> flatten() {
- final Map<String, Object> flattenedMap = new HashMap<String, Object>(mValues);
+ final Map<String, Object> flattenedMap = new HashMap<>(mValues);
for (Entry<String, SensorStats> statsEntry : mSensorStats.entrySet()) {
for (Entry<String, Object> valueEntry : statsEntry.getValue().flatten().entrySet()) {
String key = statsEntry.getKey() + DELIMITER + valueEntry.getKey();
@@ -122,8 +123,8 @@
/**
* Utility method to log the stats to the logcat.
*/
- public static void logStats(String tag, SensorStats stats) {
- final Map<String, Object> flattened = stats.flatten();
+ public void log(String tag) {
+ final Map<String, Object> flattened = flatten();
for (String key : getSortedKeys(flattened)) {
Object value = flattened.get(key);
Log.v(tag, String.format("%s: %s", key, getValueString(value)));
@@ -133,39 +134,29 @@
/**
* Utility method to log the stats to a file. Will overwrite the file if it already exists.
*/
- public static void logStatsToFile(String fileName, SensorStats stats) throws IOException {
+ public void logToFile(String fileName) throws IOException {
File statsDirectory = SensorCtsHelper.getSensorTestDataDirectory("stats/");
File logFile = new File(statsDirectory, fileName);
- final BufferedWriter writer =
- new BufferedWriter(new FileWriter(logFile, false /* append */));
- final Map<String, Object> flattened = stats.flatten();
- try {
+ final Map<String, Object> flattened = flatten();
+ FileWriter fileWriter = new FileWriter(logFile, false /* append */);
+ try (BufferedWriter writer = new BufferedWriter(fileWriter)) {
for (String key : getSortedKeys(flattened)) {
Object value = flattened.get(key);
writer.write(String.format("%s: %s\n", key, getValueString(value)));
}
- } finally {
- writer.flush();
- writer.close();
}
}
/**
* Provides a sanitized sensor name, that can be used in file names.
- * See {@link #logStatsToFile(String, SensorStats)}.
+ * See {@link #logToFile(String)}.
*/
- public static String getSanitizedSensorName(Sensor sensor) throws IOException {
- String sensorType = sensor.getStringType();
- String sanitizedSensorType = sensorType.replaceAll("[^a-zA-Z0-9_\\-]", "_");
- if (sanitizedSensorType.matches("_*")) {
- throw new IOException("Unable to sanitize sensor type (" + sensorType + "). This is a"
- + " 'test framework' issue and the sanitation routine must be fixed.");
- }
- return sanitizedSensorType;
+ public static String getSanitizedSensorName(Sensor sensor) throws SensorTestPlatformException {
+ return SensorCtsHelper.sanitizeStringForFileName(sensor.getStringType());
}
private static List<String> getSortedKeys(Map<String, Object> flattenedStats) {
- List<String> keys = new ArrayList<String>(flattenedStats.keySet());
+ List<String> keys = new ArrayList<>(flattenedStats.keySet());
Collections.sort(keys);
return keys;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestPlatformException.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestPlatformException.java
new file mode 100644
index 0000000..b230749
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestPlatformException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.hardware.cts.helpers;
+
+/**
+ * Exception that indicates an issue in the Sensor Test Platform.
+ * It usually constitutes a bug in the platform that needs to be fixed.
+ */
+public class SensorTestPlatformException extends Exception {
+ public SensorTestPlatformException(String format, Object ... params) {
+ this(String.format(format, params));
+ }
+
+ public SensorTestPlatformException(String message) {
+ super(message + " (This is a 'sensor test platform' issue, please report it so it can be fixed)");
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
index 8f33f92..7d10f91 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
@@ -19,15 +19,22 @@
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
-import android.hardware.cts.helpers.sensoroperations.ISensorOperation;
+import android.hardware.cts.helpers.sensoroperations.SensorOperation;
import java.util.concurrent.TimeUnit;
/**
- * A class that encapsulates base environment information for the {@link ISensorOperation}.
+ * A class that encapsulates base environment information for the {@link SensorOperation}.
* The environment is self contained and carries its state around all the sensor test framework.
*/
public class TestSensorEnvironment {
+
+ /**
+ * It represents the fraction of the expected sampling frequency, at which the sensor can
+ * actually produce events.
+ */
+ private static final float MAXIMUM_EXPECTED_SAMPLING_FREQUENCY_MULTIPLIER = 0.9f;
+
private final Context mContext;
private final Sensor mSensor;
private final boolean mSensorMightHaveMoreListeners;
@@ -40,7 +47,10 @@
* @param context The context for the test
* @param sensorType The type of the sensor under test
* @param samplingPeriodUs The requested collection period for the sensor under test
+ *
+ * @deprecated Use variants with {@link Sensor} objects.
*/
+ @Deprecated
public TestSensorEnvironment(Context context, int sensorType, int samplingPeriodUs) {
this(context, sensorType, false /* sensorMightHaveMoreListeners */, samplingPeriodUs);
}
@@ -52,7 +62,10 @@
* @param sensorType The type of the sensor under test
* @param samplingPeriodUs The requested collection period for the sensor under test
* @param maxReportLatencyUs The requested collection report latency for the sensor under test
+ *
+ * @deprecated Use variants with {@link Sensor} objects.
*/
+ @Deprecated
public TestSensorEnvironment(
Context context,
int sensorType,
@@ -72,7 +85,10 @@
* @param sensorType The type of the sensor under test
* @param sensorMightHaveMoreListeners Whether the sensor under test is acting under load
* @param samplingPeriodUs The requested collection period for the sensor under test
+ *
+ * @deprecated Use variants with {@link Sensor} objects.
*/
+ @Deprecated
public TestSensorEnvironment(
Context context,
int sensorType,
@@ -93,7 +109,10 @@
* @param sensorMightHaveMoreListeners Whether the sensor under test is acting under load
* @param samplingPeriodUs The requested collection period for the sensor under test
* @param maxReportLatencyUs The requested collection report latency for the sensor under test
+ *
+ * @deprecated Use variants with {@link Sensor} objects.
*/
+ @Deprecated
public TestSensorEnvironment(
Context context,
int sensorType,
@@ -112,6 +131,26 @@
*
* @param context The context for the test
* @param sensor The sensor under test
+ * @param samplingPeriodUs The requested collection period for the sensor under test
+ * @param maxReportLatencyUs The requested collection report latency for the sensor under test
+ */
+ public TestSensorEnvironment(
+ Context context,
+ Sensor sensor,
+ int samplingPeriodUs,
+ int maxReportLatencyUs) {
+ this(context,
+ sensor,
+ false /* sensorMightHaveMoreListeners */,
+ samplingPeriodUs,
+ maxReportLatencyUs);
+ }
+
+ /**
+ * Constructs an environment for sensor testing.
+ *
+ * @param context The context for the test
+ * @param sensor The sensor under test
* @param sensorMightHaveMoreListeners Whether the sensor under test is acting under load (this
* usually implies that there are several listeners
* requesting different sampling periods)
@@ -160,6 +199,17 @@
}
/**
+ * @return A string representing the frequency equivalent to
+ * {@link #getRequestedSamplingPeriodUs()}.
+ */
+ public String getFrequencyString() {
+ if (mSamplingPeriodUs == SensorManager.SENSOR_DELAY_FASTEST) {
+ return "fastest";
+ }
+ return String.format("%.0fhz", getFrequencyHz());
+ }
+
+ /**
* @return The requested collection max batch report latency in microseconds.
*/
public int getMaxReportLatencyUs() {
@@ -171,7 +221,8 @@
* data at different sampling rates (the rates are unknown); false otherwise.
*/
public boolean isSensorSamplingRateOverloaded() {
- return mSensorMightHaveMoreListeners && mSamplingPeriodUs != SensorManager.SENSOR_DELAY_FASTEST;
+ return mSensorMightHaveMoreListeners
+ && mSamplingPeriodUs != SensorManager.SENSOR_DELAY_FASTEST;
}
/**
@@ -197,6 +248,15 @@
}
/**
+ * @return The actual sampling period at which a sensor can sample data. This value is a
+ * fraction of {@link #getExpectedSamplingPeriodUs()}.
+ */
+ public int getMaximumExpectedSamplingPeriodUs() {
+ int expectedSamplingPeriodUs = getExpectedSamplingPeriodUs();
+ return (int) (expectedSamplingPeriodUs / MAXIMUM_EXPECTED_SAMPLING_FREQUENCY_MULTIPLIER);
+ }
+
+ /**
* @return The number of axes in the coordinate system of the sensor under test.
*/
public int getSensorAxesCount() {
@@ -266,6 +326,17 @@
return TimeUnit.SECONDS.toNanos(reportLatencySec);
}
+ @Override
+ public String toString() {
+ return String.format(
+ "Sensor='%s', SamplingRateOverloaded=%s, SamplingPeriod=%sus, "
+ + "MaxReportLatency=%sus",
+ mSensor,
+ isSensorSamplingRateOverloaded(),
+ mSamplingPeriodUs,
+ mMaxReportLatencyUs);
+ }
+
/**
* Return true if {@link #getRequestedSamplingPeriodUs()} is not one of
* {@link SensorManager#SENSOR_DELAY_GAME}, {@link SensorManager#SENSOR_DELAY_UI}, or
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
index e8500f1..86b2436 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
@@ -21,6 +21,8 @@
import android.hardware.SensorEventListener2;
import android.os.SystemClock;
+import java.util.Arrays;
+
/**
* Class for holding information about individual {@link SensorEvent}s.
*/
@@ -75,4 +77,14 @@
this.accuracy = accuracy;
this.values = values;
}
+
+ @Override
+ public String toString() {
+ return String.format(
+ "Timestamp=%sns, ReceivedTimestamp=%sns, Accuracy=%s, Values=%s",
+ this.timestamp,
+ this.receivedTimestamp,
+ this.accuracy,
+ Arrays.toString(this.values));
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
index 6567be2..a60428f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -21,12 +21,21 @@
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener2;
+import android.os.Handler;
+import android.os.Looper;
import android.os.SystemClock;
-import android.util.Log;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* A {@link SensorEventListener2} which performs operations such as waiting for a specific number of
@@ -36,51 +45,39 @@
*/
public class TestSensorEventListener implements SensorEventListener2 {
public static final String LOG_TAG = "TestSensorEventListener";
- private static final long EVENT_TIMEOUT_US = TimeUnit.MICROSECONDS.convert(5, TimeUnit.SECONDS);
- private static final long FLUSH_TIMEOUT_US = TimeUnit.MICROSECONDS.convert(5, TimeUnit.SECONDS);
- private final SensorEventListener2 mListener;
+ private static final long EVENT_TIMEOUT_US = TimeUnit.SECONDS.toMicros(5);
+ private static final long FLUSH_TIMEOUT_US = TimeUnit.SECONDS.toMicros(10);
- private volatile CountDownLatch mEventLatch;
- private volatile CountDownLatch mFlushLatch = new CountDownLatch(1);
- private volatile TestSensorEnvironment mEnvironment;
- private volatile boolean mLogEvents;
+ private final List<TestSensorEvent> mCollectedEvents = new ArrayList<>();
+ private final List<CountDownLatch> mEventLatches = new ArrayList<>();
+ private final List<CountDownLatch> mFlushLatches = new ArrayList<>();
+ private final AtomicInteger mEventsReceivedOutsideHandler = new AtomicInteger();
+
+ private final Handler mHandler;
+ private final TestSensorEnvironment mEnvironment;
+
+ /**
+ * @deprecated Use {@link TestSensorEventListener(TestSensorEnvironment)}.
+ */
+ @Deprecated
+ public TestSensorEventListener() {
+ this(null /* environment */);
+ }
/**
* Construct a {@link TestSensorEventListener}.
*/
- public TestSensorEventListener() {
- this(null);
+ public TestSensorEventListener(TestSensorEnvironment environment) {
+ this(environment, null /* handler */);
}
/**
- * Construct a {@link TestSensorEventListener} that wraps a {@link SensorEventListener2}.
+ * Construct a {@link TestSensorEventListener}.
*/
- public TestSensorEventListener(SensorEventListener2 listener) {
- if (listener != null) {
- mListener = listener;
- } else {
- // use a Null Object to simplify handling the listener
- mListener = new SensorEventListener2() {
- public void onFlushCompleted(Sensor sensor) {}
- public void onSensorChanged(SensorEvent sensorEvent) {}
- public void onAccuracyChanged(Sensor sensor, int i) {}
- };
- }
- }
-
- /**
- * Set the sensor, rate, and batch report latency used for the assertions.
- */
- public void setEnvironment(TestSensorEnvironment environment) {
+ public TestSensorEventListener(TestSensorEnvironment environment, Handler handler) {
mEnvironment = environment;
- }
-
- /**
- * Set whether or not to log events
- */
- public void setLogEvents(boolean log) {
- mLogEvents = log;
+ mHandler = handler;
}
/**
@@ -88,19 +85,15 @@
*/
@Override
public void onSensorChanged(SensorEvent event) {
- mListener.onSensorChanged(event);
- if (mLogEvents) {
- Log.v(LOG_TAG, String.format(
- "Sensor %d: sensor_timestamp=%dns, received_timestamp=%dns, values=%s",
- mEnvironment.getSensor().getType(),
- event.timestamp,
- SystemClock.elapsedRealtimeNanos(),
- Arrays.toString(event.values)));
+ long timestampNs = SystemClock.elapsedRealtimeNanos();
+ checkHandler();
+ synchronized (mCollectedEvents) {
+ mCollectedEvents.add(new TestSensorEvent(event, timestampNs));
}
-
- CountDownLatch eventLatch = mEventLatch;
- if(eventLatch != null) {
- eventLatch.countDown();
+ synchronized (mEventLatches) {
+ for (CountDownLatch latch : mEventLatches) {
+ latch.countDown();
+ }
}
}
@@ -109,7 +102,7 @@
*/
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
- mListener.onAccuracyChanged(sensor, accuracy);
+ checkHandler();
}
/**
@@ -117,12 +110,71 @@
*/
@Override
public void onFlushCompleted(Sensor sensor) {
- CountDownLatch latch = mFlushLatch;
- mFlushLatch = null;
- if(latch != null) {
- latch.countDown();
+ checkHandler();
+ synchronized (mFlushLatches) {
+ for (CountDownLatch latch : mFlushLatches) {
+ latch.countDown();
+ }
}
- mListener.onFlushCompleted(sensor);
+ }
+
+ /**
+ * @return The handler (if any) associated with the instance.
+ */
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ /**
+ * @return A list of {@link TestSensorEvent}s collected by the listener.
+ */
+ public List<TestSensorEvent> getCollectedEvents() {
+ synchronized (mCollectedEvents){
+ return Collections.unmodifiableList(mCollectedEvents);
+ }
+ }
+
+ /**
+ * Clears the internal list of collected {@link TestSensorEvent}s.
+ */
+ public void clearEvents() {
+ synchronized (mCollectedEvents) {
+ mCollectedEvents.clear();
+ }
+ }
+
+
+ /**
+ * Utility method to log the collected events to a file.
+ * It will overwrite the file if it already exists, the file is created in a relative directory
+ * named 'events' under the sensor test directory (part of external storage).
+ */
+ public void logCollectedEventsToFile(String fileName) throws IOException {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Sensor='").append(mEnvironment.getSensor()).append("', ");
+ builder.append("SamplingRateOverloaded=")
+ .append(mEnvironment.isSensorSamplingRateOverloaded()).append(", ");
+ builder.append("RequestedSamplingPeriod=")
+ .append(mEnvironment.getRequestedSamplingPeriodUs()).append("us, ");
+ builder.append("MaxReportLatency=")
+ .append(mEnvironment.getMaxReportLatencyUs()).append("us");
+
+ synchronized (mCollectedEvents) {
+ for (TestSensorEvent event : mCollectedEvents) {
+ builder.append("\n");
+ builder.append("Timestamp=").append(event.timestamp).append("ns, ");
+ builder.append("ReceivedTimestamp=").append(event.receivedTimestamp).append("ns, ");
+ builder.append("Accuracy=").append(event.accuracy).append(", ");
+ builder.append("Values=").append(Arrays.toString(event.values));
+ }
+ }
+
+ File eventsDirectory = SensorCtsHelper.getSensorTestDataDirectory("events/");
+ File logFile = new File(eventsDirectory, fileName);
+ FileWriter fileWriter = new FileWriter(logFile, false /* append */);
+ try (BufferedWriter writer = new BufferedWriter(fileWriter)) {
+ writer.write(builder.toString());
+ }
}
/**
@@ -131,13 +183,24 @@
* @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} µs
*/
public void waitForFlushComplete() throws InterruptedException {
- CountDownLatch latch = mFlushLatch;
- if(latch == null) {
- return;
+ clearEvents();
+ CountDownLatch latch = new CountDownLatch(1);
+ synchronized (mFlushLatches) {
+ mFlushLatches.add(latch);
}
- Assert.assertTrue(
- SensorCtsHelper.formatAssertionMessage("WaitForFlush", mEnvironment),
- latch.await(FLUSH_TIMEOUT_US, TimeUnit.MICROSECONDS));
+
+ try {
+ String message = SensorCtsHelper.formatAssertionMessage(
+ "WaitForFlush",
+ mEnvironment,
+ "timeout=%dus",
+ FLUSH_TIMEOUT_US);
+ Assert.assertTrue(message, latch.await(FLUSH_TIMEOUT_US, TimeUnit.MICROSECONDS));
+ } finally {
+ synchronized (mFlushLatches) {
+ mFlushLatches.remove(latch);
+ }
+ }
}
/**
@@ -146,22 +209,36 @@
* @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} µs
*/
public void waitForEvents(int eventCount) throws InterruptedException {
- mEventLatch = new CountDownLatch(eventCount);
+ clearEvents();
+ CountDownLatch eventLatch = new CountDownLatch(eventCount);
+ synchronized (mEventLatches) {
+ mEventLatches.add(eventLatch);
+ }
+
try {
- int rateUs = mEnvironment.getExpectedSamplingPeriodUs();
- // Timeout is 2 * event count * expected period + batch timeout + default wait
- long timeoutUs = (2 * eventCount * rateUs)
+ long samplingPeriodUs = mEnvironment.getMaximumExpectedSamplingPeriodUs();
+ // timeout is 2 * event count * expected period + batch timeout + default wait
+ // we multiply by two as not to raise an error in this function even if the events are
+ // streaming at a lower rate than expected, as long as it's not streaming twice as slow
+ // as expected
+ long timeoutUs = (2 * eventCount * samplingPeriodUs)
+ mEnvironment.getMaxReportLatencyUs()
+ EVENT_TIMEOUT_US;
- String message = SensorCtsHelper.formatAssertionMessage(
- "WaitForEvents",
- mEnvironment,
- "requested:%d, received:%d",
- eventCount,
- eventCount - mEventLatch.getCount());
- Assert.assertTrue(message, mEventLatch.await(timeoutUs, TimeUnit.MICROSECONDS));
+ boolean success = eventLatch.await(timeoutUs, TimeUnit.MICROSECONDS);
+ if (!success) {
+ String message = SensorCtsHelper.formatAssertionMessage(
+ "WaitForEvents",
+ mEnvironment,
+ "requested=%d, received=%d, timeout=%dus",
+ eventCount,
+ eventCount - eventLatch.getCount(),
+ timeoutUs);
+ Assert.fail(message);
+ }
} finally {
- mEventLatch = null;
+ synchronized (mEventLatches) {
+ mEventLatches.remove(eventLatch);
+ }
}
}
@@ -171,4 +248,28 @@
public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
SensorCtsHelper.sleep(duration, timeUnit);
}
+
+ /**
+ * Asserts that sensor events arrived in the proper thread if a {@link Handler} was associated
+ * with the current instance.
+ *
+ * If no events were received this assertion will be evaluated to {@code true}.
+ */
+ public void assertEventsReceivedInHandler() {
+ int eventsOutsideHandler = mEventsReceivedOutsideHandler.get();
+ String message = String.format(
+ "Events arrived outside the associated Looper. Expected=0, Found=%d",
+ eventsOutsideHandler);
+ Assert.assertEquals(message, 0 /* expected */, eventsOutsideHandler);
+ }
+
+ /**
+ * Keeps track of the number of events that arrived in a different {@link Looper} than the one
+ * associated with the {@link TestSensorEventListener}.
+ */
+ private void checkHandler() {
+ if (mHandler != null && mHandler.getLooper() != Looper.myLooper()) {
+ mEventsReceivedOutsideHandler.incrementAndGet();
+ }
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
index dc40ff4..fdd851e 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
@@ -19,35 +19,18 @@
import junit.framework.Assert;
import android.content.Context;
-import android.hardware.Sensor;
import android.hardware.SensorEventListener;
-import android.hardware.SensorEventListener2;
import android.hardware.SensorManager;
import android.util.Log;
-import java.util.concurrent.TimeUnit;
-
/**
- * A test class that performs the actions of {@link SensorManager} on a single sensor. This
- * class allows for a single sensor to be registered and unregistered as well as performing
- * operations such as flushing the sensor events and gathering events. This class also manages
- * performing the test verifications for the sensor manager.
- * <p>
- * This class requires that operations are performed in the following order:
- * <p><ul>
- * <li>{@link #registerListener(TestSensorEventListener)}</li>
- * <li>{@link #startFlush()}, {@link #waitForFlushCompleted()}, or {@link #flush()}.
- * <li>{@link #unregisterListener()}</li>
- * </ul><p>Or:</p><ul>
- * <li>{@link #runSensor(TestSensorEventListener, int)}</li>
- * </ul><p>Or:</p><ul>
- * <li>{@link #runSensor(TestSensorEventListener, long, TimeUnit)}</li>
- * </ul><p>
- * If methods are called outside of this order, they will print a warning to the log and then
- * return. Both {@link #runSensor(TestSensorEventListener, int)}} and
- * {@link #runSensor(TestSensorEventListener, long, TimeUnit)} will perform the appropriate
- * set up and tear down.
- * <p>
+ * A test class that performs the actions of {@link SensorManager} on a single sensor.
+ * This class allows for a single sensor to be registered and unregistered as well as performing
+ * operations such as flushing the sensor events and gathering events.
+ * This class also manages performing the test verifications for the sensor manager.
+ *
+ * NOTE: this class is expected to mirror {@link SensorManager} operations, and perform the
+ * required test verifications along with them.
*/
public class TestSensorManager {
private static final String LOG_TAG = "TestSensorManager";
@@ -55,7 +38,7 @@
private final SensorManager mSensorManager;
private final TestSensorEnvironment mEnvironment;
- private TestSensorEventListener mTestSensorEventListener;
+ private volatile TestSensorEventListener mTestSensorEventListener;
/**
* @deprecated Use {@link #TestSensorManager(TestSensorEnvironment)} instead.
@@ -90,15 +73,14 @@
return;
}
- mTestSensorEventListener = listener != null ? listener : new TestSensorEventListener();
- mTestSensorEventListener.setEnvironment(mEnvironment);
-
+ mTestSensorEventListener = listener;
String message = SensorCtsHelper.formatAssertionMessage("registerListener", mEnvironment);
boolean result = mSensorManager.registerListener(
mTestSensorEventListener,
mEnvironment.getSensor(),
mEnvironment.getRequestedSamplingPeriodUs(),
- mEnvironment.getMaxReportLatencyUs());
+ mEnvironment.getMaxReportLatencyUs(),
+ mTestSensorEventListener.getHandler());
Assert.assertTrue(message, result);
}
@@ -110,136 +92,24 @@
Log.w(LOG_TAG, "No listener registered, returning.");
return;
}
-
- mSensorManager.unregisterListener(
- mTestSensorEventListener,
- mEnvironment.getSensor());
+ mSensorManager.unregisterListener(mTestSensorEventListener, mEnvironment.getSensor());
+ mTestSensorEventListener.assertEventsReceivedInHandler();
mTestSensorEventListener = null;
}
/**
- * Wait for a specific number of events.
- */
- public void waitForEvents(int eventCount) throws InterruptedException {
- if (mTestSensorEventListener == null) {
- Log.w(LOG_TAG, "No listener registered, returning.");
- return;
- }
- mTestSensorEventListener.waitForEvents(eventCount);
- }
-
- /**
- * Wait for a specific duration.
- */
- public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
- if (mTestSensorEventListener == null) {
- Log.w(LOG_TAG, "No listener registered, returning.");
- return;
- }
- mTestSensorEventListener.waitForEvents(duration, timeUnit);
- }
-
- /**
* Call {@link SensorManager#flush(SensorEventListener)}. This method will perform a no-op if
* the sensor is not registered.
*
- * @throws AssertionError if {@link SensorManager#flush(SensorEventListener)} returns false
+ * @throws AssertionError if {@link SensorManager#flush(SensorEventListener)} fails.
*/
- public void startFlush() {
+ public void requestFlush() {
if (mTestSensorEventListener == null) {
+ Log.w(LOG_TAG, "No listener registered, returning.");
return;
}
-
Assert.assertTrue(
SensorCtsHelper.formatAssertionMessage("Flush", mEnvironment),
mSensorManager.flush(mTestSensorEventListener));
}
-
- /**
- * Wait for {@link SensorEventListener2#onFlushCompleted(Sensor)} to be called. This method will
- * perform a no-op if the sensor is not registered.
- *
- * @throws AssertionError if there is a time out
- * @throws InterruptedException if the thread was interrupted
- */
- public void waitForFlushCompleted() throws InterruptedException {
- if (mTestSensorEventListener == null) {
- return;
- }
- mTestSensorEventListener.waitForFlushComplete();
- }
-
- /**
- * Call {@link SensorManager#flush(SensorEventListener)} and wait for
- * {@link SensorEventListener2#onFlushCompleted(Sensor)} to be called. This method will perform
- * a no-op if the sensor is not registered.
- *
- * @throws AssertionError if {@link SensorManager#flush(SensorEventListener)} returns false or
- * if there is a time out
- * @throws InterruptedException if the thread was interrupted
- */
- public void flush() throws InterruptedException {
- if (mTestSensorEventListener == null) {
- return;
- }
- startFlush();
- waitForFlushCompleted();
- }
-
- /**
- * Register a listener, wait for a specific number of events, and then unregister the listener.
- */
- public void runSensor(TestSensorEventListener listener, int eventCount)
- throws InterruptedException {
- if (mTestSensorEventListener != null) {
- Log.w(LOG_TAG, "Listener already registered, returning.");
- return;
- }
- try {
- registerListener(listener);
- waitForEvents(eventCount);
- } finally {
- unregisterListener();
- }
- }
-
- /**
- * Register a listener, wait for a specific duration, and then unregister the listener.
- */
- public void runSensor(TestSensorEventListener listener, long duration, TimeUnit timeUnit)
- throws InterruptedException {
- if (mTestSensorEventListener != null) {
- Log.w(LOG_TAG, "Listener already registered, returning.");
- return;
- }
- try {
- registerListener(listener);
- waitForEvents(duration, timeUnit);
- } finally {
- unregisterListener();
- }
- }
-
- /**
- * Registers a listener, waits for a specific duration, calls flush, and waits for flush to
- * complete.
- */
- public void runSensorAndFlush(
- TestSensorEventListener listener,
- long duration,
- TimeUnit timeUnit) throws InterruptedException {
- if (mTestSensorEventListener != null) {
- Log.w(LOG_TAG, "Listener already registered, returning.");
- return;
- }
-
- try {
- registerListener(listener);
- SensorCtsHelper.sleep(duration, timeUnit);
- startFlush();
- listener.waitForFlushComplete();
- } finally {
- unregisterListener();
- }
- }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/ValidatingSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/ValidatingSensorEventListener.java
deleted file mode 100644
index 299f470..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/ValidatingSensorEventListener.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers;
-
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener2;
-import android.hardware.cts.helpers.sensorverification.ISensorVerification;
-
-import java.util.Collection;
-import java.util.LinkedList;
-
-/**
- * A {@link TestSensorEventListener} which performs validations on the received events on the fly.
- * This class is useful for long running tests where it is not practical to store all the events to
- * be processed after.
- */
-public class ValidatingSensorEventListener extends TestSensorEventListener {
-
- private final Collection<ISensorVerification> mVerifications =
- new LinkedList<ISensorVerification>();
-
- /**
- * Construct a {@link ValidatingSensorEventListener} with an additional
- * {@link SensorEventListener2}.
- */
- public ValidatingSensorEventListener(SensorEventListener2 listener,
- ISensorVerification ... verifications) {
- super(listener);
- for (ISensorVerification verification : verifications) {
- mVerifications.add(verification);
- }
- }
-
- /**
- * Construct a {@link ValidatingSensorEventListener} with an additional
- * {@link SensorEventListener2}.
- */
- public ValidatingSensorEventListener(SensorEventListener2 listener,
- Collection<ISensorVerification> verifications) {
- this(listener, verifications.toArray(new ISensorVerification[0]));
- }
-
- /**
- * Construct a {@link ValidatingSensorEventListener}.
- */
- public ValidatingSensorEventListener(ISensorVerification ... verifications) {
- this(null, verifications);
- }
-
- /**
- * Construct a {@link ValidatingSensorEventListener}.
- */
- public ValidatingSensorEventListener(Collection<ISensorVerification> verifications) {
- this(null, verifications);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onSensorChanged(SensorEvent event) {
- TestSensorEvent testEvent = new TestSensorEvent(event);
- for (ISensorVerification verification : mVerifications) {
- verification.addSensorEvent(testEvent);
- }
- super.onSensorChanged(event);
- }
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java b/tests/tests/hardware/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java
new file mode 100644
index 0000000..d34c0af
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cts.helpers.reporting;
+
+import android.hardware.cts.helpers.SensorTestPlatformException;
+
+/**
+ * Interface that represents a node in a hierarchy built by the sensor test platform.
+ */
+// TODO: this is an intermediate state to introduce a full-blown centralized recorder data produced
+// by sensor tests
+public interface ISensorTestNode {
+
+ /**
+ * Provides a name (tag) that can be used to identify the current node.
+ */
+ String getName() throws SensorTestPlatformException;
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AbstractSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AbstractSensorOperation.java
deleted file mode 100644
index 5b969f2..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AbstractSensorOperation.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers.sensoroperations;
-
-import android.hardware.cts.helpers.SensorStats;
-
-/**
- * A {@link ISensorOperation} which contains a common implementation for gathering
- * {@link SensorStats}.
- */
-public abstract class AbstractSensorOperation implements ISensorOperation {
-
- private final SensorStats mStats = new SensorStats();
-
- /**
- * Wrapper around {@link SensorStats#addSensorStats(String, SensorStats)}
- */
- protected void addSensorStats(String key, SensorStats stats) {
- mStats.addSensorStats(key, stats);
- }
-
- /**
- * Wrapper around {@link SensorStats#addSensorStats(String, SensorStats)} that allows an index
- * to be added. This is useful for {@link ISensorOperation}s that have many iterations or child
- * operations. The key added is in the form {@code key + "_" + index} where index may be zero
- * padded.
- */
- protected void addSensorStats(String key, int index, SensorStats stats) {
- addSensorStats(String.format("%s_%03d", key, index), stats);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public SensorStats getStats() {
- return mStats;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public abstract ISensorOperation clone();
-
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
index 88e4954..436a7cf 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
@@ -22,14 +22,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import java.util.concurrent.TimeUnit;
/**
- * An {@link ISensorOperation} which performs another {@link ISensorOperation} and then wakes up
+ * An {@link SensorOperation} which performs another {@link SensorOperation} and then wakes up
* after a specified period of time and waits for the child operation to complete.
* <p>
* This operation can be used to allow the device to go to sleep and wake it up after a specified
@@ -40,11 +40,11 @@
* but wake the device one time at the specified period.
* </p>
*/
-public class AlarmOperation extends AbstractSensorOperation {
+public class AlarmOperation extends SensorOperation {
private static final String ACTION = "AlarmOperationAction";
private static final String WAKE_LOCK_TAG = "AlarmOperationWakeLock";
- private final ISensorOperation mOperation;
+ private final SensorOperation mOperation;
private final Context mContext;
private final long mSleepDuration;
private final TimeUnit mTimeUnit;
@@ -55,13 +55,17 @@
/**
* Constructor for {@link DelaySensorOperation}
*
- * @param operation the child {@link ISensorOperation} to perform after the delay
+ * @param operation the child {@link SensorOperation} to perform after the delay
* @param context the context used to access the alarm manager
* @param sleepDuration the amount of time to sleep
* @param timeUnit the unit of the duration
*/
- public AlarmOperation(ISensorOperation operation, Context context, long sleepDuration,
+ public AlarmOperation(
+ SensorOperation operation,
+ Context context,
+ long sleepDuration,
TimeUnit timeUnit) {
+ super(operation.getStats());
mOperation = operation;
mContext = context;
mSleepDuration = sleepDuration;
@@ -72,7 +76,7 @@
* {@inheritDoc}
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
// Start alarm
IntentFilter intentFilter = new IntentFilter(ACTION);
BroadcastReceiver receiver = new BroadcastReceiver() {
@@ -92,7 +96,7 @@
// Execute operation
try {
- mOperation.execute();
+ mOperation.execute(asTestNode(parent));
} finally {
releaseWakeLock();
}
@@ -102,14 +106,6 @@
* {@inheritDoc}
*/
@Override
- public SensorStats getStats() {
- return mOperation.getStats();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public AlarmOperation clone() {
return new AlarmOperation(mOperation, mContext, mSleepDuration, mTimeUnit);
}
@@ -120,7 +116,7 @@
*/
private synchronized void acquireWakeLock() {
// Don't acquire wake lock if the operation has already completed.
- if (mCompleted == true || mWakeLock != null) {
+ if (mCompleted || mWakeLock != null) {
return;
}
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
index b4d1f23..8c52222 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
@@ -17,30 +17,28 @@
package android.hardware.cts.helpers.sensoroperations;
import android.hardware.cts.helpers.SensorCtsHelper;
-import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import java.util.concurrent.TimeUnit;
/**
- * An {@link ISensorOperation} which delays for a specified period of time before performing another
- * {@link ISensorOperation}.
+ * An {@link SensorOperation} which delays for a specified period of time before performing another
+ * {@link SensorOperation}.
*/
-public class DelaySensorOperation implements ISensorOperation {
- private final ISensorOperation mOperation;
+public class DelaySensorOperation extends SensorOperation {
+ private final SensorOperation mOperation;
private final long mDelay;
private final TimeUnit mTimeUnit;
/**
* Constructor for {@link DelaySensorOperation}
*
- * @param operation the child {@link ISensorOperation} to perform after the delay
+ * @param operation the child {@link SensorOperation} to perform after the delay
* @param delay the amount of time to delay
* @param timeUnit the unit of the delay
*/
- public DelaySensorOperation(ISensorOperation operation, long delay, TimeUnit timeUnit) {
- if (operation == null || timeUnit == null) {
- throw new IllegalArgumentException("Arguments cannot be null");
- }
+ public DelaySensorOperation(SensorOperation operation, long delay, TimeUnit timeUnit) {
+ super(operation.getStats());
mOperation = operation;
mDelay = delay;
mTimeUnit = timeUnit;
@@ -50,17 +48,9 @@
* {@inheritDoc}
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
SensorCtsHelper.sleep(mDelay, mTimeUnit);
- mOperation.execute();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public SensorStats getStats() {
- return mOperation.getStats();
+ mOperation.execute(asTestNode(parent));
}
/**
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
index bb64dfa..238956b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
@@ -17,16 +17,17 @@
package android.hardware.cts.helpers.sensoroperations;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import junit.framework.Assert;
import java.util.concurrent.TimeUnit;
/**
- * A fake {@ISensorOperation} that will run for a specified time and then pass or fail. Useful when
- * debugging the framework.
+ * A fake {@link SensorOperation} that will run for a specified time and then pass or fail. Useful
+ * when debugging the framework.
*/
-public class FakeSensorOperation extends AbstractSensorOperation {
+public class FakeSensorOperation extends SensorOperation {
private static final int NANOS_PER_MILLI = 1000000;
private final boolean mFail;
@@ -56,7 +57,7 @@
* {@inheritDoc}
*/
@Override
- public void execute() {
+ public void execute(ISensorTestNode parent) {
long delayNs = TimeUnit.NANOSECONDS.convert(mDelay, mTimeUnit);
try {
Thread.sleep(delayNs / NANOS_PER_MILLI, (int) (delayNs % NANOS_PER_MILLI));
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java
deleted file mode 100644
index 62a4e9e..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers.sensoroperations;
-
-import android.hardware.cts.helpers.SensorStats;
-
-/**
- * Interface used by all sensor operations. This allows for complex operations such as chaining
- * operations together or running operations in parallel.
- * <p>
- * Certain restrictions exist for {@link ISensorOperation}s:
- * <p><ul>
- * <li>{@link #execute()} should only be called once and behavior is undefined for subsequent calls.
- * Once {@link #execute()} is called, the class should not be modified. Generally, there is no
- * synchronization for operations.</li>
- * <li>{@link #getStats()} should only be called after {@link #execute()}. If it is called before,
- * the returned value is undefined.</li>
- * <li>{@link #clone()} may be called any time and should return an operation with the same
- * parameters as the original.</li>
- * </ul>
- */
-public interface ISensorOperation {
-
- /**
- * Executes the sensor operation. This may throw {@link RuntimeException}s such as
- * {@link AssertionError}s.
- *
- * NOTE: the operation is expected to handle interruption by:
- * - cleaning up on {@link InterruptedException}
- * - propagating the exception down the stack
- */
- public void execute() throws InterruptedException;
-
- /**
- * Get the stats for the operation.
- *
- * @return The {@link SensorStats} for the operation.
- */
- public SensorStats getStats();
-
- /**
- * Clones the {@link ISensorOperation}. The implementation should also clone all child
- * operations, so that a cloned operation will run with the exact same parameters as the
- * original. The stats should not be cloned.
- *
- * @return The cloned {@link ISensorOperation}
- */
- public ISensorOperation clone();
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
index 5a4466c..ed70b70 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
@@ -19,10 +19,10 @@
import junit.framework.Assert;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import android.os.SystemClock;
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
@@ -33,14 +33,14 @@
import java.util.concurrent.TimeoutException;
/**
- * A {@link ISensorOperation} that executes a set of children {@link ISensorOperation}s in parallel.
+ * A {@link SensorOperation} that executes a set of children {@link SensorOperation}s in parallel.
* The children are run in parallel but are given an index label in the order they are added. This
- * class can be combined to compose complex {@link ISensorOperation}s.
+ * class can be combined to compose complex {@link SensorOperation}s.
*/
-public class ParallelSensorOperation extends AbstractSensorOperation {
+public class ParallelSensorOperation extends SensorOperation {
public static final String STATS_TAG = "parallel";
- private final List<ISensorOperation> mOperations = new LinkedList<ISensorOperation>();
+ private final ArrayList<SensorOperation> mOperations = new ArrayList<>();
private final Long mTimeout;
private final TimeUnit mTimeUnit;
@@ -65,10 +65,10 @@
}
/**
- * Add a set of {@link ISensorOperation}s.
+ * Add a set of {@link SensorOperation}s.
*/
- public void add(ISensorOperation ... operations) {
- for (ISensorOperation operation : operations) {
+ public void add(SensorOperation ... operations) {
+ for (SensorOperation operation : operations) {
if (operation == null) {
throw new IllegalArgumentException("Arguments cannot be null");
}
@@ -77,11 +77,11 @@
}
/**
- * Executes the {@link ISensorOperation}s in parallel. If an exception occurs one or more
+ * Executes the {@link SensorOperation}s in parallel. If an exception occurs one or more
* operations, the first exception will be thrown once all operations are completed.
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(final ISensorTestNode parent) throws InterruptedException {
int operationsCount = mOperations.size();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
operationsCount,
@@ -92,12 +92,13 @@
executor.allowCoreThreadTimeOut(true);
executor.prestartAllCoreThreads();
- ArrayList<Future<ISensorOperation>> futures = new ArrayList<Future<ISensorOperation>>();
- for (final ISensorOperation operation : mOperations) {
- Future<ISensorOperation> future = executor.submit(new Callable<ISensorOperation>() {
+ final ISensorTestNode currentNode = asTestNode(parent);
+ ArrayList<Future<SensorOperation>> futures = new ArrayList<>();
+ for (final SensorOperation operation : mOperations) {
+ Future<SensorOperation> future = executor.submit(new Callable<SensorOperation>() {
@Override
- public ISensorOperation call() throws Exception {
- operation.execute();
+ public SensorOperation call() throws Exception {
+ operation.execute(currentNode);
return operation;
}
});
@@ -111,12 +112,12 @@
}
boolean hasAssertionErrors = false;
- ArrayList<Integer> timeoutIndices = new ArrayList<Integer>();
- ArrayList<Throwable> exceptions = new ArrayList<Throwable>();
+ ArrayList<Integer> timeoutIndices = new ArrayList<>();
+ ArrayList<Throwable> exceptions = new ArrayList<>();
for (int i = 0; i < operationsCount; ++i) {
- Future<ISensorOperation> future = futures.get(i);
+ Future<SensorOperation> future = futures.get(i);
try {
- ISensorOperation operation = getFutureResult(future, executionTimeNs);
+ SensorOperation operation = getFutureResult(future, executionTimeNs);
addSensorStats(STATS_TAG, i, operation.getStats());
} catch (ExecutionException e) {
// extract the exception thrown by the worker thread
@@ -151,7 +152,7 @@
@Override
public ParallelSensorOperation clone() {
ParallelSensorOperation operation = new ParallelSensorOperation();
- for (ISensorOperation subOperation : mOperations) {
+ for (SensorOperation subOperation : mOperations) {
operation.add(subOperation.clone());
}
return operation;
@@ -160,7 +161,7 @@
/**
* Helper method that waits for a {@link Future} to complete, and returns its result.
*/
- private ISensorOperation getFutureResult(Future<ISensorOperation> future, Long timeoutNs)
+ private SensorOperation getFutureResult(Future<SensorOperation> future, Long timeoutNs)
throws ExecutionException, TimeoutException, InterruptedException {
if (timeoutNs == null) {
return future.get();
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
index 3d682fe..5b333b8 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
@@ -17,42 +17,44 @@
package android.hardware.cts.helpers.sensoroperations;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorTestPlatformException;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
/**
- * A {@link ISensorOperation} that executes a single {@link ISensorOperation} a given number of
- * times. This class can be combined to compose complex {@link ISensorOperation}s.
+ * A {@link SensorOperation} that executes a single {@link SensorOperation} a given number of
+ * times. This class can be combined to compose complex {@link SensorOperation}s.
*/
-public class RepeatingSensorOperation extends AbstractSensorOperation {
+public class RepeatingSensorOperation extends SensorOperation {
public static final String STATS_TAG = "repeating";
- private final ISensorOperation mOperation;
+ private final SensorOperation mOperation;
private final int mIterations;
/**
* Constructor for {@link RepeatingSensorOperation}.
*
- * @param operation the {@link ISensorOperation} to run.
+ * @param operation the {@link SensorOperation} to run.
* @param iterations the number of iterations to run the operation for.
*/
- public RepeatingSensorOperation(ISensorOperation operation, int iterations) {
+ public RepeatingSensorOperation(SensorOperation operation, int iterations) {
if (operation == null) {
throw new IllegalArgumentException("Arguments cannot be null");
}
mOperation = operation;
mIterations = iterations;
-
}
/**
- * Executes the {@link ISensorOperation}s the given number of times. If an exception occurs
- * in one iterations, it is thrown and all subsequent iterations will not run.
+ * Executes the {@link SensorOperation}s the given number of times. If an exception occurs in
+ * one iterations, it is thrown and all subsequent iterations will not run.
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
+ ISensorTestNode currentNode = asTestNode(parent);
for(int i = 0; i < mIterations; ++i) {
- ISensorOperation operation = mOperation.clone();
+ SensorOperation operation = mOperation.clone();
try {
- operation.execute();
+ operation.execute(new TestNode(currentNode, i));
} catch (AssertionError e) {
String msg = String.format("Iteration %d failed: \"%s\"", i, e.getMessage());
getStats().addValue(SensorStats.ERROR, msg);
@@ -70,4 +72,19 @@
public RepeatingSensorOperation clone() {
return new RepeatingSensorOperation(mOperation.clone(), mIterations);
}
+
+ private class TestNode implements ISensorTestNode {
+ private final ISensorTestNode mTestNode;
+ private final int mIteration;
+
+ public TestNode(ISensorTestNode parent, int iteration) {
+ mTestNode = asTestNode(parent);
+ mIteration = iteration;
+ }
+
+ @Override
+ public String getName() throws SensorTestPlatformException {
+ return String.format("%s-iteration%d", mTestNode.getName(), mIteration);
+ }
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
new file mode 100644
index 0000000..66604d3
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cts.helpers.sensoroperations;
+
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorTestPlatformException;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
+
+/**
+ * Base class used by all sensor operations. This allows for complex operations such as chaining
+ * operations together or running operations in parallel.
+ * <p>
+ * Certain restrictions exist for {@link SensorOperation}s:
+ * <p><ul>
+ * <li>{@link #execute(ISensorTestNode)} should only be called once and behavior is undefined for
+ * subsequent calls.
+ * Once {@link #execute(ISensorTestNode)} is called, the class should not be modified. Generally,
+ * there is no synchronization for operations.</li>
+ * <li>{@link #getStats()} should only be called after {@link #execute(ISensorTestNode)}. If it
+ * is called before, the returned value is undefined.</li>
+ * <li>{@link #clone()} may be called any time and should return an operation with the same
+ * parameters as the original.</li>
+ * </ul>
+ */
+public abstract class SensorOperation {
+ private final SensorStats mStats;
+
+ protected SensorOperation() {
+ this(new SensorStats());
+ }
+
+ protected SensorOperation(SensorStats stats) {
+ mStats = stats;
+ }
+
+ /**
+ * @return The {@link SensorStats} for the operation.
+ */
+ public SensorStats getStats() {
+ return mStats;
+ }
+
+ /**
+ * Executes the sensor operation.
+ * This may throw {@link RuntimeException}s such as {@link AssertionError}s.
+ *
+ * NOTE: the operation is expected to handle interruption by:
+ * - cleaning up on {@link InterruptedException}
+ * - propagating the exception down the stack
+ */
+ public abstract void execute(ISensorTestNode parent) throws InterruptedException;
+
+ /**
+ * @return The cloned {@link SensorOperation}.
+ *
+ * NOTE: The implementation should also clone all child operations, so that a cloned operation
+ * will run with the exact same parameters as the original. The stats should not be cloned.
+ */
+ public abstract SensorOperation clone();
+
+ /**
+ * Wrapper around {@link SensorStats#addSensorStats(String, SensorStats)}
+ */
+ protected void addSensorStats(String key, SensorStats stats) {
+ getStats().addSensorStats(key, stats);
+ }
+
+ /**
+ * Wrapper around {@link SensorStats#addSensorStats(String, SensorStats)} that allows an index
+ * to be added. This is useful for {@link SensorOperation}s that have many iterations or child
+ * operations. The key added is in the form {@code key + "_" + index} where index may be zero
+ * padded.
+ */
+ protected void addSensorStats(String key, int index, SensorStats stats) {
+ addSensorStats(String.format("%s_%03d", key, index), stats);
+ }
+
+ protected ISensorTestNode asTestNode(ISensorTestNode parent) {
+ return new SensorTestNode(parent, this);
+ }
+
+ private class SensorTestNode implements ISensorTestNode {
+ private final ISensorTestNode mParent;
+ private final SensorOperation mOperation;
+
+ public SensorTestNode(ISensorTestNode parent, SensorOperation operation) {
+ mParent = parent;
+ mOperation = operation;
+ }
+
+ @Override
+ public String getName() throws SensorTestPlatformException {
+ return mParent.getName() + "-" + mOperation.getClass().getSimpleName();
+ }
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
index bc48725..30da9a0 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
@@ -19,18 +19,27 @@
import junit.framework.TestCase;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorTestPlatformException;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
- * Tests for the primitive {@link ISensorOperation}s including {@link DelaySensorOperation},
+ * Tests for the primitive {@link SensorOperation}s including {@link DelaySensorOperation},
* {@link ParallelSensorOperation}, {@link RepeatingSensorOperation} and
* {@link SequentialSensorOperation}.
*/
public class SensorOperationTest extends TestCase {
private static final long TEST_DURATION_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(5);
+ private final ISensorTestNode mTestNode = new ISensorTestNode() {
+ @Override
+ public String getName() throws SensorTestPlatformException {
+ return "SensorOperationUnitTest";
+ }
+ };
+
/**
* Test that the {@link FakeSensorOperation} functions correctly. Other tests in this class
* rely on this operation.
@@ -38,18 +47,18 @@
public void testFakeSensorOperation() throws InterruptedException {
final int opDurationMs = 100;
- ISensorOperation op = new FakeSensorOperation(opDurationMs, TimeUnit.MILLISECONDS);
+ SensorOperation op = new FakeSensorOperation(opDurationMs, TimeUnit.MILLISECONDS);
assertFalse(op.getStats().flatten().containsKey("executed"));
long start = System.currentTimeMillis();
- op.execute();
+ op.execute(mTestNode);
long duration = System.currentTimeMillis() - start;
assertTrue(Math.abs(opDurationMs - duration) < TEST_DURATION_THRESHOLD_MS);
assertTrue(op.getStats().flatten().containsKey("executed"));
op = new FakeSensorOperation(true, 0, TimeUnit.MILLISECONDS);
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
@@ -65,12 +74,12 @@
final int subOpDurationMs = 100;
FakeSensorOperation subOp = new FakeSensorOperation(subOpDurationMs, TimeUnit.MILLISECONDS);
- ISensorOperation op = new DelaySensorOperation(subOp, opDurationMs, TimeUnit.MILLISECONDS);
+ SensorOperation op = new DelaySensorOperation(subOp, opDurationMs, TimeUnit.MILLISECONDS);
long startMs = System.currentTimeMillis();
- op.execute();
- long dirationMs = System.currentTimeMillis() - startMs;
- long durationDeltaMs = Math.abs(opDurationMs + subOpDurationMs - dirationMs);
+ op.execute(mTestNode);
+ long durationMs = System.currentTimeMillis() - startMs;
+ long durationDeltaMs = Math.abs(opDurationMs + subOpDurationMs - durationMs);
assertTrue(durationDeltaMs < TEST_DURATION_THRESHOLD_MS);
}
@@ -83,7 +92,7 @@
ParallelSensorOperation op = new ParallelSensorOperation();
for (int i = 0; i < subOpCount; i++) {
- ISensorOperation subOp = new FakeSensorOperation(subOpDurationMs,
+ SensorOperation subOp = new FakeSensorOperation(subOpDurationMs,
TimeUnit.MILLISECONDS);
op.add(subOp);
}
@@ -92,7 +101,7 @@
assertEquals(0, statsKeys.size());
long start = System.currentTimeMillis();
- op.execute();
+ op.execute(mTestNode);
long durationMs = System.currentTimeMillis() - start;
long durationDeltaMs = Math.abs(subOpDurationMs - durationMs);
String message = String.format(
@@ -124,7 +133,7 @@
ParallelSensorOperation op = new ParallelSensorOperation();
for (int i = 0; i < subOpCount; i++) {
// Trigger failures in the 5th, 55th operations at t=5ms, t=55ms
- ISensorOperation subOp = new FakeSensorOperation(i % 50 == 5, i, TimeUnit.MILLISECONDS);
+ SensorOperation subOp = new FakeSensorOperation(i % 50 == 5, i, TimeUnit.MILLISECONDS);
op.add(subOp);
}
@@ -132,7 +141,7 @@
assertEquals(0, statsKeys.size());
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
@@ -164,7 +173,7 @@
ParallelSensorOperation op = new ParallelSensorOperation(1, TimeUnit.SECONDS);
for (int i = 0; i < subOpCount; i++) {
// Trigger timeouts in the 5th, 55th operations (5 seconds vs 1 seconds)
- ISensorOperation subOp = new FakeSensorOperation(i % 50 == 5 ? 5 : 0, TimeUnit.SECONDS);
+ SensorOperation subOp = new FakeSensorOperation(i % 50 == 5 ? 5 : 0, TimeUnit.SECONDS);
op.add(subOp);
}
@@ -172,7 +181,7 @@
assertEquals(0, statsKeys.size());
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
@@ -196,14 +205,14 @@
final int iterations = 10;
final int subOpDurationMs = 100;
- ISensorOperation subOp = new FakeSensorOperation(subOpDurationMs, TimeUnit.MILLISECONDS);
- ISensorOperation op = new RepeatingSensorOperation(subOp, iterations);
+ SensorOperation subOp = new FakeSensorOperation(subOpDurationMs, TimeUnit.MILLISECONDS);
+ SensorOperation op = new RepeatingSensorOperation(subOp, iterations);
Set<String> statsKeys = op.getStats().flatten().keySet();
assertEquals(0, statsKeys.size());
long start = System.currentTimeMillis();
- op.execute();
+ op.execute(mTestNode);
long duration = System.currentTimeMillis() - start;
assertTrue(Math.abs(subOpDurationMs * iterations - duration) < TEST_DURATION_THRESHOLD_MS);
@@ -223,13 +232,13 @@
final int iterations = 100;
final int failCount = 75;
- ISensorOperation subOp = new FakeSensorOperation(0, TimeUnit.MILLISECONDS) {
+ SensorOperation subOp = new FakeSensorOperation(0, TimeUnit.MILLISECONDS) {
private int mExecutedCount = 0;
private SensorStats mFakeStats = new SensorStats();
@Override
- public void execute() {
- super.execute();
+ public void execute(ISensorTestNode parent) {
+ super.execute(parent);
mExecutedCount++;
if (failCount == mExecutedCount) {
@@ -249,13 +258,13 @@
return mFakeStats;
}
};
- ISensorOperation op = new RepeatingSensorOperation(subOp, iterations);
+ SensorOperation op = new RepeatingSensorOperation(subOp, iterations);
Set<String> statsKeys = op.getStats().flatten().keySet();
assertEquals(0, statsKeys.size());
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
@@ -283,7 +292,7 @@
SequentialSensorOperation op = new SequentialSensorOperation();
for (int i = 0; i < subOpCount; i++) {
- ISensorOperation subOp = new FakeSensorOperation(subOpDurationMs,
+ SensorOperation subOp = new FakeSensorOperation(subOpDurationMs,
TimeUnit.MILLISECONDS);
op.add(subOp);
}
@@ -292,7 +301,7 @@
assertEquals(0, statsKeys.size());
long start = System.currentTimeMillis();
- op.execute();
+ op.execute(mTestNode);
long duration = System.currentTimeMillis() - start;
assertTrue(Math.abs(subOpDurationMs * subOpCount - duration) < TEST_DURATION_THRESHOLD_MS);
@@ -315,7 +324,7 @@
SequentialSensorOperation op = new SequentialSensorOperation();
for (int i = 0; i < subOpCount; i++) {
// Trigger a failure in the 75th operation only
- ISensorOperation subOp = new FakeSensorOperation(i + 1 == failCount, 0,
+ SensorOperation subOp = new FakeSensorOperation(i + 1 == failCount, 0,
TimeUnit.MILLISECONDS);
op.add(subOp);
}
@@ -324,7 +333,7 @@
assertEquals(0, statsKeys.size());
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
index 2ed0ca6..847c0f2 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
@@ -17,25 +17,25 @@
package android.hardware.cts.helpers.sensoroperations;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.ArrayList;
/**
- * A {@link ISensorOperation} that executes a set of children {@link ISensorOperation}s in a
+ * A {@link SensorOperation} that executes a set of children {@link SensorOperation}s in a
* sequence. The children are executed in the order they are added. This class can be combined to
- * compose complex {@link ISensorOperation}s.
+ * compose complex {@link SensorOperation}s.
*/
-public class SequentialSensorOperation extends AbstractSensorOperation {
+public class SequentialSensorOperation extends SensorOperation {
public static final String STATS_TAG = "sequential";
- private final List<ISensorOperation> mOperations = new LinkedList<ISensorOperation>();
+ private final ArrayList<SensorOperation> mOperations = new ArrayList<>();
/**
- * Add a set of {@link ISensorOperation}s.
+ * Add a set of {@link SensorOperation}s.
*/
- public void add(ISensorOperation ... operations) {
- for (ISensorOperation operation : operations) {
+ public void add(SensorOperation ... operations) {
+ for (SensorOperation operation : operations) {
if (operation == null) {
throw new IllegalArgumentException("Arguments cannot be null");
}
@@ -44,15 +44,16 @@
}
/**
- * Executes the {@link ISensorOperation}s in the order they were added. If an exception occurs
+ * Executes the {@link SensorOperation}s in the order they were added. If an exception occurs
* in one operation, it is thrown and all subsequent operations will not run.
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
+ ISensorTestNode currentNode = asTestNode(parent);
for (int i = 0; i < mOperations.size(); i++) {
- ISensorOperation operation = mOperations.get(i);
+ SensorOperation operation = mOperations.get(i);
try {
- operation.execute();
+ operation.execute(currentNode);
} catch (AssertionError e) {
String msg = String.format("Operation %d failed: \"%s\"", i, e.getMessage());
getStats().addValue(SensorStats.ERROR, msg);
@@ -69,7 +70,7 @@
@Override
public SequentialSensorOperation clone() {
SequentialSensorOperation operation = new SequentialSensorOperation();
- for (ISensorOperation subOperation : mOperations) {
+ for (SensorOperation subOperation : mOperations) {
operation.add(subOperation.clone());
}
return operation;
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorFlushOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorFlushOperation.java
deleted file mode 100644
index d5aa4b9..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorFlushOperation.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers.sensoroperations;
-
-import android.hardware.cts.helpers.TestSensorEnvironment;
-import android.hardware.cts.helpers.TestSensorEventListener;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * A {@link ISensorOperation} used to verify that sensor events and sensor values are correct.
- * <p>
- * Provides methods to set test expectations as well as providing a set of default expectations
- * depending on sensor type. When {{@link #execute()} is called, the sensor will collect the
- * events, call flush, and then run all the tests.
- * </p>
- */
-public class TestSensorFlushOperation extends VerifiableSensorOperation {
- private final Long mDuration;
- private final TimeUnit mTimeUnit;
-
- /**
- * Create a {@link TestSensorOperation}.
- *
- * @param environment the test environment
- * @param duration the duration to gather events before calling {@code SensorManager.flush()}
- * @param timeUnit the time unit of the duration
- */
- public TestSensorFlushOperation(
- TestSensorEnvironment environment,
- long duration,
- TimeUnit timeUnit) {
- super(environment);
- mDuration = duration;
- mTimeUnit = timeUnit;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void doExecute(TestSensorEventListener listener) throws InterruptedException {
- mSensorManager.runSensorAndFlush(listener, mDuration, mTimeUnit);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected VerifiableSensorOperation doClone() {
- return new TestSensorFlushOperation(mEnvironment, mDuration,mTimeUnit);
- }
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
index 695e1a7..901216a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
@@ -16,83 +16,264 @@
package android.hardware.cts.helpers.sensoroperations;
-import android.hardware.cts.helpers.TestSensorEnvironment;
-import android.hardware.cts.helpers.TestSensorEventListener;
+import junit.framework.Assert;
+import android.hardware.cts.helpers.SensorCtsHelper;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorTestPlatformException;
+import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.TestSensorEvent;
+import android.hardware.cts.helpers.TestSensorEventListener;
+import android.hardware.cts.helpers.TestSensorManager;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
+import android.hardware.cts.helpers.sensorverification.EventGapVerification;
+import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
+import android.hardware.cts.helpers.sensorverification.EventTimestampSynchronizationVerification;
+import android.hardware.cts.helpers.sensorverification.FrequencyVerification;
+import android.hardware.cts.helpers.sensorverification.ISensorVerification;
+import android.hardware.cts.helpers.sensorverification.JitterVerification;
+import android.hardware.cts.helpers.sensorverification.MagnitudeVerification;
+import android.hardware.cts.helpers.sensorverification.MeanVerification;
+import android.hardware.cts.helpers.sensorverification.StandardDeviationVerification;
+import android.os.Handler;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
import java.util.concurrent.TimeUnit;
/**
- * A {@link ISensorOperation} used to verify that sensor events and sensor values are correct.
+ * A {@link SensorOperation} used to verify that sensor events and sensor values are correct.
* <p>
* Provides methods to set test expectations as well as providing a set of default expectations
- * depending on sensor type. When {{@link #execute()} is called, the sensor will collect the
- * events and then run all the tests.
+ * depending on sensor type. When {{@link #execute(ISensorTestNode)} is called, the sensor will
+ * collect the events and then run all the tests.
* </p>
*/
-public class TestSensorOperation extends VerifiableSensorOperation {
- private final Integer mEventCount;
- private final Long mDuration;
- private final TimeUnit mTimeUnit;
+public class TestSensorOperation extends SensorOperation {
+ private static final String TAG = "TestSensorOperation";
+
+ private final HashSet<ISensorVerification> mVerifications = new HashSet<>();
+
+ private final TestSensorManager mSensorManager;
+ private final TestSensorEnvironment mEnvironment;
+ private final Executor mExecutor;
+ private final Handler mHandler;
/**
- * Create a {@link TestSensorOperation}.
- *
- * @param environment the test environment
- * @param eventCount the number of events to gather
+ * An interface that defines an abstraction for operations to be performed by the
+ * {@link TestSensorOperation}.
*/
- public TestSensorOperation(TestSensorEnvironment environment, int eventCount) {
- this(environment, eventCount, null /* duration */, null /* timeUnit */);
+ public interface Executor {
+ void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
+ throws InterruptedException;
}
/**
* Create a {@link TestSensorOperation}.
- *
- * @param environment the test environment
- * @param duration the duration to gather events for
- * @param timeUnit the time unit of the duration
+ */
+ public TestSensorOperation(TestSensorEnvironment environment, Executor executor) {
+ this(environment, executor, null /* handler */);
+ }
+
+ /**
+ * Create a {@link TestSensorOperation}.
*/
public TestSensorOperation(
TestSensorEnvironment environment,
- long duration,
- TimeUnit timeUnit) {
- this(environment, null /* eventCount */, duration, timeUnit);
+ Executor executor,
+ Handler handler) {
+ mEnvironment = environment;
+ mExecutor = executor;
+ mHandler = handler;
+ mSensorManager = new TestSensorManager(mEnvironment);
}
/**
- * Private helper constructor.
+ * Set all of the default test expectations.
*/
- private TestSensorOperation(
+ public void addDefaultVerifications() {
+ addVerification(EventGapVerification.getDefault(mEnvironment));
+ addVerification(EventOrderingVerification.getDefault(mEnvironment));
+ addVerification(FrequencyVerification.getDefault(mEnvironment));
+ addVerification(JitterVerification.getDefault(mEnvironment));
+ addVerification(MagnitudeVerification.getDefault(mEnvironment));
+ addVerification(MeanVerification.getDefault(mEnvironment));
+ addVerification(StandardDeviationVerification.getDefault(mEnvironment));
+ addVerification(EventTimestampSynchronizationVerification.getDefault(mEnvironment));
+ }
+
+ public void addVerification(ISensorVerification verification) {
+ if (verification != null) {
+ mVerifications.add(verification);
+ }
+ }
+
+ /**
+ * Collect the specified number of events from the sensor and run all enabled verifications.
+ */
+ @Override
+ public void execute(ISensorTestNode parent) throws InterruptedException {
+ getStats().addValue("sensor_name", mEnvironment.getSensor().getName());
+ TestSensorEventListener listener = new TestSensorEventListener(mEnvironment, mHandler);
+ mExecutor.execute(mSensorManager, listener);
+
+ boolean failed = false;
+ StringBuilder sb = new StringBuilder();
+ List<TestSensorEvent> collectedEvents = listener.getCollectedEvents();
+ for (ISensorVerification verification : mVerifications) {
+ failed |= evaluateResults(collectedEvents, verification, sb);
+ }
+
+ if (failed) {
+ trySaveCollectedEvents(parent, listener);
+
+ String msg = SensorCtsHelper
+ .formatAssertionMessage("VerifySensorOperation", mEnvironment, sb.toString());
+ getStats().addValue(SensorStats.ERROR, msg);
+ Assert.fail(msg);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public TestSensorOperation clone() {
+ TestSensorOperation operation = new TestSensorOperation(mEnvironment, mExecutor);
+ for (ISensorVerification verification : mVerifications) {
+ operation.addVerification(verification.clone());
+ }
+ return operation;
+ }
+
+ /**
+ * Evaluate the results of a test, aggregate the stats, and build the error message.
+ */
+ private boolean evaluateResults(
+ List<TestSensorEvent> events,
+ ISensorVerification verification,
+ StringBuilder sb) {
+ try {
+ // this is an intermediate state in refactoring, at some point verifications might
+ // become stateless
+ verification.addSensorEvents(events);
+ verification.verify(mEnvironment, getStats());
+ } catch (AssertionError e) {
+ if (sb.length() > 0) {
+ sb.append(", ");
+ }
+ sb.append(e.getMessage());
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Tries to save collected {@link TestSensorEvent}s to a file.
+ *
+ * NOTE: it is more important to handle verifications and its results, than failing if the file
+ * cannot be created. So we silently fail if necessary.
+ */
+ private void trySaveCollectedEvents(ISensorTestNode parent, TestSensorEventListener listener) {
+ String sanitizedFileName;
+ try {
+ String fileName = asTestNode(parent).getName();
+ sanitizedFileName = String.format(
+ "%s-%s-%s_%dus.txt",
+ SensorCtsHelper.sanitizeStringForFileName(fileName),
+ SensorStats.getSanitizedSensorName(mEnvironment.getSensor()),
+ mEnvironment.getFrequencyString(),
+ mEnvironment.getMaxReportLatencyUs());
+ } catch (SensorTestPlatformException e) {
+ Log.w(TAG, "Unable to generate file name to save collected events", e);
+ return;
+ }
+
+ try {
+ listener.logCollectedEventsToFile(sanitizedFileName);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to save collected events to file: " + sanitizedFileName, e);
+ }
+ }
+
+ /**
+ * Creates an operation that will wait for a given amount of events to arrive.
+ *
+ * @param environment The test environment.
+ * @param eventCount The number of events to wait for.
+ */
+ public static TestSensorOperation createOperation(
TestSensorEnvironment environment,
- Integer eventCount,
- Long duration,
- TimeUnit timeUnit) {
- super(environment);
- mEventCount = eventCount;
- mDuration = duration;
- mTimeUnit = timeUnit;
+ final int eventCount) {
+ Executor executor = new Executor() {
+ @Override
+ public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
+ throws InterruptedException {
+ try {
+ sensorManager.registerListener(listener);
+ listener.waitForEvents(eventCount);
+ } finally {
+ sensorManager.unregisterListener();
+ }
+ }
+ };
+ return new TestSensorOperation(environment, executor);
}
/**
- * {@inheritDoc}
+ * Creates an operation that will wait for a given amount of time to collect events.
+ *
+ * @param environment The test environment.
+ * @param duration The duration to wait for events.
+ * @param timeUnit The time unit for {@code duration}.
*/
- @Override
- protected void doExecute(TestSensorEventListener listener) throws InterruptedException {
- if (mEventCount != null) {
- mSensorManager.runSensor(listener, mEventCount);
- } else {
- mSensorManager.runSensor(listener, mDuration, mTimeUnit);
- }
+ public static TestSensorOperation createOperation(
+ TestSensorEnvironment environment,
+ final long duration,
+ final TimeUnit timeUnit) {
+ Executor executor = new Executor() {
+ @Override
+ public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
+ throws InterruptedException {
+ try {
+ sensorManager.registerListener(listener);
+ listener.waitForEvents(duration, timeUnit);
+ } finally {
+ sensorManager.unregisterListener();
+ }
+ }
+ };
+ return new TestSensorOperation(environment, executor);
}
/**
- * {@inheritDoc}
+ * Creates an operation that will wait for a given amount of time before calling
+ * {@link TestSensorManager#requestFlush()}.
+ *
+ * @param environment The test environment.
+ * @param duration The duration to wait before calling {@link TestSensorManager#requestFlush()}.
+ * @param timeUnit The time unit for {@code duration}.
*/
- @Override
- protected VerifiableSensorOperation doClone() {
- if (mEventCount != null) {
- return new TestSensorOperation(mEnvironment, mEventCount);
- } else {
- return new TestSensorOperation(mEnvironment, mDuration, mTimeUnit);
- }
+ public static TestSensorOperation createFlushOperation(
+ TestSensorEnvironment environment,
+ final long duration,
+ final TimeUnit timeUnit) {
+ Executor executor = new Executor() {
+ @Override
+ public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
+ throws InterruptedException {
+ try {
+ sensorManager.registerListener(listener);
+ SensorCtsHelper.sleep(duration, timeUnit);
+ sensorManager.requestFlush();
+ listener.waitForFlushComplete();
+ } finally {
+ sensorManager.unregisterListener();
+ }
+ }
+ };
+ return new TestSensorOperation(environment, executor);
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/VerifiableSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/VerifiableSensorOperation.java
deleted file mode 100644
index 57018eb..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/VerifiableSensorOperation.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers.sensoroperations;
-
-import junit.framework.Assert;
-
-import android.hardware.cts.helpers.SensorCtsHelper;
-import android.hardware.cts.helpers.SensorStats;
-import android.hardware.cts.helpers.TestSensorEnvironment;
-import android.hardware.cts.helpers.TestSensorEventListener;
-import android.hardware.cts.helpers.TestSensorManager;
-import android.hardware.cts.helpers.ValidatingSensorEventListener;
-import android.hardware.cts.helpers.sensorverification.EventGapVerification;
-import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
-import android.hardware.cts.helpers.sensorverification.FrequencyVerification;
-import android.hardware.cts.helpers.sensorverification.ISensorVerification;
-import android.hardware.cts.helpers.sensorverification.JitterVerification;
-import android.hardware.cts.helpers.sensorverification.MagnitudeVerification;
-import android.hardware.cts.helpers.sensorverification.MeanVerification;
-import android.hardware.cts.helpers.sensorverification.StandardDeviationVerification;
-
-import java.util.Collection;
-import java.util.HashSet;
-
-/**
- * A {@link ISensorOperation} used to verify that sensor events and sensor values are correct.
- * <p>
- * Provides methods to set test expectations as well as providing a set of default expectations
- * depending on sensor type. When {{@link #execute()} is called, the sensor will collect the
- * events and then run all the tests.
- * </p>
- */
-public abstract class VerifiableSensorOperation extends AbstractSensorOperation {
- protected final TestSensorManager mSensorManager;
- protected final TestSensorEnvironment mEnvironment;
-
- private final Collection<ISensorVerification> mVerifications =
- new HashSet<ISensorVerification>();
-
- private boolean mLogEvents = false;
-
- /**
- * Create a {@link TestSensorOperation}.
- *
- * @param environment the test environment
- */
- public VerifiableSensorOperation(TestSensorEnvironment environment) {
- mEnvironment = environment;
- mSensorManager = new TestSensorManager(mEnvironment);
- }
-
- /**
- * Set whether to log events.
- */
- public void setLogEvents(boolean logEvents) {
- mLogEvents = logEvents;
- }
-
- /**
- * Set all of the default test expectations.
- */
- public void addDefaultVerifications() {
- addVerification(EventGapVerification.getDefault(mEnvironment));
- addVerification(EventOrderingVerification.getDefault(mEnvironment));
- addVerification(FrequencyVerification.getDefault(mEnvironment));
- addVerification(JitterVerification.getDefault(mEnvironment));
- addVerification(MagnitudeVerification.getDefault(mEnvironment));
- addVerification(MeanVerification.getDefault(mEnvironment));
- // Skip SigNumVerification since it has no default
- addVerification(StandardDeviationVerification.getDefault(mEnvironment));
- }
-
- public void addVerification(ISensorVerification verification) {
- if (verification != null) {
- mVerifications.add(verification);
- }
- }
-
- /**
- * Collect the specified number of events from the sensor and run all enabled verifications.
- */
- @Override
- public void execute() throws InterruptedException {
- getStats().addValue("sensor_name", mEnvironment.getSensor().getName());
-
- ValidatingSensorEventListener listener = new ValidatingSensorEventListener(mVerifications);
- listener.setLogEvents(mLogEvents);
-
- doExecute(listener);
-
- boolean failed = false;
- StringBuilder sb = new StringBuilder();
- for (ISensorVerification verification : mVerifications) {
- failed |= evaluateResults(verification, sb);
- }
-
- if (failed) {
- String msg = SensorCtsHelper
- .formatAssertionMessage("VerifySensorOperation", mEnvironment, sb.toString());
- getStats().addValue(SensorStats.ERROR, msg);
- Assert.fail(msg);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public VerifiableSensorOperation clone() {
- VerifiableSensorOperation operation = doClone();
- for (ISensorVerification verification : mVerifications) {
- operation.addVerification(verification.clone());
- }
- return operation;
- }
-
- /**
- * Execute operations in a {@link TestSensorManager}.
- */
- protected abstract void doExecute(TestSensorEventListener listener) throws InterruptedException;
-
- /**
- * Clone the subclass operation.
- */
- protected abstract VerifiableSensorOperation doClone();
-
- /**
- * Evaluate the results of a test, aggregate the stats, and build the error message.
- */
- private boolean evaluateResults(ISensorVerification verification, StringBuilder sb) {
- try {
- verification.verify(mEnvironment, getStats());
- } catch (AssertionError e) {
- if (sb.length() > 0) {
- sb.append(", ");
- }
- sb.append(e.getMessage());
- return true;
- }
- return false;
- }
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
index b500ea7..9f03f31 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
@@ -17,41 +17,42 @@
package android.hardware.cts.helpers.sensoroperations;
import android.content.Context;
-import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
/**
- * An {@link ISensorOperation} which holds a wakelock while performing another
- * {@link ISensorOperation}.
+ * An {@link SensorOperation} which holds a wake-lock while performing another
+ * {@link SensorOperation}.
*/
-public class WakeLockOperation extends AbstractSensorOperation {
+public class WakeLockOperation extends SensorOperation {
private static final String TAG = "WakeLockOperation";
- private final ISensorOperation mOperation;
+ private final SensorOperation mOperation;
private final Context mContext;
- private final int mWakelockFlags;
+ private final int mWakeLockFlags;
/**
* Constructor for {@link WakeLockOperation}.
*
- * @param operation the child {@link ISensorOperation} to perform after the delay
+ * @param operation the child {@link SensorOperation} to perform after the delay
* @param context the context used to access the power manager
- * @param wakelockFlags the flags used when acquiring the wakelock
+ * @param wakeLockFlags the flags used when acquiring the wake-lock
*/
- public WakeLockOperation(ISensorOperation operation, Context context, int wakelockFlags) {
+ public WakeLockOperation(SensorOperation operation, Context context, int wakeLockFlags) {
+ super(operation.getStats());
mOperation = operation;
mContext = context;
- mWakelockFlags = wakelockFlags;
+ mWakeLockFlags = wakeLockFlags;
}
/**
* Constructor for {@link WakeLockOperation}.
*
- * @param operation the child {@link ISensorOperation} to perform after the delay
+ * @param operation the child {@link SensorOperation} to perform after the delay
* @param context the context used to access the power manager
*/
- public WakeLockOperation(ISensorOperation operation, Context context) {
+ public WakeLockOperation(SensorOperation operation, Context context) {
this(operation, context, PowerManager.PARTIAL_WAKE_LOCK);
}
@@ -59,13 +60,12 @@
* {@inheritDoc}
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- WakeLock wakeLock = pm.newWakeLock(mWakelockFlags, TAG);
-
+ WakeLock wakeLock = pm.newWakeLock(mWakeLockFlags, TAG);
wakeLock.acquire();
try {
- mOperation.execute();
+ mOperation.execute(asTestNode(parent));
} finally {
wakeLock.release();
}
@@ -75,15 +75,7 @@
* {@inheritDoc}
*/
@Override
- public SensorStats getStats() {
- return mOperation.getStats();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public ISensorOperation clone() {
- return new WakeLockOperation(mOperation, mContext, mWakelockFlags);
+ public SensorOperation clone() {
+ return new WakeLockOperation(mOperation.clone(), mContext, mWakeLockFlags);
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
index 911ae3a..1e775e3 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
@@ -18,6 +18,9 @@
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.Collection;
+import java.util.List;
+
/**
* Abstract class that deals with the synchronization of the sensor verifications.
*/
@@ -27,7 +30,7 @@
* {@inheritDoc}
*/
@Override
- public synchronized void addSensorEvents(TestSensorEvent ... events) {
+ public synchronized void addSensorEvents(Collection<TestSensorEvent> events) {
for (TestSensorEvent event : events) {
addSensorEventInternal(event);
}
@@ -37,14 +40,6 @@
* {@inheritDoc}
*/
@Override
- public synchronized void addSensorEvent(TestSensorEvent event) {
- addSensorEventInternal(event);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public abstract ISensorVerification clone();
/**
@@ -52,18 +47,38 @@
*/
protected abstract void addSensorEventInternal(TestSensorEvent event);
+ protected <TEvent extends IndexedEvent> int[] getIndexArray(List<TEvent> indexedEvents) {
+ int eventsCount = indexedEvents.size();
+ int[] indices = new int[eventsCount];
+ for (int i = 0; i < eventsCount; i++) {
+ indices[i] = indexedEvents.get(i).index;
+ }
+ return indices;
+ }
+
+ /**
+ * Helper class to store the index and current event.
+ * Events are added to the verification in the order they are generated, the index represents
+ * the position of the given event, in the list of added events.
+ */
+ protected class IndexedEvent {
+ public final int index;
+ public final TestSensorEvent event;
+
+ public IndexedEvent(int index, TestSensorEvent event) {
+ this.index = index;
+ this.event = event;
+ }
+ }
+
/**
* Helper class to store the index, previous event, and current event.
*/
- protected class IndexedEventPair {
- public final int index;
- public final TestSensorEvent event;
+ protected class IndexedEventPair extends IndexedEvent {
public final TestSensorEvent previousEvent;
- public IndexedEventPair(int index, TestSensorEvent event,
- TestSensorEvent previousEvent) {
- this.index = index;
- this.event = event;
+ public IndexedEventPair(int index, TestSensorEvent event, TestSensorEvent previousEvent) {
+ super(index, event);
this.previousEvent = previousEvent;
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java
index 156afa8..b692f0f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java
@@ -63,19 +63,14 @@
public void verify(TestSensorEnvironment environment, SensorStats stats) {
if (environment.isSensorSamplingRateOverloaded()) {
// the verification is not reliable on environments under load
- stats.addValue(PASSED_KEY, true);
+ 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);
-
- final int[] indices = new int[count];
- for (int i = 0; i < indices.length; i++) {
- indices[i] = mEventGaps.get(i).index;
- }
- stats.addValue(SensorStats.EVENT_GAP_POSITIONS_KEY, indices);
+ stats.addValue(SensorStats.EVENT_GAP_POSITIONS_KEY, getIndexArray(mEventGaps));
if (count > 0) {
StringBuilder sb = new StringBuilder();
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
index d01e108..6f17e7b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link EventGapVerification}.
*/
@@ -90,11 +93,13 @@
}
}
- private ISensorVerification getVerification(int expected, long ... timestamps) {
- ISensorVerification verification = new EventGapVerification(expected);
+ private static EventGapVerification getVerification(int expected, long ... timestamps) {
+ Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
for (long timestamp : timestamps) {
- verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ events.add(new TestSensorEvent(null, timestamp, 0, null));
}
+ EventGapVerification verification = new EventGapVerification(expected);
+ verification.addSensorEvents(events);
return verification;
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
index 6598725..7b77ead 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
@@ -75,12 +75,9 @@
final int count = mOutOfOrderEvents.size();
stats.addValue(PASSED_KEY, count == 0);
stats.addValue(SensorStats.EVENT_OUT_OF_ORDER_COUNT_KEY, count);
-
- final int[] indices = new int[count];
- for (int i = 0; i < indices.length; i++) {
- indices[i] = mOutOfOrderEvents.get(i).index;
- }
- stats.addValue(SensorStats.EVENT_OUT_OF_ORDER_POSITIONS_KEY, indices);
+ stats.addValue(
+ SensorStats.EVENT_OUT_OF_ORDER_POSITIONS_KEY,
+ getIndexArray(mOutOfOrderEvents));
if (count > 0) {
StringBuilder sb = new StringBuilder();
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
index 88d5c19..b9848fa 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
@@ -22,6 +22,7 @@
import android.hardware.cts.helpers.TestSensorEvent;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -96,11 +97,13 @@
assertTrue(indices.contains(4));
}
- private EventOrderingVerification getVerification(long ... timestamps) {
- EventOrderingVerification verification = new EventOrderingVerification();
+ private static EventOrderingVerification getVerification(long ... timestamps) {
+ Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
for (long timestamp : timestamps) {
- verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ events.add(new TestSensorEvent(null, timestamp, 0, null));
}
+ EventOrderingVerification verification = new EventOrderingVerification();
+ verification.addSensorEvents(events);
return verification;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
new file mode 100644
index 0000000..d4a1f38
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.hardware.cts.helpers.sensorverification;
+
+import junit.framework.Assert;
+
+import android.hardware.SensorEvent;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.TestSensorEvent;
+import android.os.SystemClock;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link ISensorVerification} which verifies that the timestamp of the {@link SensorEvent} is
+ * synchronized with {@link SystemClock#elapsedRealtimeNanos()}, based on a given threshold.
+ */
+public class EventTimestampSynchronizationVerification extends AbstractSensorVerification {
+ public static final String PASSED_KEY = "timestamp_synchronization_passed";
+
+ // number of indices to print in assertion message before truncating
+ private static final int TRUNCATE_MESSAGE_LENGTH = 3;
+
+ private static final long DEFAULT_THRESHOLD_NS = TimeUnit.MILLISECONDS.toNanos(500);
+
+ private final ArrayList<TestSensorEvent> mCollectedEvents = new ArrayList<TestSensorEvent>();
+
+ private final long mMaximumSynchronizationErrorNs;
+ private final long mReportLatencyNs;
+
+ /**
+ * Constructs an instance of {@link EventTimestampSynchronizationVerification}.
+ *
+ * @param maximumSynchronizationErrorNs The valid threshold for timestamp synchronization.
+ * @param reportLatencyNs The latency on which batching events are received
+ */
+ public EventTimestampSynchronizationVerification(
+ long maximumSynchronizationErrorNs,
+ long reportLatencyNs) {
+ mMaximumSynchronizationErrorNs = maximumSynchronizationErrorNs;
+ mReportLatencyNs = reportLatencyNs;
+ }
+
+ /**
+ * Gets a default {@link EventTimestampSynchronizationVerification}.
+ *
+ * @param environment The test environment
+ * @return The verification or null if the verification is not supported in the given
+ * environment.
+ */
+ public static EventTimestampSynchronizationVerification getDefault(
+ TestSensorEnvironment environment) {
+ int reportLatencyUs = environment.getMaxReportLatencyUs();
+ int fifoMaxEventCount = environment.getSensor().getFifoMaxEventCount();
+ if (fifoMaxEventCount > 0) {
+ int fifoBasedReportLatencyUs =
+ fifoMaxEventCount * environment.getMaximumExpectedSamplingPeriodUs();
+ reportLatencyUs = Math.min(reportLatencyUs, fifoBasedReportLatencyUs);
+
+ }
+ long reportLatencyNs = TimeUnit.MICROSECONDS.toNanos(reportLatencyUs);
+ return new EventTimestampSynchronizationVerification(DEFAULT_THRESHOLD_NS, reportLatencyNs);
+ }
+
+ @Override
+ public void verify(TestSensorEnvironment environment, SensorStats stats) {
+ StringBuilder errorMessageBuilder =
+ new StringBuilder(" event timestamp synchronization failures: ");
+ List<IndexedEvent> failures = verifyTimestampSynchronization(errorMessageBuilder);
+
+ int failuresCount = failures.size();
+ stats.addValue(SensorStats.EVENT_TIME_SYNCHRONIZATION_COUNT_KEY, failuresCount);
+ stats.addValue(
+ SensorStats.EVENT_TIME_SYNCHRONIZATION_POSITIONS_KEY,
+ getIndexArray(failures));
+
+ boolean success = failures.isEmpty();
+ stats.addValue(PASSED_KEY, success);
+ errorMessageBuilder.insert(0, failuresCount);
+ Assert.assertTrue(errorMessageBuilder.toString(), success);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EventTimestampSynchronizationVerification clone() {
+ return new EventTimestampSynchronizationVerification(
+ mMaximumSynchronizationErrorNs,
+ mReportLatencyNs);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addSensorEventInternal(TestSensorEvent event) {
+ mCollectedEvents.add(event);
+ }
+
+ /**
+ * Verifies timestamp synchronization for all sensor events.
+ * The verification accounts for a lower and upper threshold, such thresholds are adjusted for
+ * batching cases.
+ *
+ * @param builder A string builder to store error messaged found in the collected sensor events.
+ * @return A list of events tha failed the verification.
+ */
+ private List<IndexedEvent> verifyTimestampSynchronization(StringBuilder builder) {
+ int collectedEventsCount = mCollectedEvents.size();
+ ArrayList<IndexedEvent> failures = new ArrayList<IndexedEvent>();
+
+ for (int i = 0; i < collectedEventsCount; ++i) {
+ TestSensorEvent event = mCollectedEvents.get(i);
+ long eventTimestampNs = event.timestamp;
+ long receivedTimestampNs = event.receivedTimestamp;
+ long upperThresholdNs = receivedTimestampNs;
+ long lowerThresholdNs = receivedTimestampNs - mMaximumSynchronizationErrorNs
+ - mReportLatencyNs;
+
+ if (eventTimestampNs < lowerThresholdNs || eventTimestampNs > upperThresholdNs) {
+ if (failures.size() < TRUNCATE_MESSAGE_LENGTH) {
+ builder.append("position=").append(i);
+ builder.append(", timestamp=").append(eventTimestampNs).append("ns");
+ builder.append(", expected=[").append(lowerThresholdNs);
+ builder.append(", ").append(upperThresholdNs).append("]ns; ");
+ }
+ failures.add(new IndexedEvent(i, event));
+ }
+ }
+ if (failures.size() >= TRUNCATE_MESSAGE_LENGTH) {
+ builder.append("more; ");
+ }
+ return failures;
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
index 24349ce..bbf022a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link EventOrderingVerification}.
*/
@@ -73,15 +76,17 @@
return new TestSensorEnvironment(getContext(), Sensor.TYPE_ALL, rateUs);
}
- private ISensorVerification getVerification(
+ private static FrequencyVerification getVerification(
double lowerThreshold,
double upperThreshold,
long ... timestamps) {
- ISensorVerification verification =
- new FrequencyVerification(lowerThreshold, upperThreshold);
+ Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
for (long timestamp : timestamps) {
- verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ events.add(new TestSensorEvent(null, timestamp, 0, null));
}
+ FrequencyVerification verification =
+ new FrequencyVerification(lowerThreshold, upperThreshold);
+ verification.addSensorEvents(events);
return verification;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
index 4f7b65a..2027f0f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
@@ -20,24 +20,25 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.Collection;
+
/**
- * Interface describing the sensor verification. This class was designed for to handle streaming
- * events. The methods {@link #addSensorEvent(TestSensorEvent)} and
- * {@link #addSensorEvents(TestSensorEvent...)} should be called in the order that the events are
- * received. The method {@link #verify(TestSensorEnvironment, SensorStats)} should be called after
- * all events are added.
+ * Interface describing the sensor verification.
+ * This class was designed to handle streaming of events.
+ *
+ * The method {@link #addSensorEvents(Collection)} should be called in the order that the events are
+ * received.
+ *
+ * The method {@link #verify(TestSensorEnvironment, SensorStats)} should be called after all events
+ * are added.
*/
public interface ISensorVerification {
/**
- * Add a single {@link TestSensorEvent} to be evaluated.
+ * Add a list of {@link TestSensorEvent}s to be evaluated.
*/
- public void addSensorEvent(TestSensorEvent event);
-
- /**
- * Add multiple {@link TestSensorEvent}s to be evaluated.
- */
- public void addSensorEvents(TestSensorEvent ... events);
+ // TODO: refactor verifications to be stateless, and pass the list of events in verify()
+ void addSensorEvents(Collection<TestSensorEvent> events);
/**
* Evaluate all added {@link TestSensorEvent}s and update stats.
@@ -45,10 +46,10 @@
* @param stats a {@link SensorStats} object used to keep track of the stats.
* @throws AssertionError if the verification fails.
*/
- public void verify(TestSensorEnvironment environment, SensorStats stats);
+ void verify(TestSensorEnvironment environment, SensorStats stats);
/**
* Clones the {@link ISensorVerification}
*/
- public ISensorVerification clone();
+ ISensorVerification clone();
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
index 0c85b63..50e288c 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
@@ -22,6 +22,8 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -98,11 +100,13 @@
assertEquals(3.0, jitterValues.get(3));
}
- private JitterVerification getVerification(int threshold, long ... timestamps) {
- JitterVerification verification = new JitterVerification(threshold);
+ private static JitterVerification getVerification(int threshold, long ... timestamps) {
+ Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
for (long timestamp : timestamps) {
- verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ events.add(new TestSensorEvent(null, timestamp, 0, null));
}
+ JitterVerification verification = new JitterVerification(threshold);
+ verification.addSensorEvents(events);
return verification;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
index bb29330..ac873c1 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link MagnitudeVerification}.
*/
@@ -63,12 +66,14 @@
assertEquals(magnitude, (Float) stats.getValue(SensorStats.MAGNITUDE_KEY), 0.01);
}
- private MagnitudeVerification getVerification(float expected, float threshold,
+ private static MagnitudeVerification getVerification(float expected, float threshold,
float[] ... values) {
- MagnitudeVerification verification = new MagnitudeVerification(expected, threshold);
+ Collection<TestSensorEvent> events = new ArrayList<>(values.length);
for (float[] value : values) {
- verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ events.add(new TestSensorEvent(null, 0, 0, value));
}
+ MagnitudeVerification verification = new MagnitudeVerification(expected, threshold);
+ verification.addSensorEvents(events);
return verification;
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
index b07ea50..d7fcf9f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link MeanVerification}.
*/
@@ -89,12 +92,14 @@
verifyStats(stats, false, new float[]{2.0f, 3.0f, 6.0f});
}
- private MeanVerification getVerification(float[] expected, float[] threshold,
+ private static MeanVerification getVerification(float[] expected, float[] threshold,
float[] ... values) {
- MeanVerification verification = new MeanVerification(expected, threshold);
+ Collection<TestSensorEvent> events = new ArrayList<>(values.length);
for (float[] value : values) {
- verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ events.add(new TestSensorEvent(null, 0, 0, value));
}
+ MeanVerification verification = new MeanVerification(expected, threshold);
+ verification.addSensorEvents(events);
return verification;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
index 5d958f5..617a438 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link StandardDeviationVerification}.
*/
@@ -79,11 +82,15 @@
}
}
- private StandardDeviationVerification getVerification(float[] threshold, float[] ... values) {
- StandardDeviationVerification verification = new StandardDeviationVerification(threshold);
+ private static StandardDeviationVerification getVerification(
+ float[] threshold,
+ float[] ... values) {
+ Collection<TestSensorEvent> events = new ArrayList<>(values.length);
for (float[] value : values) {
- verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ events.add(new TestSensorEvent(null, 0, 0, value));
}
+ StandardDeviationVerification verification = new StandardDeviationVerification(threshold);
+ verification.addSensorEvents(events);
return verification;
}
}