Allow for long running operations.
Refactor sensor verifications to allow for running verifications on the
fly. This changes how the sensor manager works, moves the test sensor
event listener to a separate class, and breaks up the verifications into
individual classes for more flexibility.
Change-Id: If712edb589206adce95347de2e0fe975fcaff188
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 44bed6c..5a0af28 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
@@ -18,7 +18,8 @@
import android.hardware.Sensor;
import android.hardware.SensorManager;
-import android.hardware.cts.helpers.sensoroperations.VerifySensorOperation;
+import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
+import android.hardware.cts.helpers.sensorverification.MeanVerification;
import java.util.concurrent.TimeUnit;
@@ -74,15 +75,15 @@
*/
private void verifyMeasurements(float ... expectations) throws Throwable {
Thread.sleep(500 /*ms*/);
- VerifySensorOperation verifyMeasurements = new VerifySensorOperation(
+ TestSensorOperation verifyMeasurements = new TestSensorOperation(
getApplicationContext(),
Sensor.TYPE_ACCELEROMETER,
SensorManager.SENSOR_DELAY_FASTEST,
0 /*reportLatencyInUs*/,
100 /* event count */);
- verifyMeasurements.verifyMean(
+ verifyMeasurements.addVerification(new MeanVerification(
expectations,
- new float[]{1.95f, 1.95f, 1.95f} /* m / s^2 */);
+ new float[]{1.95f, 1.95f, 1.95f} /* m / s^2 */));
verifyMeasurements.execute();
logSuccess();
}
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 cdb5b3f..066bda4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
@@ -18,7 +18,8 @@
import android.hardware.Sensor;
import android.hardware.SensorManager;
-import android.hardware.cts.helpers.sensoroperations.VerifySensorOperation;
+import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
+import android.hardware.cts.helpers.sensorverification.SigNumVerification;
/**
* Semi-automated test that focuses on characteristics associated with Accelerometer measurements.
@@ -96,15 +97,15 @@
waitForUser();
Thread.sleep(500 /*ms*/);
- VerifySensorOperation verifySignum = new VerifySensorOperation(
+ TestSensorOperation verifySignum = new TestSensorOperation(
getApplicationContext(),
Sensor.TYPE_GYROSCOPE,
SensorManager.SENSOR_DELAY_FASTEST,
0 /*reportLatencyInUs*/,
100 /* event count */);
- verifySignum.verifySignum(
+ verifySignum.addVerification(new SigNumVerification(
expectations,
- new float[]{0.2f, 0.2f, 0.2f} /*noiseThreshold*/);
+ new float[]{0.2f, 0.2f, 0.2f} /*noiseThreshold*/));
verifySignum.execute();
logSuccess();
}
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 d36c998..a131b2b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
@@ -21,8 +21,11 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener2;
import android.hardware.SensorManager;
+import android.hardware.cts.helpers.TestSensorEventListener;
import android.hardware.cts.helpers.TestSensorManager;
-import android.hardware.cts.helpers.sensoroperations.VerifySensorOperation;
+import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
+import android.hardware.cts.helpers.sensorverification.MagnitudeVerification;
+import android.hardware.cts.helpers.sensorverification.StandardDeviationVerification;
/**
* Semi-automated test that focuses characteristics associated with Accelerometer measurements.
@@ -64,9 +67,9 @@
TestSensorManager magnetometer = new TestSensorManager(
this.getApplicationContext(), Sensor.TYPE_MAGNETIC_FIELD,
- SensorManager.SENSOR_DELAY_NORMAL, 0, listener);
+ SensorManager.SENSOR_DELAY_NORMAL, 0);
try {
- magnetometer.registerListener();
+ magnetometer.registerListener(new TestSensorEventListener(listener));
waitForUser();
} finally {
magnetometer.unregisterListener();
@@ -98,15 +101,15 @@
(SensorManager.MAGNETIC_FIELD_EARTH_MAX + SensorManager.MAGNETIC_FIELD_EARTH_MIN) / 2;
float magneticFieldEarthThreshold =
expectedMagneticFieldEarth - SensorManager.MAGNETIC_FIELD_EARTH_MIN;
- VerifySensorOperation verifyNorm = new VerifySensorOperation(
+ TestSensorOperation verifyNorm = new TestSensorOperation(
this.getApplicationContext(),
Sensor.TYPE_MAGNETIC_FIELD,
SensorManager.SENSOR_DELAY_FASTEST,
0 /*reportLatencyInUs*/,
100 /* event count */);
- verifyNorm.verifyMagnitude(
+ verifyNorm.addVerification(new MagnitudeVerification(
expectedMagneticFieldEarth,
- magneticFieldEarthThreshold);
+ magneticFieldEarthThreshold));
verifyNorm.execute();
logSuccess();
}
@@ -135,14 +138,14 @@
* the failure to help track down the issue.
*/
private void verifyStandardDeviation() throws Throwable {
- VerifySensorOperation verifyStdDev = new VerifySensorOperation(
+ TestSensorOperation verifyStdDev = new TestSensorOperation(
this.getApplicationContext(),
Sensor.TYPE_MAGNETIC_FIELD,
SensorManager.SENSOR_DELAY_FASTEST,
0 /*reportLatencyInUs*/,
100 /* event count */);
- verifyStdDev.verifyStandardDeviation(
- new float[]{2f, 2f, 2f} /* uT */);
+ verifyStdDev.addVerification(new StandardDeviationVerification(
+ new float[]{2f, 2f, 2f} /* uT */));
verifyStdDev.execute();
logSuccess();
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
index bcf9755..c27d108 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
@@ -25,7 +25,8 @@
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.VerifySensorOperation;
+import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
+import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -96,22 +97,22 @@
ParallelSensorOperation operation = new ParallelSensorOperation();
for(int sensorType : sensorTypes) {
- VerifySensorOperation continuousOperation = new VerifySensorOperation(
+ TestSensorOperation continuousOperation = new TestSensorOperation(
context,
sensorType,
SensorManager.SENSOR_DELAY_NORMAL,
0 /* reportLatencyInUs */,
100 /* event count */);
- continuousOperation.verifyEventOrdering();
+ continuousOperation.addVerification(new EventOrderingVerification());
operation.add(new RepeatingSensorOperation(continuousOperation, ITERATIONS));
- VerifySensorOperation batchingOperation = new VerifySensorOperation(
+ TestSensorOperation batchingOperation = new TestSensorOperation(
context,
sensorType,
SensorTestInformation.getMaxSamplingRateInUs(context, sensorType),
SensorCtsHelper.getSecondsAsMicroSeconds(BATCHING_RATE_IN_SECONDS),
100);
- batchingOperation.verifyEventOrdering();
+ batchingOperation.addVerification(new EventOrderingVerification());
operation.add(new RepeatingSensorOperation(batchingOperation, ITERATIONS));
}
operation.execute();
@@ -154,13 +155,13 @@
for(int instance = 0; instance < INSTANCES_TO_USE; ++instance) {
SequentialSensorOperation sequentialOperation = new SequentialSensorOperation();
for(int iteration = 0; iteration < ITERATIONS_TO_EXECUTE; ++iteration) {
- VerifySensorOperation sensorOperation = new VerifySensorOperation(
+ TestSensorOperation sensorOperation = new TestSensorOperation(
this.getContext(),
sensorType,
this.generateSamplingRateInUs(sensorType),
this.generateReportLatencyInUs(),
100);
- sensorOperation.verifyEventOrdering();
+ sensorOperation.addVerification(new EventOrderingVerification());
sequentialOperation.add(sensorOperation);
}
operation.add(sequentialOperation);
@@ -218,21 +219,21 @@
public void testSensorStoppingInteraction() throws Throwable {
Context context = this.getContext();
- VerifySensorOperation tester = new VerifySensorOperation(
+ TestSensorOperation tester = new TestSensorOperation(
context,
mSensorTypeTester,
SensorManager.SENSOR_DELAY_NORMAL,
0 /*reportLatencyInUs*/,
100 /* event count */);
- tester.verifyEventOrdering();
+ tester.addVerification(new EventOrderingVerification());
- VerifySensorOperation testee = new VerifySensorOperation(
+ TestSensorOperation testee = new TestSensorOperation(
context,
mSensorTypeTestee,
SensorManager.SENSOR_DELAY_UI,
0 /*reportLatencyInUs*/,
100 /* event count */);
- testee.verifyEventOrdering();
+ testee.addVerification(new EventOrderingVerification());
ParallelSensorOperation operation = new ParallelSensorOperation();
operation.add(tester, testee);
diff --git a/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java b/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
index 8bdc161..647e7dc 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
@@ -22,11 +22,13 @@
import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.SensorTestCase;
import android.hardware.cts.helpers.SensorTestInformation;
-import android.hardware.cts.helpers.sensoroperations.VerifySensorOperation;
+import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
+import android.util.Log;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
/**
* Set of tests to verify that sensors operate correctly when operating alone.
@@ -214,12 +216,21 @@
minDelay * 8,
minDelay * 16,
};
+ int[] maxBatchReportLatencyUss = {
+ 0, // No batching
+ (int) TimeUnit.MICROSECONDS.convert(1, TimeUnit.SECONDS),
+ (int) TimeUnit.MICROSECONDS.convert(5, TimeUnit.SECONDS),
+ };
for (int rateUs : rateUss) {
- VerifySensorOperation op = new VerifySensorOperation(this.getContext(), sensorType,
- rateUs, 0, 100);
- op.setDefaultVerifications();
- op.execute();
- SensorStats.logStats(TAG, op.getStats());
+ for (int maxBatchReportLatencyUs : maxBatchReportLatencyUss) {
+ Log.v(TAG, String.format("Run on %d with rate %d and batch %d", sensorType, rateUs,
+ maxBatchReportLatencyUs));
+ TestSensorOperation op = new TestSensorOperation(this.getContext(), sensorType,
+ rateUs, maxBatchReportLatencyUs, 1, TimeUnit.SECONDS);
+ op.setDefaultVerifications();
+ op.execute();
+ SensorStats.logStats(TAG, op.getStats());
+ }
}
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java
new file mode 100644
index 0000000..981d74c
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java
@@ -0,0 +1,95 @@
+/*
+ * 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.os.SystemClock;
+
+import java.util.concurrent.ConcurrentLinkedDeque;
+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 ConcurrentLinkedDeque<TestSensorEvent> mSensorEventsList =
+ new ConcurrentLinkedDeque<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);
+ mSensorEventsList.addLast(new TestSensorEvent(event, SystemClock.elapsedRealtimeNanos()));
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Clears the event queue before starting.
+ * </p>
+ */
+ @Override
+ public void waitForEvents(int eventCount) {
+ clearEvents();
+ super.waitForEvents(eventCount);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Clears the event queue before starting.
+ * </p>
+ */
+ @Override
+ public void waitForEvents(long duration, TimeUnit timeUnit) {
+ clearEvents();
+ super.waitForEvents(duration, timeUnit);
+ }
+
+ /**
+ * Get the {@link TestSensorEvent} array from the event queue.
+ */
+ public TestSensorEvent[] getEvents() {
+ return mSensorEventsList.toArray(new TestSensorEvent[0]);
+ }
+
+ /**
+ * Clear the event queue.
+ */
+ public void clearEvents() {
+ mSensorEventsList.clear();
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/FrameworkUnitTests.java b/tests/tests/hardware/src/android/hardware/cts/helpers/FrameworkUnitTests.java
new file mode 100644
index 0000000..872bf28
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/FrameworkUnitTests.java
@@ -0,0 +1,59 @@
+/*
+ * 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.cts.helpers.sensoroperations.SensorOperationTest;
+import android.hardware.cts.helpers.sensorverification.EventOrderingVerificationTest;
+import android.hardware.cts.helpers.sensorverification.FrequencyVerificationTest;
+import android.hardware.cts.helpers.sensorverification.JitterVerificationTest;
+import android.hardware.cts.helpers.sensorverification.MagnitudeVerificationTest;
+import android.hardware.cts.helpers.sensorverification.MeanVerificationTest;
+import android.hardware.cts.helpers.sensorverification.SigNumVerificationTest;
+import android.hardware.cts.helpers.sensorverification.StandardDeviationVerificationTest;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test suite for the CTS sensor framework.
+ */
+public class FrameworkUnitTests extends TestSuite {
+
+ public FrameworkUnitTests() {
+ super();
+
+ // helpers
+ addTestSuite(SensorCtsHelperTest.class);
+ addTestSuite(SensorStatsTest.class);
+
+ // sensorverification
+ addTestSuite(EventOrderingVerificationTest.class);
+ addTestSuite(FrequencyVerificationTest.class);
+ addTestSuite(JitterVerificationTest.class);
+ addTestSuite(MagnitudeVerificationTest.class);
+ addTestSuite(MeanVerificationTest.class);
+ addTestSuite(SigNumVerificationTest.class);
+ addTestSuite(StandardDeviationVerificationTest.class);
+
+ // sensorOperations
+ addTestSuite(SensorOperationTest.class);
+ }
+
+ public static Test suite() {
+ return new FrameworkUnitTests();
+ }
+}
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 9f281b9..65e0072 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
@@ -56,72 +56,6 @@
}
/**
- * Calculates the mean for each of the values in the set of TestSensorEvents.
- *
- * @throws IllegalArgumentException if there are no events
- */
- public static Float[] getMeans(TestSensorEvent[] events) {
- if (events.length == 0) {
- throw new IllegalArgumentException("Events cannot be empty");
- }
-
- Float[] means = new Float[events[0].values.length];
- for (int i = 0; i < means.length; i++) {
- means[i] = 0.0f;
- }
- for (TestSensorEvent event : events) {
- for (int i = 0; i < means.length; i++) {
- means[i] += event.values[i];
- }
- }
- for (int i = 0; i < means.length; i++) {
- means[i] /= events.length;
- }
- return means;
- }
-
- /**
- * Calculates the bias-corrected variance for each of the values in the set of TestSensorEvents.
- *
- * @throws IllegalArgumentException if there are no events
- */
- public static Float[] getVariances(TestSensorEvent[] events) {
- Float[] means = getMeans(events);
- Float[] variances = new Float[means.length];
- for (int i = 0; i < variances.length; i++) {
- variances[i] = 0.0f;
- }
- for (int i = 0; i < means.length; i++) {
- Collection<Float> squaredDiffs = new ArrayList<Float>(events.length);
- for (TestSensorEvent event : events) {
- float diff = event.values[i] - means[i];
- squaredDiffs.add(diff * diff);
- }
- float sum = 0.0f;
- for (float value : squaredDiffs) {
- sum += value;
- }
- variances[i] = sum / (events.length - 1);
- }
- return variances;
- }
-
- /**
- * Calculates the bias-corrected standard deviation for each of the values in the set of
- * TestSensorEvents.
- *
- * @throws IllegalArgumentException if there are no events
- */
- public static Float[] getStandardDeviations(TestSensorEvent[] events) {
- Float[] variances = getVariances(events);
- Float[] stdDevs = new Float[variances.length];
- for (int i = 0; i < variances.length; i++) {
- stdDevs[i] = (float) Math.sqrt(variances[i]);
- }
- return stdDevs;
- }
-
- /**
* Calculate the mean of a collection.
*
* @throws IllegalArgumentException if the collection is null or empty
@@ -169,41 +103,6 @@
}
/**
- * Get a list containing the delay between sensor events.
- *
- * @param events The array of {@link TestSensorEvent}.
- * @return A list containing the delay between sensor events in nanoseconds.
- */
- public static List<Long> getTimestampDelayValues(TestSensorEvent[] events) {
- if (events.length < 2) {
- return new ArrayList<Long>();
- }
- List<Long> timestampDelayValues = new ArrayList<Long>(events.length - 1);
- for (int i = 1; i < events.length; i++) {
- timestampDelayValues.add(events[i].timestamp - events[i - 1].timestamp);
- }
- return timestampDelayValues;
- }
-
- /**
- * Get a list containing the jitter values for a collection of sensor events.
- *
- * @param events The array of {@link TestSensorEvent}.
- * @return A list containing the jitter values between each event.
- * @throws IllegalArgumentException if the number of events is less that 2.
- */
- public static List<Double> getJitterValues(TestSensorEvent[] events) {
- List<Long> timestampDelayValues = getTimestampDelayValues(events);
- double averageTimestampDelay = getMean(timestampDelayValues);
-
- List<Double> jitterValues = new ArrayList<Double>(timestampDelayValues.size());
- for (long timestampDelay : timestampDelayValues) {
- jitterValues.add(Math.abs(timestampDelay - averageTimestampDelay));
- }
- return jitterValues;
- }
-
- /**
* Get the default sensor for a given type.
*/
public static Sensor getSensor(Context context, int sensorType) {
@@ -279,6 +178,16 @@
}
/**
+ * Return true if the operation rate is not one of {@link SensorManager#SENSOR_DELAY_GAME},
+ * {@link SensorManager#SENSOR_DELAY_UI}, or {@link SensorManager#SENSOR_DELAY_NORMAL}.
+ */
+ public boolean isDelayRateTestable(int rateUs) {
+ return (rateUs != SensorManager.SENSOR_DELAY_GAME
+ && rateUs != SensorManager.SENSOR_DELAY_UI
+ && rateUs != SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ /**
* Helper method to sleep for a given duration.
*/
public static void sleep(long duration, TimeUnit timeUnit) {
@@ -291,6 +200,34 @@
}
/**
+ * Format an assertion message.
+ *
+ * @param sensor the {@link Sensor}
+ * @param label the verification name
+ * @return The formatted string
+ */
+ public static String formatAssertionMessage(Sensor sensor, String label) {
+ return String.format("%s | %s, handle: %d", label,
+ SensorTestInformation.getSensorName(sensor.getType()), sensor.getHandle());
+ }
+
+ /**
+ * Format an assertion message with a custom message.
+ *
+ * @param sensor the {@link Sensor}
+ * @param label the verification name
+ * @param format the additional format string
+ * @param params the additional format params
+ * @return The formatted string
+ */
+ public static String formatAssertionMessage(Sensor sensor, String label, String format,
+ Object ... params) {
+ return String.format("%s | %s, handle: %d | %s", label,
+ SensorTestInformation.getSensorName(sensor.getType()), sensor.getHandle(),
+ String.format(format, params));
+ }
+
+ /**
* Validate that a collection is not null or empty.
*
* @throws IllegalStateException if collection is null or empty.
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelperTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelperTest.java
index b8cb06f..6f99692 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelperTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelperTest.java
@@ -53,73 +53,6 @@
}
/**
- * Test {@link SensorCtsHelper#getMeans(TestSensorEvent[])}.
- */
- public void testGetMeans() {
- long[] timestamps = {0, 1, 2, 3, 4};
-
- float[] values = {0, 1, 2, 3, 4}; // 2.0
- Float[] means = SensorCtsHelper.getMeans(getSensorEvents(timestamps, values));
- assertEquals(1, means.length);
- assertEquals(2.0, means[0], 0.00001);
-
- float[] values1 = {0, 1, 2, 3, 4}; // 2.0
- float[] values2 = {1, 2, 3, 4, 5}; // 3.0
- float[] values3 = {0, 1, 4, 9, 16}; // 6.0
- means = SensorCtsHelper.getMeans(
- getSensorEvents(timestamps, values1, values2, values3));
- assertEquals(3, means.length);
- assertEquals(2.0, means[0], 0.00001);
- assertEquals(3.0, means[1], 0.00001);
- assertEquals(6.0, means[2], 0.00001);
- }
-
- /**
- * Test {@link SensorCtsHelper#getVariances(TestSensorEvent[])}.
- */
- public void testGetVariences() {
- long[] timestamps = {0, 1, 2, 3, 4};
-
- float[] values = {0, 1, 2, 3, 4}; // 2.5
- Float[] variances = SensorCtsHelper.getVariances(getSensorEvents(timestamps, values));
- assertEquals(1, variances.length);
- assertEquals(2.5, variances[0], 0.00001);
-
- float[] values1 = {0, 1, 2, 3, 4}; // 2.5
- float[] values2 = {1, 2, 3, 4, 5}; // 2.5
- float[] values3 = {0, 2, 4, 6, 8}; // 10.0
- variances = SensorCtsHelper.getVariances(
- getSensorEvents(timestamps, values1, values2, values3));
- assertEquals(3, variances.length);
- assertEquals(2.5, variances[0], 0.00001);
- assertEquals(2.5, variances[1], 0.00001);
- assertEquals(10.0, variances[2], 0.00001);
- }
-
- /**
- * Test {@link SensorCtsHelper#getStandardDeviations(TestSensorEvent[])}.
- */
- public void testGetStandardDeviations() {
- long[] timestamps = {0, 1, 2, 3, 4};
-
- float[] values = {0, 1, 2, 3, 4}; // sqrt(2.5)
- Float[] stddev = SensorCtsHelper.getStandardDeviations(
- getSensorEvents(timestamps, values));
- assertEquals(1, stddev.length);
- assertEquals(Math.sqrt(2.5), stddev[0], 0.00001);
-
- float[] values1 = {0, 1, 2, 3, 4}; // sqrt(2.5)
- float[] values2 = {1, 2, 3, 4, 5}; // sqrt(2.5)
- float[] values3 = {0, 2, 4, 6, 8}; // sqrt(10.0)
- stddev = SensorCtsHelper.getStandardDeviations(
- getSensorEvents(timestamps, values1, values2, values3));
- assertEquals(3, stddev.length);
- assertEquals(Math.sqrt(2.5), stddev[0], 0.00001);
- assertEquals(Math.sqrt(2.5), stddev[1], 0.00001);
- assertEquals(Math.sqrt(10.0), stddev[2], 0.00001);
- }
-
- /**
* Test {@link SensorCtsHelper#getMean(Collection)}.
*/
public void testGetMean() {
@@ -171,22 +104,6 @@
}
/**
- * Test {@link SensorCtsHelper#getTimestampDelayValues(TestSensorEvent[])}.
- */
- public void testGetTimestampDelayValues() {
- float[] values = {0, 1, 2, 3, 4};
-
- long[] timestamps = {0, 0, 1, 3, 100};
- List<Long> timestampDelayValues = SensorCtsHelper.getTimestampDelayValues(
- getSensorEvents(timestamps, values));
- assertEquals(4, timestampDelayValues.size());
- assertEquals(0, (long) timestampDelayValues.get(0));
- assertEquals(1, (long) timestampDelayValues.get(1));
- assertEquals(2, (long) timestampDelayValues.get(2));
- assertEquals(97, (long) timestampDelayValues.get(3));
- }
-
- /**
* Test {@link SensorCtsHelper#getFrequency(Number, TimeUnit)}.
*/
public void testGetFrequency() {
@@ -217,50 +134,4 @@
assertEquals(100, SensorCtsHelper.getPeriod(10000000, TimeUnit.NANOSECONDS), 0.001);
assertEquals(1, SensorCtsHelper.getPeriod(1000000000, TimeUnit.NANOSECONDS), 0.001);
}
-
- /**
- * Test {@link SensorCtsHelper#getJitterValues(TestSensorEvent[])}.
- */
- public void testGetJitterValues() {
- float[] values = {0, 1, 2, 3, 4};
-
- long[] timestamps1 = {0, 1, 2, 3, 4};
- List<Double> jitterValues = SensorCtsHelper.getJitterValues(
- getSensorEvents(timestamps1, values));
- assertEquals(4, jitterValues.size());
- assertEquals(0.0, (double) jitterValues.get(0));
- assertEquals(0.0, (double) jitterValues.get(1));
- assertEquals(0.0, (double) jitterValues.get(2));
- assertEquals(0.0, (double) jitterValues.get(3));
-
- long[] timestamps2 = {0, 0, 2, 4, 4};
- jitterValues = SensorCtsHelper.getJitterValues(
- getSensorEvents(timestamps2, values));
- assertEquals(4, jitterValues.size());
- assertEquals(1.0, (double) jitterValues.get(0));
- assertEquals(1.0, (double) jitterValues.get(1));
- assertEquals(1.0, (double) jitterValues.get(2));
- assertEquals(1.0, (double) jitterValues.get(3));
-
- long[] timestamps3 = {0, 1, 4, 9, 16};
- jitterValues = SensorCtsHelper.getJitterValues(
- getSensorEvents(timestamps3, values));
- assertEquals(4, jitterValues.size());
- assertEquals(3.0, (double) jitterValues.get(0));
- assertEquals(1.0, (double) jitterValues.get(1));
- assertEquals(1.0, (double) jitterValues.get(2));
- assertEquals(3.0, (double) jitterValues.get(3));
- }
-
- private TestSensorEvent[] getSensorEvents(long[] timestamps, float[] ... values) {
- TestSensorEvent[] events = new TestSensorEvent[timestamps.length];
- for (int i = 0; i < timestamps.length; i++) {
- float[] eventValues = new float[values.length];
- for (int j = 0; j < values.length; j++) {
- eventValues[j] = values[j][i];
- }
- events[i] = new TestSensorEvent(null, timestamps[i], 0, eventValues);
- }
- return events;
- }
}
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 48f8136..1898570 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
@@ -20,11 +20,13 @@
import android.util.Log;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
/**
* Class used to store stats related to {@link ISensorOperation}s. Sensor stats may be linked
@@ -33,6 +35,17 @@
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 EVENT_COUNT_KEY = "event_count";
+ 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 FREQUENCY_KEY = "frequency";
+ public static final String JITTER_95_PERCENTILE_KEY = "jitter_95_percentile";
+ 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>();
@@ -64,6 +77,22 @@
}
/**
+ * Get the keys from the values table. Will not get the keys from the nested
+ * {@link SensorStats}.
+ */
+ public synchronized Set<String> getKeys() {
+ return mValues.keySet();
+ }
+
+ /**
+ * Get a value from the values table. Will not attempt to get values from nested
+ * {@link SensorStats}.
+ */
+ public synchronized Object getValue(String key) {
+ return mValues.get(key);
+ }
+
+ /**
* 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
@@ -91,11 +120,31 @@
Collections.sort(keys);
for (String key : keys) {
Object value = flattened.get(key);
- if (value instanceof Double || value instanceof Float) {
- Log.v(tag, String.format("%s: %.4f", key, value));
+ if (value instanceof boolean[]) {
+ logStat(tag, key, Arrays.toString((boolean[]) value));
+ } else if (value instanceof byte[]) {
+ logStat(tag, key, Arrays.toString((byte[]) value));
+ } else if (value instanceof char[]) {
+ logStat(tag, key, Arrays.toString((char[]) value));
+ } else if (value instanceof double[]) {
+ logStat(tag, key, Arrays.toString((double[]) value));
+ } else if (value instanceof float[]) {
+ logStat(tag, key, Arrays.toString((float[]) value));
+ } else if (value instanceof int[]) {
+ logStat(tag, key, Arrays.toString((int[]) value));
+ } else if (value instanceof long[]) {
+ logStat(tag, key, Arrays.toString((long[]) value));
+ } else if (value instanceof short[]) {
+ logStat(tag, key, Arrays.toString((short[]) value));
+ } else if (value instanceof Object[]) {
+ logStat(tag, key, Arrays.toString((Object[]) value));
} else {
- Log.v(tag, String.format("%s: %s", key, value.toString()));
+ logStat(tag, key, value.toString());
}
}
}
+
+ private static void logStat(String tag, String key, String value) {
+ Log.v(tag, String.format("%s: %s", key, value));
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelper.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelper.java
deleted file mode 100644
index 76e243f..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelper.java
+++ /dev/null
@@ -1,369 +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 java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Set of static helper methods to verify sensor CTS tests.
- */
-public class SensorVerificationHelper {
-
- public static final String EVENT_ORDER_COUNT_KEY = "event_order_count";
- public static final String EVENT_ORDER_POSITIONS_KEY = "event_order_positions";
- public static final String FREQUENCY_KEY = "frequency";
- public static final String JITTER_95_PERCENTILE_KEY = "jitter_95_percentile";
- public static final String MEAN_KEY = "mean";
- public static final String MAGNITUDE_KEY = "magnitude";
- public static final String STANDARD_DEVIATION_KEY = "standard_deviation";
-
- private static final int MESSAGE_LENGTH = 3;
-
- /**
- * Class which holds results from the verification.
- */
- public static class VerificationResult {
- private boolean mFailed = false;
- private String mMessage = null;
- private Map<String, Object> mValueMap = new HashMap<String, Object>();
-
- public void fail(String messageFormat, Object ... args) {
- mFailed = true;
- mMessage = String.format(messageFormat, args);
- }
-
- public boolean isFailed() {
- return mFailed;
- }
-
- public String getFailureMessage() {
- return mMessage;
- }
-
- public void putValue(String key, Object value) {
- mValueMap.put(key, value);
- }
-
- public Set<String> getKeys() {
- return mValueMap.keySet();
- }
-
- public Object getValue(String key) {
- return mValueMap.get(key);
- }
- }
-
- /**
- * Private constructor for static class.
- */
- private SensorVerificationHelper() {}
-
- /**
- * Verify that the events are in the correct order.
- *
- * @param events The array of {@link TestSensorEvent}
- * @return a {@link VerificationResult} containing the verification info including the keys
- * "count" which is the number of events out of order and "positions" which contains an
- * array of indexes that were out of order.
- * @throws IllegalStateException if number of events less than 1.
- */
- public static VerificationResult verifyEventOrdering(TestSensorEvent[] events) {
- VerificationResult result = new VerificationResult();
- List<Integer> indices = new ArrayList<Integer>();
- long maxTimestamp = events[0].timestamp;
- for (int i = 1; i < events.length; i++) {
- long currentTimestamp = events[i].timestamp;
- if (currentTimestamp < maxTimestamp) {
- indices.add(i);
- } else if (currentTimestamp > maxTimestamp) {
- maxTimestamp = currentTimestamp;
- }
- }
-
- result.putValue(EVENT_ORDER_COUNT_KEY, indices.size());
- result.putValue(EVENT_ORDER_POSITIONS_KEY, indices);
-
- if (indices.size() > 0) {
- StringBuilder sb = new StringBuilder();
- sb.append(indices.size()).append(" events out of order: ");
- for (int i = 0; i < Math.min(indices.size(), MESSAGE_LENGTH); i++) {
- int index = indices.get(i);
- sb.append(String.format("position=%d, previous=%d, timestamp=%d; ", index,
- events[index - 1].timestamp, events[index].timestamp));
- }
- if (indices.size() > MESSAGE_LENGTH) {
- sb.append(indices.size() - MESSAGE_LENGTH).append(" more");
- } else {
- // Delete the "; "
- sb.delete(sb.length() - 2, sb.length());
- }
-
- result.fail(sb.toString());
- }
-
- return result;
- }
-
- /**
- * Verify that the sensor frequency matches the expected frequency.
- *
- * @param events The array of {@link TestSensorEvent}
- * @param expected The expected frequency in Hz
- * @param lowerThreshold The acceptable margin of error in Hz for the lower bound
- * @param upperThreshold The acceptable margin of error in Hz for the upper bound
- * @return a {@link VerificationResult} containing the verification info including the key
- * "frequency" which is the computed frequency of the events in Hz.
- * @throws IllegalStateException if number of events less than 1.
- */
- public static VerificationResult verifyFrequency(TestSensorEvent[] events, double expected,
- double lowerThreshold, double upperThreshold) {
- VerificationResult result = new VerificationResult();
- List<Long> timestampDelayValues = SensorCtsHelper.getTimestampDelayValues(events);
- double frequency = SensorCtsHelper.getFrequency(
- SensorCtsHelper.getMean(timestampDelayValues), TimeUnit.NANOSECONDS);
- result.putValue(FREQUENCY_KEY, frequency);
-
- if (frequency <= expected - lowerThreshold || frequency >= expected + upperThreshold) {
- result.fail("Frequency out of range: frequency=%.2fHz, "
- + "expected=(%.2f-%.2fHz, %.2f+.%2f)", frequency, expected, lowerThreshold,
- expected, upperThreshold);
- }
- return result;
- }
-
- /**
- * Verify that the jitter is in an acceptable range
- *
- * @param events The array of {@link TestSensorEvent}
- * @param expected the expected period in ns
- * @param threshold The acceptable margin of error as a percentage
- * @return a {@link VerificationResult} containing the verification info including the keys
- * "jitter" which is the list of computed jitter values and "jitter95Percentile" which is
- * 95th percentile of the jitter values.
- * @throws IllegalStateException if number of events less than 2.
- */
- public static VerificationResult verifyJitter(TestSensorEvent[] events, int expected,
- int threshold) {
- VerificationResult result = new VerificationResult();
- List<Double> jitterValues = SensorCtsHelper.getJitterValues(events);
- double jitter95Percentile = SensorCtsHelper.get95PercentileValue(jitterValues);
- result.putValue(JITTER_95_PERCENTILE_KEY, jitter95Percentile);
-
- if (jitter95Percentile > expected * (threshold / 100.0)) {
- result.fail("Jitter out of range: jitter at 95th percentile=%.0fns, expected=<%.0fns",
- jitter95Percentile, expected * (threshold / 100.0));
- }
- return result;
- }
-
- /**
- * Verify that the means matches the expected measurement.
- *
- * @param events The array of {@link TestSensorEvent}
- * @param expected The array of expected values
- * @param threshold The array of thresholds
- * @return a {@link VerificationResult} containing the verification info including the key
- * "mean" which is the computed means for each value of the sensor.
- * @throws IllegalStateException if number of events less than 1.
- */
- public static VerificationResult verifyMean(TestSensorEvent[] events, float[] expected,
- float[] threshold) {
- VerificationResult result = new VerificationResult();
- Float[] means = SensorCtsHelper.getMeans(events);
- result.putValue(MEAN_KEY, Arrays.asList(means));
-
- boolean failed = false;
- StringBuilder meanSb = new StringBuilder();
- StringBuilder expectedSb = new StringBuilder();
-
- if (means.length > 1) {
- meanSb.append("(");
- expectedSb.append("(");
- }
- for (int i = 0; i < means.length; i++) {
- if (Math.abs(means[i] - expected[i]) > threshold[i]) {
- failed = true;
- }
- meanSb.append(String.format("%.2f", means[i]));
- if (i != means.length - 1) meanSb.append(", ");
- expectedSb.append(String.format("%.2f+/-%.2f", expected[i], threshold[i]));
- if (i != means.length - 1) expectedSb.append(", ");
- }
- if (means.length > 1) {
- meanSb.append(")");
- expectedSb.append(")");
- }
-
- if (failed) {
- result.fail("Mean out of range: mean=%s, expected=%s",
- meanSb.toString(), expectedSb.toString());
- }
- return result;
- }
-
- /**
- * Verify that the mean of the magnitude of the sensors vector is within the expected range.
- *
- * @param events The array of {@link TestSensorEvent}
- * @param expected The expected value
- * @param threshold The threshold
- * @return a {@link VerificationResult} containing the verification info including the key
- * "magnitude" which is the mean of the computed magnitude of the sensor values.
- * @throws IllegalStateException if number of events less than 1.
- */
- public static VerificationResult verifyMagnitude(TestSensorEvent[] events, float expected,
- float threshold) {
- VerificationResult result = new VerificationResult();
- Collection<Float> magnitudes = new ArrayList<Float>(events.length);
-
- for (TestSensorEvent event : events) {
- float sumOfSquares = 0;
- for (int i = 0; i < event.values.length; i++) {
- sumOfSquares += event.values[i] * event.values[i];
- }
- magnitudes.add((float) Math.sqrt(sumOfSquares));
- }
-
- float mean = (float) SensorCtsHelper.getMean(magnitudes);
- result.putValue(MAGNITUDE_KEY, mean);
-
- if (Math.abs(mean - expected) > threshold) {
- result.fail(String.format("Magnitude mean out of range: mean=%s, expected=%s+/-%s",
- mean, expected, threshold));
- }
- return result;
- }
-
- /**
- * Verify that the sign of each of the sensor values is correct.
- * <p>
- * If the value of the measurement is in [-threshold, threshold], the sign is considered 0. If
- * it is less than -threshold, it is considered -1. If it is greater than threshold, it is
- * considered 1.
- * </p>
- *
- * @param events
- * @param threshold The threshold that needs to be crossed to consider a measurement nonzero
- * @return a {@link VerificationResult} containing the verification info including the key
- * "mean" which is the computed means for each value of the sensor.
- * @throws IllegalStateException if number of events less than 1.
- */
- public static VerificationResult verifySignum(TestSensorEvent[] events, int[] expected,
- float[] threshold) {
- VerificationResult result = new VerificationResult();
- for (int i = 0; i < expected.length; i++) {
- if (!(expected[i] == -1 || expected[i] == 0 || expected[i] == 1)) {
- throw new IllegalArgumentException("Expected value must be -1, 0, or 1");
- }
- }
- Float[] means = SensorCtsHelper.getMeans(events);
- result.putValue(MEAN_KEY, Arrays.asList(means));
-
- boolean failed = false;
- StringBuilder meanSb = new StringBuilder();
- StringBuilder expectedSb = new StringBuilder();
-
- if (means.length > 1) {
- meanSb.append("(");
- expectedSb.append("(");
- }
- for (int i = 0; i < means.length; i++) {
- meanSb.append(String.format("%.2f", means[i]));
- if (i != means.length - 1) meanSb.append(", ");
-
- if (expected[i] == 0) {
- if (Math.abs(means[i]) > threshold[i]) {
- failed = true;
- }
- expectedSb.append(String.format("[%.2f, %.2f]", -threshold[i], threshold[i]));
- } else {
- if (expected[i] > 0) {
- if (means[i] <= threshold[i]) {
- failed = true;
- }
- expectedSb.append(String.format("(%.2f, inf)", threshold[i]));
- } else {
- if (means[i] >= -1 * threshold[i]) {
- failed = true;
- }
- expectedSb.append(String.format("(-inf, %.2f)", -1 * threshold[i]));
- }
- }
- if (i != means.length - 1) expectedSb.append(", ");
- }
- if (means.length > 1) {
- meanSb.append(")");
- expectedSb.append(")");
- }
-
- if (failed) {
- result.fail("Signum out of range: mean=%s, expected=%s",
- meanSb.toString(), expectedSb.toString());
- }
- return result;
- }
-
- /**
- * Verify that the standard deviations is within the expected range.
- *
- * @param events The array of {@link TestSensorEvent}
- * @param threshold The array of thresholds
- * @return a {@link VerificationResult} containing the verification info including the key
- * "stddevs" which is the computed standard deviations for each value of the sensor.
- * @throws IllegalStateException if number of events less than 1.
- */
- public static VerificationResult verifyStandardDeviation(TestSensorEvent[] events,
- float[] threshold) {
- VerificationResult result = new VerificationResult();
- Float[] standardDeviations = SensorCtsHelper.getStandardDeviations(events);
- result.putValue(STANDARD_DEVIATION_KEY, Arrays.asList(standardDeviations));
-
- boolean failed = false;
- StringBuilder stddevSb = new StringBuilder();
- StringBuilder expectedSb = new StringBuilder();
-
- if (standardDeviations.length > 1) {
- stddevSb.append("(");
- expectedSb.append("(");
- }
- for (int i = 0; i < standardDeviations.length; i++) {
- if (standardDeviations[i] > threshold[i]) {
- failed = true;
- }
- stddevSb.append(String.format("%.2f", standardDeviations[i]));
- if (i != standardDeviations.length - 1) stddevSb.append(", ");
- expectedSb.append(String.format("<%.2f", threshold[i]));
- if (i != standardDeviations.length - 1) expectedSb.append(", ");
- }
- if (standardDeviations.length > 1) {
- stddevSb.append(")");
- expectedSb.append(")");
- }
-
- if (failed) {
- result.fail("Standard deviation out of range: stddev=%s, expected=%s",
- stddevSb.toString(), expectedSb.toString());
- }
- return result;
- }
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelperTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelperTest.java
deleted file mode 100644
index fd3c03c..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelperTest.java
+++ /dev/null
@@ -1,296 +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.cts.helpers.SensorVerificationHelper.VerificationResult;
-
-import junit.framework.TestCase;
-
-import java.util.List;
-
-/**
- * Unit tests for the {@link SensorVerificationHelper} class.
- */
-public class SensorVerificationHelperTest extends TestCase {
-
- /**
- * Test {@link SensorVerificationHelper#verifyEventOrdering(TestSensorEvent[])}.
- */
- @SuppressWarnings("unchecked")
- public void testVerifyEventOrdering() {
- float[] values = {0, 1, 2, 3, 4};
-
- long[] timestamps1 = {0, 0, 0, 0, 0};
- TestSensorEvent[] events1 = getSensorEvents(timestamps1, values);
- VerificationResult result = SensorVerificationHelper.verifyEventOrdering(events1);
- assertFalse(result.isFailed());
- assertEquals(0, result.getValue(SensorVerificationHelper.EVENT_ORDER_COUNT_KEY));
-
- long[] timestamps2 = {0, 1, 2, 3, 4};
- TestSensorEvent[] events2 = getSensorEvents(timestamps2, values);
- result = SensorVerificationHelper.verifyEventOrdering(events2);
- assertFalse(result.isFailed());
- assertEquals(0, result.getValue(SensorVerificationHelper.EVENT_ORDER_COUNT_KEY));
-
- long[] timestamps3 = {0, 2, 1, 3, 4};
- TestSensorEvent[] events3 = getSensorEvents(timestamps3, values);
- result = SensorVerificationHelper.verifyEventOrdering(events3);
- assertTrue(result.isFailed());
- assertEquals(1, result.getValue(SensorVerificationHelper.EVENT_ORDER_COUNT_KEY));
- List<Integer> indices = (List<Integer>) result.getValue(
- SensorVerificationHelper.EVENT_ORDER_POSITIONS_KEY);
- assertTrue(indices.contains(2));
-
- long[] timestamps4 = {4, 0, 1, 2, 3};
- TestSensorEvent[] events4 = getSensorEvents(timestamps4, values);
- result = SensorVerificationHelper.verifyEventOrdering(events4);
- assertTrue(result.isFailed());
- assertEquals(4, result.getValue(SensorVerificationHelper.EVENT_ORDER_COUNT_KEY));
- indices = (List<Integer>) result.getValue(
- SensorVerificationHelper.EVENT_ORDER_POSITIONS_KEY);
- assertTrue(indices.contains(1));
- assertTrue(indices.contains(2));
- assertTrue(indices.contains(3));
- assertTrue(indices.contains(4));
- }
-
- /**
- * Test
- * {@link SensorVerificationHelper#verifyFrequency(TestSensorEvent[], double, double, double)}.
- */
- public void testVerifyFrequency() {
- float[] values = {0, 1, 2, 3, 4};
- long[] timestamps = {0, 1000000, 2000000, 3000000, 4000000}; // 1000Hz
- TestSensorEvent[] events = getSensorEvents(timestamps, values);
-
- VerificationResult result = SensorVerificationHelper.verifyFrequency(events, 1000.0, 1.0,
- 1.0);
- assertFalse(result.isFailed());
- assertEquals(1000.0, (Double) result.getValue("frequency"), 0.01);
-
- result = SensorVerificationHelper.verifyFrequency(events, 950.0, 100.0, 100.0);
- assertFalse(result.isFailed());
- assertEquals(1000.0, (Double) result.getValue("frequency"), 0.01);
-
- result = SensorVerificationHelper.verifyFrequency(events, 1050.0, 100.0, 100.0);
- assertFalse(result.isFailed());
- assertEquals(1000.0, (Double) result.getValue("frequency"), 0.01);
-
- result = SensorVerificationHelper.verifyFrequency(events, 950.0, 100.0, 25.0);
- assertTrue(result.isFailed());
- assertEquals(1000.0, (Double) result.getValue("frequency"), 0.01);
-
- result = SensorVerificationHelper.verifyFrequency(events, 1050.0, 25.0, 100.0);
- assertTrue(result.isFailed());
- assertEquals(1000.0, (Double) result.getValue("frequency"), 0.01);
- }
-
- /**
- * Test {@link SensorVerificationHelper#verifyJitter(TestSensorEvent[], int, int)}.
- */
- public void testVerifyJitter() {
- final int SAMPLE_SIZE = 100;
- float[] values = new float[SAMPLE_SIZE];
- for (int i = 0; i < SAMPLE_SIZE; i++) {
- values[i] = i;
- }
-
- long[] timestamps1 = new long[SAMPLE_SIZE]; // 100 samples at 1000Hz
- for (int i = 0; i < SAMPLE_SIZE; i++) {
- timestamps1[i] = i * 100000;
- }
- TestSensorEvent[] events1 = getSensorEvents(timestamps1, values);
- VerificationResult result = SensorVerificationHelper.verifyJitter(events1, 1000, 10);
- assertFalse(result.isFailed());
- Double jitter95 = (Double) result.getValue(
- SensorVerificationHelper.JITTER_95_PERCENTILE_KEY);
- assertEquals(0.0, jitter95, 0.01);
-
- long[] timestamps2 = new long[SAMPLE_SIZE]; // 90 samples at 1000Hz, 10 samples at 2000Hz
- long timestamp = 0;
- for (int i = 0; i < SAMPLE_SIZE; i++) {
- timestamps2[i] = timestamp;
- timestamp += (i % 10 == 0) ? 500000 : 1000000;
- }
- TestSensorEvent[] events2 = getSensorEvents(timestamps2, values);
- result = SensorVerificationHelper.verifyJitter(events2, 1000, 10);
- assertTrue(result.isFailed());
- assertNotNull(result.getValue(SensorVerificationHelper.JITTER_95_PERCENTILE_KEY));
- }
-
- /**
- * Test {@link SensorVerificationHelper#verifyMean(TestSensorEvent[], float[], float[])}.
- */
- public void testVerifyMean() {
- long[] timestamps = {0, 1, 2, 3, 4};
- float[] values1 = {0, 1, 2, 3, 4};
- float[] values2 = {1, 2, 3, 4, 5};
- float[] values3 = {0, 1, 4, 9, 16};
- TestSensorEvent[] events = getSensorEvents(timestamps, values1, values2, values3);
-
- float[] expected1 = {2.0f, 3.0f, 6.0f};
- float[] threshold1 = {0.1f, 0.1f, 0.1f};
- VerificationResult result = SensorVerificationHelper.verifyMean(events, expected1,
- threshold1);
- assertFalse(result.isFailed());
- @SuppressWarnings("unchecked")
- List<Float> means = (List<Float>) result.getValue(SensorVerificationHelper.MEAN_KEY);
- assertEquals(2.0f, means.get(0), 0.01);
- assertEquals(3.0f, means.get(1), 0.01);
- assertEquals(6.0f, means.get(2), 0.01);
-
- float[] expected = {2.5f, 2.5f, 5.5f};
- float[] threshold = {0.6f, 0.6f, 0.6f};
- result = SensorVerificationHelper.verifyMean(events, expected, threshold);
- assertFalse(result.isFailed());
-
- expected = new float[]{2.5f, 2.5f, 5.5f};
- threshold = new float[]{0.1f, 0.6f, 0.6f};
- result = SensorVerificationHelper.verifyMean(events, expected, threshold);
- assertTrue(result.isFailed());
-
- expected = new float[]{2.5f, 2.5f, 5.5f};
- threshold = new float[]{0.6f, 0.1f, 0.6f};
- result = SensorVerificationHelper.verifyMean(events, expected, threshold);
- assertTrue(result.isFailed());
-
- threshold = new float[]{2.5f, 2.5f, 5.5f};
- threshold = new float[]{0.6f, 0.6f, 0.1f};
- result = SensorVerificationHelper.verifyMean(events, expected, threshold);
- assertTrue(result.isFailed());
- }
-
- /**
- * Test {@link SensorVerificationHelper#verifyMagnitude(TestSensorEvent[], float, float)}.
- */
- public void testVerifyMagnitude() {
- long[] timestamps = {0, 1, 2, 3, 4};
- float[] values1 = {0, 4, 3, 0, 6};
- float[] values2 = {3, 0, 4, 0, 0};
- float[] values3 = {4, 3, 0, 4, 0};
- TestSensorEvent[] events = getSensorEvents(timestamps, values1, values2, values3);
-
- float expected = 5.0f;
- float threshold = 0.1f;
- VerificationResult result = SensorVerificationHelper.verifyMagnitude(events, expected,
- threshold);
- assertFalse(result.isFailed());
- assertEquals(5.0f, (Float) result.getValue(SensorVerificationHelper.MAGNITUDE_KEY), 0.01);
-
- expected = 4.5f;
- threshold = 0.6f;
- result = SensorVerificationHelper.verifyMagnitude(events, expected, threshold);
- assertFalse(result.isFailed());
-
- expected = 5.5f;
- threshold = 0.6f;
- result = SensorVerificationHelper.verifyMagnitude(events, expected, threshold);
- assertFalse(result.isFailed());
-
- expected = 4.5f;
- threshold = 0.1f;
- result = SensorVerificationHelper.verifyMagnitude(events, expected, threshold);
- assertTrue(result.isFailed());
-
- expected = 5.5f;
- threshold = 0.1f;
- result = SensorVerificationHelper.verifyMagnitude(events, expected, threshold);
- assertTrue(result.isFailed());
- }
-
- /**
- * Test {@link SensorVerificationHelper#verifySignum(TestSensorEvent[], int[], float[])}.
- */
- public void testVerifySignum() {
- long[] timestamps = {0};
- float[][] values = {{1}, {0.2f}, {0}, {-0.2f}, {-1}};
- TestSensorEvent[] events = getSensorEvents(timestamps, values);
-
- int[] expected = {1, 1, 0, -1, -1};
- float[] threshold = {0.1f, 0.1f, 0.1f, 0.1f, 0.1f};
- VerificationResult result = SensorVerificationHelper.verifySignum(events, expected,
- threshold);
- assertFalse(result.isFailed());
- assertNotNull(result.getValue(SensorVerificationHelper.MEAN_KEY));
-
- expected = new int[]{1, 0, 0, 0, -1};
- threshold = new float[]{0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
- result = SensorVerificationHelper.verifySignum(events, expected, threshold);
- assertFalse(result.isFailed());
-
- expected = new int[]{0, 1, 0, -1, 0};
- threshold = new float[]{1.5f, 0.1f, 0.1f, 0.1f, 1.5f};
- result = SensorVerificationHelper.verifySignum(events, expected, threshold);
- assertFalse(result.isFailed());
-
- expected = new int[]{1, 0, 0, 0, 1};
- threshold = new float[]{0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
- result = SensorVerificationHelper.verifySignum(events, expected, threshold);
- assertTrue(result.isFailed());
-
- expected = new int[]{-1, 0, 0, 0, -1};
- threshold = new float[]{0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
- result = SensorVerificationHelper.verifySignum(events, expected, threshold);
- assertTrue(result.isFailed());
- }
-
- /**
- * Test {@link SensorVerificationHelper#verifyStandardDeviation(TestSensorEvent[], float[])}.
- */
- public void testVerifyStandardDeviation() {
- long[] timestamps = {0, 1, 2, 3, 4};
- float[] values1 = {0, 1, 2, 3, 4}; // sqrt(2.5)
- float[] values2 = {1, 2, 3, 4, 5}; // sqrt(2.5)
- float[] values3 = {0, 2, 4, 6, 8}; // sqrt(10.0)
- TestSensorEvent[] events = getSensorEvents(timestamps, values1, values2, values3);
-
- float[] threshold = {2, 2, 4};
- VerificationResult result = SensorVerificationHelper.verifyStandardDeviation(events,
- threshold);
- assertFalse(result.isFailed());
- @SuppressWarnings("unchecked")
- List<Float> stddevs = (List<Float>) result.getValue(
- SensorVerificationHelper.STANDARD_DEVIATION_KEY);
- assertEquals(Math.sqrt(2.5), stddevs.get(0), 0.01);
- assertEquals(Math.sqrt(2.5), stddevs.get(1), 0.01);
- assertEquals(Math.sqrt(10.0), stddevs.get(2), 0.01);
-
- threshold = new float[]{1, 2, 4};
- result = SensorVerificationHelper.verifyStandardDeviation(events, threshold);
- assertTrue(result.isFailed());
-
- threshold = new float[]{2, 1, 4};
- result = SensorVerificationHelper.verifyStandardDeviation(events, threshold);
- assertTrue(result.isFailed());
-
- threshold = new float[]{2, 2, 3};
- result = SensorVerificationHelper.verifyStandardDeviation(events, threshold);
- assertTrue(result.isFailed());
- }
-
- private TestSensorEvent[] getSensorEvents(long[] timestamps, float[] ... values) {
- TestSensorEvent[] events = new TestSensorEvent[timestamps.length];
- for (int i = 0; i < timestamps.length; i++) {
- float[] eventValues = new float[values.length];
- for (int j = 0; j < values.length; j++) {
- eventValues[j] = values[j][i];
- }
- events[i] = new TestSensorEvent(null, timestamps[i], 0, eventValues);
- }
- return events;
- }
-}
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 c22ad8e..b349e1b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
@@ -51,14 +51,14 @@
/**
* Constructor for TestSensorEvent. Exposed for unit testing.
*/
- TestSensorEvent(Sensor sensor, long timestamp, int accuracy, float[] values) {
+ public TestSensorEvent(Sensor sensor, long timestamp, int accuracy, float[] values) {
this(sensor, timestamp, timestamp, accuracy, values);
}
/**
* Constructor for TestSensorEvent. Exposed for unit testing.
*/
- TestSensorEvent(Sensor sensor, long timestamp, long receivedTimestamp, int accuracy,
+ public TestSensorEvent(Sensor sensor, long timestamp, long receivedTimestamp, int accuracy,
float[] values) {
this.sensor = sensor;
this.timestamp = timestamp;
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
new file mode 100644
index 0000000..2d13ce9
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -0,0 +1,174 @@
+/*
+ * 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.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener2;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link SensorEventListener2} which performs operations such as waiting for a specific number of
+ * events or for a specific time, or waiting for a flush to complete. This class performs
+ * verifications and will throw {@link AssertionError}s if there are any errors. It may also wrap
+ * another {@link SensorEventListener2}.
+ */
+public class TestSensorEventListener implements SensorEventListener2 {
+ public static final String LOG_TAG = "TestSensorEventListener";
+ public static final boolean DEBUG = true;
+ 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 volatile CountDownLatch mEventLatch = null;
+ private volatile CountDownLatch mFlushLatch = new CountDownLatch(1);
+
+ private Sensor mSensor = null;
+ private int mRateUs = 0;
+ private int mMaxBatchReportLatencyUs = 0;
+
+ /**
+ * Construct a {@link TestSensorEventListener}.
+ */
+ public TestSensorEventListener() {
+ this(null);
+ }
+
+ /**
+ * Construct a {@link TestSensorEventListener} that wraps a {@link SensorEventListener2}.
+ */
+ public TestSensorEventListener(SensorEventListener2 listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Set the sensor, rate, and batch report latency used for the assertions.
+ */
+ public void setSensorInfo(Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
+ mSensor = sensor;
+ mRateUs = rateUs;
+ mMaxBatchReportLatencyUs = maxBatchReportLatencyUs;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if(mEventLatch != null) {
+ mEventLatch.countDown();
+ }
+ if (mListener != null) {
+ mListener.onSensorChanged(event);
+ }
+ if (DEBUG) {
+ StringBuilder valuesSb = new StringBuilder();
+ if (event.values.length == 1) {
+ valuesSb.append(String.format("%.2f", event.values[0]));
+ } else {
+ valuesSb.append("[").append(String.format("%.2f", event.values[0]));
+ for (int i = 1; i < event.values.length; i++) {
+ valuesSb.append(String.format(", %.2f", event.values[i]));
+ }
+ valuesSb.append("]");
+ }
+
+ Log.v(LOG_TAG, String.format(
+ "Sensor %d: device_timestamp=%d, values=%s",
+ mSensor.getType(), event.timestamp, Arrays.toString(event.values)));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ if (mListener != null) {
+ mListener.onAccuracyChanged(sensor, accuracy);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onFlushCompleted(Sensor sensor) {
+ CountDownLatch latch = mFlushLatch;
+ mFlushLatch = new CountDownLatch(1);
+ if(latch != null) {
+ latch.countDown();
+ }
+ if (mListener != null) {
+ mListener.onFlushCompleted(sensor);
+ }
+ }
+
+ /**
+ * Wait for {@link #onFlushCompleted(Sensor)} to be called.
+ *
+ * @throws AssertionError if there was a timeout after {@value #FLUSH_TIMEOUT_US} µs
+ */
+ public void waitForFlushComplete() {
+ CountDownLatch latch = mFlushLatch;
+ try {
+ if(latch != null) {
+ String message = SensorCtsHelper.formatAssertionMessage(mSensor, "WaitForFlush");
+ Assert.assertTrue(message, latch.await(FLUSH_TIMEOUT_US, TimeUnit.MICROSECONDS));
+ }
+ } catch(InterruptedException e) {
+ // Ignore
+ }
+ }
+
+ /**
+ * Collect a specific number of {@link TestSensorEvent}s.
+ *
+ * @throws AssertionError if there was a timeout after {@value #FLUSH_TIMEOUT_US} µs
+ */
+ public void waitForEvents(int eventCount) {
+ mEventLatch = new CountDownLatch(eventCount);
+ try {
+ int rateUs = SensorCtsHelper.getDelay(mSensor, mRateUs);
+ // Timeout is 2 * event count * expected period + batch timeout + default wait
+ long timeoutUs = ((2 * eventCount * rateUs)
+ + mMaxBatchReportLatencyUs + EVENT_TIMEOUT_US);
+
+ String message = SensorCtsHelper.formatAssertionMessage(mSensor, "WaitForEvents",
+ "count:%d, available:%d", eventCount, mEventLatch.getCount());
+ Assert.assertTrue(message, mEventLatch.await(timeoutUs, TimeUnit.MICROSECONDS));
+ } catch(InterruptedException e) {
+ // Ignore
+ } finally {
+ mEventLatch = null;
+ }
+ }
+
+ /**
+ * Collect {@link TestSensorEvent} for a specific duration.
+ */
+ public void waitForEvents(long duration, TimeUnit timeUnit) {
+ SensorCtsHelper.sleep(duration, timeUnit);
+ }
+}
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 eb5c300..32bd3c9 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -18,7 +18,6 @@
import android.content.Context;
import android.hardware.Sensor;
-import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorEventListener2;
import android.hardware.SensorManager;
@@ -26,8 +25,6 @@
import junit.framework.Assert;
-import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
@@ -36,61 +33,41 @@
* operations such as flushing the sensor events and gathering events. This class also manages
* performing the test verifications for the sensor manager.
* <p>
- * The class makes use of an internal {@link SensorEventListener2} in order to gather events and
- * check to make sure that flushes completed. An additionaly {@link SensorEventListener2} may be
- * provided in order to perform more complex tests.
- * </p><p>
* This class requires that operations are performed in the following order:
* <p><ul>
- * <li>{@link #registerListener()}</li>
- * <li>{@link #getEvents()}, {@link #getEvents(int)}, {@link #getEvents(long, TimeUnit)},
- * {@link #clearEvents()}, {@link #startFlush()}, {@link #waitForFlushCompleted()}, or {@link #flush()}.
+ * <li>{@link #registerListener(TestSensorEventListener)}</li>
+ * <li>{@link #startFlush()}, {@link #waitForFlushCompleted()}, or {@link #flush()}.
* <li>{@link #unregisterListener()}</li>
* </ul><p>Or:</p><ul>
- * <li>{@link #collectEvents(int)}</li>
+ * <li>{@link #runSensor(TestSensorEventListener, int)}</li>
* </ul><p>Or:</p><ul>
- * <li>{@link #collectEvents(long, TimeUnit)}</li>
+ * <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 #collectEvents(int)} and {@link #collectEvents(long, TimeUnit)} will perform
- * the appropriate clean up and tear down.
+ * return. Both {@link #runSensor(TestSensorEventListener, int)}} and
+ * {@link #runSensor(TestSensorEventListener, long, TimeUnit)} will perform the appropriate
+ * set up and tear down.
* <p>
*/
public class TestSensorManager {
private static final String LOG_TAG = "TestSensorManager";
- 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 SensorManager mSensorManager;
private final Sensor mSensor;
private final int mRateUs;
private final int mMaxBatchReportLatencyUs;
- private final SensorEventListener2 mSensorEventListener;
- private TestSensorListener mTestSensorEventListener = null;
+ private TestSensorEventListener mTestSensorEventListener = null;
/**
- * Create a {@link TestSensorManager} with a {@link SensorEventListener2}. This can be used for
- * tests which require special behavior to be triggered on methods such as
- * {@link SensorEventListener2#onAccuracyChanged(Sensor, int)},
- * {@link SensorEventListener2#onFlushCompleted(Sensor)}, or
- * {@link SensorEventListener2#onSensorChanged(SensorEvent)}.
+ * Construct a {@link TestSensorManager}.
*/
public TestSensorManager(Context context, int sensorType, int rateUs,
- int maxBatchReportLatencyUs, SensorEventListener2 sensorEventListener) {
+ int maxBatchReportLatencyUs) {
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mSensor = SensorCtsHelper.getSensor(context, sensorType);
mRateUs = rateUs;
mMaxBatchReportLatencyUs = maxBatchReportLatencyUs;
- mSensorEventListener = sensorEventListener;
- }
-
- /**
- * Create a {@link TestSensorManager} without a {@link SensorEventListener2}.
- */
- public TestSensorManager(Context context, int sensorType, int rateUs,
- int maxBatchReportLatencyUs) {
- this(context, sensorType, rateUs, maxBatchReportLatencyUs, null);
}
/**
@@ -99,15 +76,16 @@
* @throws AssertionError if there was an error registering the listener with the
* {@link SensorManager}
*/
- public void registerListener() {
+ public void registerListener(TestSensorEventListener listener) {
if (mTestSensorEventListener != null) {
Log.w(LOG_TAG, "Listener already registered, returning.");
return;
}
- mTestSensorEventListener = new TestSensorListener(mSensorEventListener);
+ mTestSensorEventListener = listener != null ? listener : new TestSensorEventListener();
+ mTestSensorEventListener.setSensorInfo(mSensor, mRateUs, mMaxBatchReportLatencyUs);
- String message = formatAssertionMessage("registerListener");
+ String message = SensorCtsHelper.formatAssertionMessage(mSensor, "registerListener");
boolean result = mSensorManager.registerListener(mTestSensorEventListener, mSensor, mRateUs,
mMaxBatchReportLatencyUs);
Assert.assertTrue(message, result);
@@ -127,64 +105,27 @@
}
/**
- * Get a specific number of {@link TestSensorEvent}s and then clear the event queue. This method
- * will perform a no-op if the sensor is not registered.
- *
- * @throws AssertionError if there is a time out while collecting events
+ * Wait for a specific number of events.
*/
- public TestSensorEvent[] getEvents(int count) {
- if (mTestSensorEventListener == null) {
- Log.w(LOG_TAG, "No listener registered, returning.");
- return null;
- }
-
- mTestSensorEventListener.waitForEvents(count);
- TestSensorEvent[] events = mTestSensorEventListener.getEvents();
- mTestSensorEventListener.clearEvents();
-
- return events;
- }
-
- /**
- * Get the {@link TestSensorEvent} for a specific duration and then clear the event queue. This
- * method will perform a no-op if the sensor is not registered.
- */
- public TestSensorEvent[] getEvents(long duration, TimeUnit timeUnit) {
- if (mTestSensorEventListener == null) {
- Log.w(LOG_TAG, "No listener registered, returning.");
- return null;
- }
-
- mTestSensorEventListener.waitForEvents(duration, timeUnit);
- TestSensorEvent[] events = mTestSensorEventListener.getEvents();
- mTestSensorEventListener.clearEvents();
-
- return events;
- }
-
- /**
- * Get the {@link TestSensorEvent} from the event queue. This method will perform a no-op if the
- * sensor is not registered.
- */
- public TestSensorEvent[] getEvents() {
- if (mTestSensorEventListener == null) {
- Log.w(LOG_TAG, "No listener registered, returning.");
- return null;
- }
-
- return mTestSensorEventListener.getEvents();
- }
-
- /**
- * Clear the event queue. This method will perform a no-op if the sensor is not registered.
- */
- public void clearEvents() {
+ public void waitForEvents(int eventCount) {
if (mTestSensorEventListener == null) {
Log.w(LOG_TAG, "No listener registered, returning.");
return;
}
- mTestSensorEventListener.clearEvents();
+ mTestSensorEventListener.waitForEvents(eventCount);
+ }
+
+ /**
+ * Wait for a specific duration.
+ */
+ public void waitForEvents(long duration, TimeUnit timeUnit) {
+ if (mTestSensorEventListener == null) {
+ Log.w(LOG_TAG, "No listener registered, returning.");
+ return;
+ }
+
+ mTestSensorEventListener.waitForEvents(duration, timeUnit);
}
/**
@@ -198,7 +139,7 @@
return;
}
- String message = formatAssertionMessage("Flush");
+ String message = SensorCtsHelper.formatAssertionMessage(mSensor, "Flush");
Assert.assertTrue(message, mSensorManager.flush(mTestSensorEventListener));
}
@@ -236,43 +177,34 @@
}
/**
- * Collect a specific number of {@link TestSensorEvent}s. This method registers the event
- * listener before collecting the events and then unregisters the listener after. It will
- * perform a no-op if the sensor is already registered.
- *
- * @throws AssertionError if there is are errors registering the event listener or if there is
- * a time out collecting the events
+ * Register a listener, wait for a specific number of events, and then unregister the listener.
*/
- public TestSensorEvent[] collectEvents(int eventCount) {
+ public void runSensor(TestSensorEventListener listener, int eventCount) {
if (mTestSensorEventListener != null) {
Log.w(LOG_TAG, "Listener already registered, returning.");
- return null;
+ return;
}
try {
- registerListener();
- return getEvents(eventCount);
+ registerListener(listener);
+ waitForEvents(eventCount);
} finally {
unregisterListener();
}
}
/**
- * Collect the {@link TestSensorEvent} for a specific duration. This method registers the event
- * listener before collecting the events and then unregisters the listener after. It will
- * perform a no-op if the sensor is already registered.
- *
- * @throws AssertionError if there is are errors registering the event listener
+ * Register a listener, wait for a specific duration, and then unregister the listener.
*/
- public TestSensorEvent[] collectEvents(long duration, TimeUnit timeUnit) {
+ public void runSensor(TestSensorEventListener listener, long duration, TimeUnit timeUnit) {
if (mTestSensorEventListener != null) {
Log.w(LOG_TAG, "Listener already registered, returning.");
- return null;
+ return;
}
try {
- registerListener();
- return getEvents(duration, timeUnit);
+ registerListener(listener);
+ waitForEvents(duration, timeUnit);
} finally {
unregisterListener();
}
@@ -284,143 +216,4 @@
public Sensor getSensor() {
return mSensor;
}
-
- /**
- * Helper class which collects events and ensures the flushes are completed in a timely manner.
- */
- private class TestSensorListener implements SensorEventListener2 {
- private final SensorEventListener2 mListener;
-
- private final ConcurrentLinkedDeque<TestSensorEvent> mSensorEventsList =
- new ConcurrentLinkedDeque<TestSensorEvent>();
-
- private volatile CountDownLatch mEventLatch = null;
- private volatile CountDownLatch mFlushLatch = new CountDownLatch(1);
-
- public TestSensorListener(SensorEventListener2 listener) {
- mListener = listener;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onSensorChanged(SensorEvent event) {
- mSensorEventsList.addLast(new TestSensorEvent(event, System.nanoTime()));
- if(mEventLatch != null) {
- mEventLatch.countDown();
- }
- if (mListener != null) {
- mListener.onSensorChanged(event);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- if (mListener != null) {
- mListener.onAccuracyChanged(sensor, accuracy);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFlushCompleted(Sensor sensor) {
- CountDownLatch latch = mFlushLatch;
- mFlushLatch = new CountDownLatch(1);
- if(latch != null) {
- latch.countDown();
- }
- if (mListener != null) {
- mListener.onFlushCompleted(sensor);
- }
- }
-
- /**
- * Wait for {@link #onFlushCompleted(Sensor)} to be called.
- *
- * @throws AssertionError if there was a timeout after {@value #FLUSH_TIMEOUT_US} µs
- * @throws InterruptedException if the thread was interrupted
- */
- public void waitForFlushComplete() throws InterruptedException {
- CountDownLatch latch = mFlushLatch;
- if(latch != null) {
- String message = formatAssertionMessage("WaitForFlush");
- Assert.assertTrue(message, latch.await(FLUSH_TIMEOUT_US, TimeUnit.MICROSECONDS));
- }
- }
-
- /**
- * Collect a specific number of {@link TestSensorEvent}s.
- *
- * @throws AssertionError if there was a timeout after {@value #FLUSH_TIMEOUT_US} µs
- */
- public void waitForEvents(int eventCount) {
- mEventLatch = new CountDownLatch(eventCount);
- clearEvents();
- try {
- int rateUs = SensorCtsHelper.getDelay(mSensor, mRateUs);
- // Timeout is 2 * event count * expected period + default wait
- long timeoutUs = (2 * eventCount * rateUs) + EVENT_TIMEOUT_US;
-
- String message = formatAssertionMessage("WaitForEvents",
- "count:%d, available:%d", eventCount, mSensorEventsList.size());
- Assert.assertTrue(message, mEventLatch.await(timeoutUs, TimeUnit.MICROSECONDS));
- } catch(InterruptedException e) {
- // Ignore
- } finally {
- mEventLatch = null;
- }
- }
-
- /**
- * Collect {@link TestSensorEvent} for a specific duration.
- */
- public void waitForEvents(long duration, TimeUnit timeUnit) {
- clearEvents();
- SensorCtsHelper.sleep(duration, timeUnit);
- }
-
- /**
- * Get the {@link TestSensorEvent} from the event queue.
- */
- public TestSensorEvent[] getEvents() {
- return mSensorEventsList.toArray(new TestSensorEvent[0]);
- }
-
- /**
- * Clear the event queue.
- */
- public void clearEvents() {
- mSensorEventsList.clear();
- }
- }
-
- /**
- * Format an assertion message.
- *
- * @param label The verification name
- * @return The formatted string
- */
- private String formatAssertionMessage(String label) {
- return formatAssertionMessage(label, "");
- }
-
- /**
- * Format an assertion message with a custom message.
- *
- * @param label The verification name
- * @param format The additional format string
- * @param params The additional format params
- * @return The formatted string
- */
- private String formatAssertionMessage(String label, String format, Object ... params) {
- return String.format("%s | %s, handle: %d | %s",
- SensorTestInformation.getSensorName(mSensor.getType()), mSensor.getHandle(),
- String.format(format, params));
- }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/ValidatingSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/ValidatingSensorEventListener.java
new file mode 100644
index 0000000..b8f67be
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/ValidatingSensorEventListener.java
@@ -0,0 +1,82 @@
+/*
+ * 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, System.nanoTime());
+ for (ISensorVerification verification : mVerifications) {
+ verification.addSensorEvent(testEvent);
+ }
+ super.onSensorChanged(event);
+ }
+}
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
index 5f6e558..db1dff7 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AbstractSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AbstractSensorOperation.java
@@ -1,3 +1,19 @@
+/*
+ * 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;
@@ -8,14 +24,7 @@
*/
public abstract class AbstractSensorOperation implements ISensorOperation {
- private final SensorStats mStats = new SensorStats();
-
- /**
- * Wrapper around {@link SensorStats#addValue(String, Object)}
- */
- protected void addValue(String key, Object value) {
- mStats.addValue(key, value);
- }
+ protected final SensorStats mStats = new SensorStats();
/**
* Wrapper around {@link SensorStats#addSensorStats(String, SensorStats)}
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 af78db0..bf43189 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
@@ -26,8 +26,6 @@
* {@link ISensorOperation}.
*/
public class DelaySensorOperation implements ISensorOperation {
- private static final int NANOS_PER_MILLI = 1000000;
-
private final ISensorOperation mOperation;
private final long mDelay;
private final TimeUnit mTimeUnit;
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 0c7e771..cbcbc0d 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
@@ -58,7 +58,7 @@
long delayNs = TimeUnit.NANOSECONDS.convert(mDelay, mTimeUnit);
try {
Thread.sleep(delayNs / NANOS_PER_MILLI, (int) (delayNs % NANOS_PER_MILLI));
- addValue("executed", new Boolean(true));
+ mStats.addValue("executed", true);
if (mFail) {
Assert.fail("FakeSensorOperation failed");
}
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
new file mode 100644
index 0000000..b40176d
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
@@ -0,0 +1,189 @@
+/*
+ * 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.content.Context;
+import android.hardware.Sensor;
+import android.hardware.cts.helpers.SensorCtsHelper;
+import android.hardware.cts.helpers.SensorTestInformation;
+import android.hardware.cts.helpers.TestSensorManager;
+import android.hardware.cts.helpers.ValidatingSensorEventListener;
+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 junit.framework.Assert;
+
+import java.util.Collection;
+import java.util.HashSet;
+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 and then run all the tests.
+ * </p>
+ */
+public class TestSensorOperation extends AbstractSensorOperation {
+ private final TestSensorManager mSensorManager;
+ private final Context mContext;
+ private final int mSensorType;
+ private final int mRateUs;
+ private final int mMaxBatchReportLatencyUs;
+ private final Integer mEventCount;
+ private final Long mDuration;
+ private final TimeUnit mTimeUnit;
+
+ private final Collection<ISensorVerification> mVerifications =
+ new HashSet<ISensorVerification>();
+
+ /**
+ * Create a {@link TestSensorOperation}.
+ *
+ * @param context the {@link Context}.
+ * @param sensorType the sensor type
+ * @param rateUs the rate that
+ * @param maxBatchReportLatencyUs the max batch report latency
+ * @param eventCount the number of events to gather
+ */
+ public TestSensorOperation(Context context, int sensorType, int rateUs,
+ int maxBatchReportLatencyUs, int eventCount) {
+ this(context, sensorType, rateUs, maxBatchReportLatencyUs, eventCount, null, null);
+ }
+
+ /**
+ * Create a {@link TestSensorOperation}.
+ *
+ * @param context the {@link Context}.
+ * @param sensorType the sensor type
+ * @param rateUs the rate that
+ * @param maxBatchReportLatencyUs the max batch report latency
+ * @param duration the duration to gather events for
+ * @param timeUnit the time unit of the duration
+ */
+ public TestSensorOperation(Context context, int sensorType, int rateUs,
+ int maxBatchReportLatencyUs, long duration, TimeUnit timeUnit) {
+ this(context, sensorType, rateUs, maxBatchReportLatencyUs, null, duration, timeUnit);
+ }
+
+ /**
+ * Private helper constructor.
+ */
+ private TestSensorOperation(Context context, int sensorType, int rateUs,
+ int maxBatchReportLatencyUs, Integer eventCount, Long duration, TimeUnit timeUnit) {
+ mContext = context;
+ mSensorType = sensorType;
+ mRateUs = rateUs;
+ mMaxBatchReportLatencyUs = maxBatchReportLatencyUs;
+ mEventCount = eventCount;
+ mDuration = duration;
+ mTimeUnit = timeUnit;
+ mSensorManager = new TestSensorManager(mContext, mSensorType, mRateUs,
+ mMaxBatchReportLatencyUs);
+ }
+
+ /**
+ * Set all of the default test expectations.
+ */
+ public void setDefaultVerifications() {
+ Sensor sensor = mSensorManager.getSensor();
+ addVerification(EventOrderingVerification.getDefault(sensor));
+ addVerification(FrequencyVerification.getDefault(sensor, mRateUs));
+ addVerification(JitterVerification.getDefault(sensor, mRateUs));
+ addVerification(MagnitudeVerification.getDefault(sensor));
+ addVerification(MeanVerification.getDefault(sensor));
+ // Skip SigNumVerification since it has no default
+ addVerification(StandardDeviationVerification.getDefault(sensor));
+ }
+
+ 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() {
+ mStats.addValue("sensor_name", SensorTestInformation.getSensorName(mSensorType));
+ mStats.addValue("sensor_handle", mSensorManager.getSensor().getHandle());
+
+ ValidatingSensorEventListener listener = new ValidatingSensorEventListener(mVerifications);
+
+ if (mEventCount != null) {
+ mSensorManager.runSensor(listener, mEventCount);
+ } else {
+ mSensorManager.runSensor(listener, mDuration, mTimeUnit);
+ }
+
+ boolean failed = false;
+ StringBuilder sb = new StringBuilder();
+
+ for (ISensorVerification verification : mVerifications) {
+ failed |= evaluateResults(verification, sb);
+ }
+
+ if (failed) {
+ Assert.fail(SensorCtsHelper.formatAssertionMessage(mSensorManager.getSensor(),
+ "VerifySensorOperation", sb.toString()));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public TestSensorOperation clone() {
+ TestSensorOperation operation;
+ if (mEventCount != null) {
+ operation = new TestSensorOperation(mContext, mSensorType, mRateUs,
+ mMaxBatchReportLatencyUs, mEventCount);
+ } else {
+ operation = new TestSensorOperation(mContext, mSensorType, mRateUs,
+ mMaxBatchReportLatencyUs, mDuration, mTimeUnit);
+ }
+
+ 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(ISensorVerification verification, StringBuilder sb) {
+ try {
+ verification.verify(mStats);
+ } 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/VerifySensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/VerifySensorOperation.java
deleted file mode 100644
index 6f53573..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/VerifySensorOperation.java
+++ /dev/null
@@ -1,654 +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.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-import android.hardware.cts.helpers.SensorCtsHelper;
-import android.hardware.cts.helpers.SensorTestInformation;
-import android.hardware.cts.helpers.SensorVerificationHelper;
-import android.hardware.cts.helpers.SensorVerificationHelper.VerificationResult;
-import android.hardware.cts.helpers.TestSensorEvent;
-import android.hardware.cts.helpers.TestSensorManager;
-import android.util.Log;
-
-import junit.framework.Assert;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-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 and then run all the tests.
- * </p>
- */
-public class VerifySensorOperation extends AbstractSensorOperation {
- private static final String TAG = "VerifySensorOperation";
-
- private static final boolean DEBUG = false;
-
- // threshold is (100 - 10)% expected to (100 + 110)% expected
- private static final int[] DEFAULT_FREQUENCY_THRESHOLDS = {10, 110};
-
- private TestSensorManager mSensorManager;
- private Context mContext = null;
- private int mSensorType = 0;
- private int mRateUs = 0;
- private int mMaxBatchReportLatencyUs = 0;
- private Integer mEventCount = null;
- private Long mDuration = null;
- private TimeUnit mTimeUnit = null;
-
- private boolean mVerifyEventOrdering = false;
-
- private boolean mVerifyFrequency = false;
- private double mFrequencyExpected = 0.0;
- private double mFrequencyLowerThreshold = 0.0;
- private double mFrequencyUpperThreshold = 0.0;
-
- private boolean mVerifyJitter = false;
- private int mJitterExpected = 0;
- private int mJitterThreshold = 0;
-
- private boolean mVerifyMean = false;
- private float[] mMeanExpected = null;
- private float[] mMeanThreshold = null;
-
- private boolean mVerifyMagnitude = false;
- private float mMagnitudeExpected = 0.0f;
- private float mMagnitudeThreshold = 0.0f;
-
- private boolean mVerifySignum = false;
- private int[] mSignumExpected = null;
- private float[] mSignumThreshold = null;
-
- private boolean mVerifyStandardDeviation = false;
- private float[] mStandardDeviationThreshold = null;
-
- /**
- * Create a {@link VerifySensorOperation}.
- *
- * @param context the {@link Context}.
- * @param sensorType the sensor type
- * @param rateUs the rate that
- * @param maxBatchReportLatencyUs the max batch report latency
- * @param eventCount the number of events to gather
- */
- public VerifySensorOperation(Context context, int sensorType, int rateUs,
- int maxBatchReportLatencyUs, int eventCount) {
- mContext = context;
- mSensorType = sensorType;
- mRateUs = rateUs;
- mMaxBatchReportLatencyUs = maxBatchReportLatencyUs;
- mEventCount = eventCount;
- mSensorManager = new TestSensorManager(mContext, mSensorType, mRateUs,
- mMaxBatchReportLatencyUs);
- }
-
- /**
- * Create a {@link VerifySensorOperation}.
- *
- * @param context the {@link Context}.
- * @param sensorType the sensor type
- * @param rateUs the rate that
- * @param maxBatchReportLatencyUs the max batch report latency
- * @param duration the duration to gather events for
- * @param timeUnit the time unit of the duration
- */
- public VerifySensorOperation(Context context, int sensorType, int rateUs,
- int maxBatchReportLatencyUs, long duration, TimeUnit timeUnit) {
- mContext = context;
- mSensorType = sensorType;
- mRateUs = rateUs;
- mMaxBatchReportLatencyUs = maxBatchReportLatencyUs;
- mDuration = duration;
- mTimeUnit = timeUnit;
- mSensorManager = new TestSensorManager(mContext, mSensorType, mRateUs,
- mMaxBatchReportLatencyUs);
- }
-
- /**
- * Set all of the default test expectations.
- */
- public void setDefaultVerifications() {
- setDefaultVerifyEventOrdering();
- setDefaultVerifyFrequency();
- setDefaultVerifyJitter();
- setDefaultVerifyMean();
- setDefaultVerifyMagnitude();
- setDefaultVerifySignum();
- setDefaultVerifyStandardDeviation();
- }
-
- /**
- * Enable the event ordering verification.
- */
- public void verifyEventOrdering() {
- mVerifyEventOrdering = true;
- }
-
- /**
- * Set the default event ordering verification.
- */
- @SuppressWarnings("deprecation")
- public void setDefaultVerifyEventOrdering() {
- switch (mSensorType) {
- case Sensor.TYPE_ACCELEROMETER:
- case Sensor.TYPE_MAGNETIC_FIELD:
- case Sensor.TYPE_ORIENTATION:
- case Sensor.TYPE_GYROSCOPE:
- case Sensor.TYPE_PRESSURE:
- case Sensor.TYPE_GRAVITY:
- case Sensor.TYPE_LINEAR_ACCELERATION:
- case Sensor.TYPE_ROTATION_VECTOR:
- case Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED:
- case Sensor.TYPE_GAME_ROTATION_VECTOR:
- case Sensor.TYPE_GYROSCOPE_UNCALIBRATED:
- case Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR:
- verifyEventOrdering();
- break;
- }
- }
-
- /**
- * Enable the frequency verification.
- *
- * @param expected the expected frequency in Hz.
- * @param threshold the threshold in Hz.
- */
- public void verifyFrequency(double expected, double threshold) {
- mVerifyFrequency = true;
- mFrequencyExpected = expected;
- mFrequencyLowerThreshold = threshold;
- mFrequencyUpperThreshold = threshold;
- }
-
- /**
- * Enable the frequency verification.
- *
- * @param expected the expected frequency in Hz.
- * @param lowerThreshold the lower threshold in Hz.
- * @param upperThreshold the upper threshold in Hz.
- */
- public void verifyFrequency(double expected, double lowerThreshold, double upperThreshold) {
- mVerifyFrequency = true;
- mFrequencyExpected = expected;
- mFrequencyLowerThreshold = lowerThreshold;
- mFrequencyUpperThreshold = upperThreshold;
- }
-
- /**
- * Set the default frequency verification depending on the sensor.
- * <p>
- * The expected frequency is based on {@link Sensor#getMinDelay()} and the threshold is
- * calculated based on a percentage of the expected frequency. The verification will not be run
- * if the rate is set to {@link SensorManager#SENSOR_DELAY_GAME},
- * {@link SensorManager#SENSOR_DELAY_UI}, or {@link SensorManager#SENSOR_DELAY_NORMAL} because
- * these rates are not specified in the CDD.
- */
- @SuppressWarnings("deprecation")
- public void setDefaultVerifyFrequency() {
- if (!isRateValid()) {
- return;
- }
-
- // sensorType: lowerThreshold, upperThreshold (% of expected frequency)
- Map<Integer, int[]> defaults = new HashMap<Integer, int[]>(12);
- defaults.put(Sensor.TYPE_ACCELEROMETER, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_MAGNETIC_FIELD, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_GYROSCOPE, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_ORIENTATION, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_PRESSURE, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_GRAVITY, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_LINEAR_ACCELERATION, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_ROTATION_VECTOR, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_GAME_ROTATION_VECTOR, DEFAULT_FREQUENCY_THRESHOLDS);
- defaults.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, DEFAULT_FREQUENCY_THRESHOLDS);
-
- if (defaults.containsKey(mSensorType)) {
- // Expected frequency in Hz
- double expected = SensorCtsHelper.getFrequency(
- SensorCtsHelper.getDelay(mSensorManager.getSensor(), mRateUs),
- TimeUnit.MICROSECONDS);
- // Expected frequency * threshold percentage
- double lowerThreshold = expected * defaults.get(mSensorType)[0] / 100;
- double upperThreshold = expected * defaults.get(mSensorType)[1] / 100;
- verifyFrequency(expected, lowerThreshold, upperThreshold);
- }
- }
-
- /**
- * Enable the jitter verification.
- * <p>
- * This test looks at the 95th percentile of the jitter and makes sure it is less than the
- * threshold percentage of the expected period.
- * </p>
- *
- * @param expected the expected period in ns.
- * @param threshold the theshold as a percentage of the expected period.
- */
- public void verifyJitter(int expected, int threshold) {
- mVerifyJitter = true;
- mJitterExpected = expected;
- mJitterThreshold = threshold;
- }
-
- /**
- * Set the default jitter verification based on the sensor type.
- * <p>
- * The verification will not be run if the rate is set to
- * {@link SensorManager#SENSOR_DELAY_GAME}, {@link SensorManager#SENSOR_DELAY_UI}, or
- * {@link SensorManager#SENSOR_DELAY_NORMAL} because these rates are not specified in the CDD.
- * </p>
- */
- @SuppressWarnings("deprecation")
- public void setDefaultVerifyJitter() {
- if (!isRateValid()) {
- return;
- }
-
- // sensorType: threshold (% of expected period)
- Map<Integer, Integer> defaults = new HashMap<Integer, Integer>(12);
- // Sensors that we don't want to test at this time but still want to record the values.
- defaults.put(Sensor.TYPE_ACCELEROMETER, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_MAGNETIC_FIELD, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_GYROSCOPE, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_ORIENTATION, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_PRESSURE, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_GRAVITY, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_LINEAR_ACCELERATION, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_ROTATION_VECTOR, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_GAME_ROTATION_VECTOR, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, Integer.MAX_VALUE);
- defaults.put(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, Integer.MAX_VALUE);
-
- if (defaults.containsKey(mSensorType)) {
- int expected = (int) TimeUnit.NANOSECONDS.convert(
- SensorCtsHelper.getDelay(mSensorManager.getSensor(), mRateUs),
- TimeUnit.MICROSECONDS);
- verifyJitter(expected, defaults.get(mSensorType));
- }
- }
-
- /**
- * Enable the mean verification.
- *
- * @param expected the expected means
- * @param threshold the threshold
- */
- public void verifyMean(float[] expected, float[] threshold) {
- mVerifyMean = true;
- mMeanExpected = expected;
- mMeanThreshold = threshold;
- }
-
- /**
- * Set the default mean verification based on sensor type.
- * <p>
- * This sets the mean expectations for a device at rest in a standard environment. For sensors
- * whose values vary depending on the orientation or environment, the expectations will not be
- * set.
- * </p><p>
- * The following expectations are set for these sensors:
- * </p><ul>
- * <li>Gyroscope: all values should be 0.</li>
- * <li>Pressure: values[0] should be close to the standard pressure.</li>
- * <li>Linear acceleration: all values should be 0.</li>
- * <li>Game rotation vector: all values should be 0 except values[3] which should be 1.</li>
- * <li>Uncalibrated gyroscope: all values should be 0.</li>
- * </ul>
- */
- @SuppressWarnings("deprecation")
- public void setDefaultVerifyMean() {
- // sensorType: {expected, threshold}
- Map<Integer, Object[]> defaults = new HashMap<Integer, Object[]>(5);
- // Sensors that we don't want to test at this time but still want to record the values.
- // Gyroscope should be 0 for a static device
- defaults.put(Sensor.TYPE_GYROSCOPE, new Object[]{
- new float[]{0.0f, 0.0f, 0.0f},
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}});
- // Pressure will not be exact in a controlled environment but should be relatively close to
- // sea level. Second values should always be 0.
- defaults.put(Sensor.TYPE_PRESSURE, new Object[]{
- new float[]{SensorManager.PRESSURE_STANDARD_ATMOSPHERE, 0.0f, 0.0f},
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}});
- // Linear acceleration should be 0 in all directions for a static device
- defaults.put(Sensor.TYPE_LINEAR_ACCELERATION, new Object[]{
- new float[]{0.0f, 0.0f, 0.0f},
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}});
- // Game rotation vector should be (0, 0, 0, 1, 0) for a static device
- defaults.put(Sensor.TYPE_GAME_ROTATION_VECTOR, new Object[]{
- new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
- Float.MAX_VALUE}});
- // Uncalibrated gyroscope should be 0 for a static device but allow a bigger threshold
- defaults.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, new Object[]{
- new float[]{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
- Float.MAX_VALUE, Float.MAX_VALUE}});
-
- if (defaults.containsKey(mSensorType)) {
- float[] expected = (float[]) defaults.get(mSensorType)[0];
- float[] threshold = (float[]) defaults.get(mSensorType)[1];
- verifyMean(expected, threshold);
- }
- }
-
- /**
- * Enable the magnitude verification.
- *
- * @param expected the expected magnitude of the vector
- * @param threshold the threshold
- */
- public void verifyMagnitude(float expected, float threshold) {
- mVerifyMagnitude = true;
- mMagnitudeExpected = expected;
- mMagnitudeThreshold = threshold;
- }
-
- /**
- * Set the default magnitude verification base on the sensor type.
- * <p>
- * This sets the magnitude expectations for a device at rest in a standard environment. For
- * sensors whose values vary depending on the orientation or environment, the expectations will
- * not be set.
- * </p>
- */
- @SuppressWarnings("deprecation")
- public void setDefaultVerifyMagnitude() {
- // sensorType: {expected, threshold}
- Map<Integer, Float[]> defaults = new HashMap<Integer, Float[]>(3);
- defaults.put(Sensor.TYPE_ACCELEROMETER, new Float[]{SensorManager.STANDARD_GRAVITY, 1.5f});
- defaults.put(Sensor.TYPE_GYROSCOPE, new Float[]{0.0f, 1.5f});
- // Sensors that we don't want to test at this time but still want to record the values.
- defaults.put(Sensor.TYPE_GRAVITY,
- new Float[]{SensorManager.STANDARD_GRAVITY, Float.MAX_VALUE});
-
- if (defaults.containsKey(mSensorType)) {
- Float expected = defaults.get(mSensorType)[0];
- Float threshold = defaults.get(mSensorType)[1];
- verifyMagnitude(expected, threshold);
- }
- }
-
- /**
- * Enable the signum verification.
- *
- * @param expected the expected signs, an array of either -1s, 0s, or 1s.
- * @param threshold the threshold
- */
- public void verifySignum(int[] expected, float[] threshold) {
- mVerifySignum = true;
- mSignumExpected = expected;
- mSignumThreshold = threshold;
- }
-
- /**
- * Set the default signum verification base on the sensor type.
- * <p>
- * This is a no-op since currently all sensors which can specify a default sign can also specify
- * a default mean which is a more precise test.
- * </p>
- */
- public void setDefaultVerifySignum() {
- // No-op: All sensors that have an expected sign when static are already tested in
- // setDefaultVerifyMean().
- }
-
- /**
- * Enable the standard deviation verification.
- *
- * @param threshold the threshold.
- */
- public void verifyStandardDeviation(float[] threshold) {
- mVerifyStandardDeviation = true;
- mStandardDeviationThreshold = threshold;
- }
-
- /**
- * Set the default standard deviation verification based on the sensor type.
- */
- @SuppressWarnings("deprecation")
- public void setDefaultVerifyStandardDeviation() {
- // sensorType: threshold
- Map<Integer, float[]> defaults = new HashMap<Integer, float[]>(12);
- defaults.put(Sensor.TYPE_ACCELEROMETER, new float[]{1.0f, 1.0f, 1.0f});
- defaults.put(Sensor.TYPE_GYROSCOPE, new float[]{0.5f, 0.5f, 0.5f});
- // Sensors that we don't want to test at this time but still want to record the values.
- defaults.put(Sensor.TYPE_MAGNETIC_FIELD,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
- defaults.put(Sensor.TYPE_ORIENTATION,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
- defaults.put(Sensor.TYPE_PRESSURE,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
- defaults.put(Sensor.TYPE_GRAVITY,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
- defaults.put(Sensor.TYPE_LINEAR_ACCELERATION,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
- defaults.put(Sensor.TYPE_ROTATION_VECTOR,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
- Float.MAX_VALUE});
- defaults.put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
- Float.MAX_VALUE, Float.MAX_VALUE});
- defaults.put(Sensor.TYPE_GAME_ROTATION_VECTOR,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
- Float.MAX_VALUE});
- defaults.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
- Float.MAX_VALUE, Float.MAX_VALUE});
- defaults.put(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR,
- new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
- Float.MAX_VALUE});
-
- if (defaults.containsKey(mSensorType)) {
- float[] threshold = defaults.get(mSensorType);
- verifyStandardDeviation(threshold);
- }
- }
-
- /**
- * Collect the specified number of events from the sensor and run all enabled verifications.
- */
- @Override
- public void execute() {
- addValue("sensor_name", SensorTestInformation.getSensorName(mSensorType));
- addValue("sensor_handle", mSensorManager.getSensor().getHandle());
-
- TestSensorEvent[] events;
- if (mEventCount != null) {
- events = mSensorManager.collectEvents(mEventCount);
- } else {
- events = mSensorManager.collectEvents(mDuration, mTimeUnit);
- }
-
- boolean failed = false;
- StringBuilder sb = new StringBuilder();
- VerificationResult result = null;
-
- if (mVerifyEventOrdering) {
- result = SensorVerificationHelper.verifyEventOrdering(events);
- // evaluateResults first so it is always called.
- failed |= evaluateResults(result, sb);
- }
-
- if (mVerifyFrequency) {
- result = SensorVerificationHelper.verifyFrequency(events, mFrequencyExpected,
- mFrequencyLowerThreshold, mFrequencyUpperThreshold);
- failed |= evaluateResults(result, sb);
- }
-
- if (mVerifyJitter) {
- result = SensorVerificationHelper.verifyJitter(events, mJitterExpected,
- mJitterThreshold);
- failed |= evaluateResults(result, sb);
- }
-
- if (mVerifyMean) {
- result = SensorVerificationHelper.verifyMean(events, mMeanExpected, mMeanThreshold);
- failed |= evaluateResults(result, sb);
- }
-
- if (mVerifyMagnitude) {
- result = SensorVerificationHelper.verifyMagnitude(events, mMagnitudeExpected,
- mMagnitudeThreshold);
- failed |= evaluateResults(result, sb);
- }
-
- if (mVerifySignum) {
- result = SensorVerificationHelper.verifySignum(events, mSignumExpected,
- mSignumThreshold);
- failed |= evaluateResults(result, sb);
- }
-
- if (mVerifyStandardDeviation) {
- result = SensorVerificationHelper.verifyStandardDeviation(events,
- mStandardDeviationThreshold);
- failed |= evaluateResults(result, sb);
- }
-
- if (DEBUG) {
- logStats(events);
- }
-
- if (failed) {
- Assert.fail(String.format("%s, handle %d: %s",
- SensorTestInformation.getSensorName(mSensorType),
- mSensorManager.getSensor().getHandle(), sb.toString()));
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public VerifySensorOperation clone() {
- VerifySensorOperation operation;
- if (mEventCount != null) {
- operation = new VerifySensorOperation(mContext, mSensorType, mRateUs,
- mMaxBatchReportLatencyUs, mEventCount);
- } else {
- operation = new VerifySensorOperation(mContext, mSensorType, mRateUs,
- mMaxBatchReportLatencyUs, mDuration, mTimeUnit);
- }
- if (mVerifyEventOrdering) {
- operation.verifyEventOrdering();
- }
- if (mVerifyFrequency) {
- operation.verifyFrequency(mFrequencyExpected, mFrequencyLowerThreshold,
- mFrequencyUpperThreshold);
- }
- if (mVerifyJitter) {
- operation.verifyJitter(mJitterExpected, mJitterThreshold);
- }
- if (mVerifyMean) {
- operation.verifyMean(mMeanExpected, mMeanThreshold);
- }
- if (mVerifyMagnitude) {
- operation.verifyMagnitude(mMagnitudeExpected, mMagnitudeThreshold);
- }
- if (mVerifySignum) {
- operation.verifySignum(mSignumExpected, mSignumThreshold);
- }
- if (mVerifyStandardDeviation) {
- operation.verifyStandardDeviation(mStandardDeviationThreshold);
- }
- return operation;
- }
-
- /**
- * Return true if the operation rate is not one of {@link SensorManager#SENSOR_DELAY_GAME},
- * {@link SensorManager#SENSOR_DELAY_UI}, or {@link SensorManager#SENSOR_DELAY_NORMAL}.
- */
- private boolean isRateValid() {
- return (mRateUs != SensorManager.SENSOR_DELAY_GAME
- && mRateUs != SensorManager.SENSOR_DELAY_UI
- && mRateUs != SensorManager.SENSOR_DELAY_NORMAL);
- }
-
- /**
- * Evaluate the results of a test, aggregate the stats, and build the error message.
- */
- private boolean evaluateResults(VerificationResult result, StringBuilder sb) {
- for (String key : result.getKeys()) {
- addValue(key, result.getValue(key));
- }
-
- if (result.isFailed()) {
- if (sb.length() > 0) {
- sb.append(", ");
- }
- sb.append(result.getFailureMessage());
- return true;
- }
- return false;
- }
-
- /**
- * Log the events to the logcat.
- */
- private void logStats(TestSensorEvent[] events) {
- if (events.length <= 0) {
- return;
- }
-
- List<Double> jitterValues = null;
- if (events.length > 1) {
- jitterValues = SensorCtsHelper.getJitterValues(events);
- }
-
- logTestSensorEvent(0, events[0], null, null);
- for (int i = 1; i < events.length; i++) {
- Double jitter = jitterValues == null ? null : jitterValues.get(i - 1);
- logTestSensorEvent(i, events[i], events[i - 1], jitter);
- }
- }
-
- /**
- * Log a single sensor event to the logcat.
- */
- private void logTestSensorEvent(int index, TestSensorEvent event, TestSensorEvent prevEvent,
- Double jitter) {
- String deltaStr = prevEvent == null ? null : String.format("%d",
- event.timestamp - prevEvent.timestamp);
- String jitterStr = jitter == null ? null : String.format("%.2f", jitter);
-
- StringBuilder valuesSb = new StringBuilder();
- if (event.values.length == 1) {
- valuesSb.append(String.format("%.2f", event.values[0]));
- } else {
- valuesSb.append("[").append(String.format("%.2f", event.values[0]));
- for (int i = 1; i < event.values.length; i++) {
- valuesSb.append(String.format(", %.2f", event.values[i]));
- }
- valuesSb.append("]");
- }
-
- Log.v(TAG, String.format(
- "Sensor %d: Event %d: device_timestamp=%d, delta_timestamp=%s, jitter=%s, "
- + "values=%s", mSensorManager.getSensor().getType(), index, event.timestamp,
- deltaStr, jitterStr, valuesSb.toString()));
- }
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractMeanVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractMeanVerification.java
new file mode 100644
index 0000000..8d132a3
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractMeanVerification.java
@@ -0,0 +1,66 @@
+/*
+ * 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 android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.Assert;
+
+/**
+ * Abstract class that calculates of the mean event values.
+ */
+public abstract class AbstractMeanVerification extends AbstractSensorVerification {
+ private float[] mSums = null;
+ private int mCount = 0;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addSensorEventInternal(TestSensorEvent event) {
+ if (mSums == null) {
+ mSums = new float[event.values.length];
+ }
+ Assert.assertEquals(mSums.length, event.values.length);
+ for (int i = 0; i < mSums.length; i++) {
+ mSums[i] += event.values[i];
+ }
+ mCount++;
+ }
+
+ /**
+ * Return the number of events.
+ */
+ protected int getCount() {
+ return mCount;
+ }
+
+ /**
+ * Return the means of the event values.
+ */
+ protected float[] getMeans() {
+ if (mCount < 0) {
+ return null;
+ }
+
+ float[] means = new float[mSums.length];
+ for (int i = 0; i < mSums.length; i++) {
+ means[i] = mSums[i] / mCount;
+ }
+ return means;
+ }
+}
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
new file mode 100644
index 0000000..f11f7a4
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
@@ -0,0 +1,54 @@
+/*
+ * 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 android.hardware.cts.helpers.TestSensorEvent;
+
+/**
+ * Abstract class that deals with the synchronization of the sensor verifications.
+ */
+public abstract class AbstractSensorVerification implements ISensorVerification {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized void addSensorEvents(TestSensorEvent ... events) {
+ for (TestSensorEvent event : events) {
+ addSensorEventInternal(event);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized void addSensorEvent(TestSensorEvent event) {
+ addSensorEventInternal(event);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public abstract ISensorVerification clone();
+
+ /**
+ * Used by implementing classes to add a sensor event.
+ */
+ protected abstract void addSensorEventInternal(TestSensorEvent event);
+}
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
new file mode 100644
index 0000000..28ddfe7
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
@@ -0,0 +1,145 @@
+/*
+ * 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 android.hardware.Sensor;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.Assert;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A {@link ISensorVerification} which verifies that all events are received in the correct order.
+ */
+public class EventOrderingVerification extends AbstractSensorVerification {
+ public static final String PASSED_KEY = "event_order_passed";
+
+ private static final int MESSAGE_LENGTH = 3;
+
+ private Long mMaxTimestamp = null;
+ private TestSensorEvent mPreviousEvent = null;
+ private final List<EventInfo> mOutOfOrderEvents = new LinkedList<EventInfo>();
+ private int mCount = 0;
+ private int mIndex = 0;
+
+ /**
+ * Get the default {@link EventOrderingVerification} for a sensor.
+ *
+ * @param sensor a {@link Sensor}
+ * @return the verification or null if the verification does not apply to the sensor.
+ */
+ @SuppressWarnings("deprecation")
+ public static EventOrderingVerification getDefault(Sensor sensor) {
+ switch (sensor.getType()) {
+ case Sensor.TYPE_ACCELEROMETER:
+ case Sensor.TYPE_MAGNETIC_FIELD:
+ case Sensor.TYPE_ORIENTATION:
+ case Sensor.TYPE_GYROSCOPE:
+ case Sensor.TYPE_PRESSURE:
+ case Sensor.TYPE_GRAVITY:
+ case Sensor.TYPE_LINEAR_ACCELERATION:
+ case Sensor.TYPE_ROTATION_VECTOR:
+ case Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+ case Sensor.TYPE_GAME_ROTATION_VECTOR:
+ case Sensor.TYPE_GYROSCOPE_UNCALIBRATED:
+ case Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+ return new EventOrderingVerification();
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Verify that the events are in the correct order. Add {@value #PASSED_KEY},
+ * {@value SensorStats#EVENT_OUT_OF_ORDER_COUNT_KEY}, and
+ * {@value SensorStats#EVENT_OUT_OF_ORDER_POSITIONS_KEY} keys to {@link SensorStats}.
+ *
+ * @throws AssertionError if the verification failed.
+ */
+ @Override
+ public void verify(SensorStats stats) {
+ stats.addValue(PASSED_KEY, mCount == 0);
+ stats.addValue(SensorStats.EVENT_OUT_OF_ORDER_COUNT_KEY, mCount);
+
+ int[] indices = new int[mOutOfOrderEvents.size()];
+ for (int i = 0; i < indices.length; i++) {
+ indices[i] = mOutOfOrderEvents.get(i).index;
+ }
+ stats.addValue(SensorStats.EVENT_OUT_OF_ORDER_POSITIONS_KEY, indices);
+
+ if (mOutOfOrderEvents.size() > 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(mCount).append(" events out of order: ");
+ for (int i = 0; i < Math.min(mOutOfOrderEvents.size(), MESSAGE_LENGTH); i++) {
+ EventInfo info = mOutOfOrderEvents.get(i);
+ sb.append(String.format("position=%d, previous=%d, timestamp=%d; ", info.index,
+ info.previousEvent.timestamp, info.event.timestamp));
+ }
+ if (mOutOfOrderEvents.size() > MESSAGE_LENGTH) {
+ sb.append(mOutOfOrderEvents.size() - MESSAGE_LENGTH).append(" more");
+ } else {
+ // Delete the trailing "; "
+ sb.delete(sb.length() - 2, sb.length());
+ }
+
+ Assert.fail(sb.toString());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EventOrderingVerification clone() {
+ return new EventOrderingVerification();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addSensorEventInternal(TestSensorEvent event) {
+ if (mPreviousEvent == null) {
+ mMaxTimestamp = event.timestamp;
+ } else {
+ if (event.timestamp < mMaxTimestamp) {
+ mOutOfOrderEvents.add(new EventInfo(mIndex, event, mPreviousEvent));
+ mCount++;
+ } else if (event.timestamp > mMaxTimestamp) {
+ mMaxTimestamp = event.timestamp;
+ }
+ }
+
+ mPreviousEvent = event;
+ mIndex++;
+ }
+
+ private class EventInfo {
+ public final int index;
+ public final TestSensorEvent event;
+ public final TestSensorEvent previousEvent;
+
+ public EventInfo(int index, TestSensorEvent event, TestSensorEvent previousEvent) {
+ this.index = index;
+ this.event = event;
+ this.previousEvent = previousEvent;
+ }
+ }
+}
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
new file mode 100644
index 0000000..28cbd01
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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 android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link EventOrderingVerification}.
+ */
+public class EventOrderingVerificationTest extends TestCase {
+
+ /**
+ * Test that the verification passes when there are no results.
+ */
+ public void testNoEvents() {
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification();
+ verification.verify(stats);
+ verifyStats(stats, true, 0);
+ }
+
+ /**
+ * Test that the verification passes when the timestamps are the same.
+ */
+ public void testSameTimestamp() {
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(0, 0, 0, 0, 0);
+ verification.verify(stats);
+ verifyStats(stats, true, 0);
+ }
+
+ /**
+ * Test that the verification passes when the timestamps are increasing.
+ */
+ public void testSequentialTimestamp() {
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(0, 1, 2, 3, 4);
+ verification.verify(stats);
+ verifyStats(stats, true, 0);
+ }
+
+ /**
+ * Test that the verification fails when there is one event out of order.
+ */
+ public void testSingleOutofOrder() {
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(0, 2, 1, 3, 4);
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ verifyStats(stats, false, 1);
+ List<Integer> indices = getIndices(stats);
+ assertTrue(indices.contains(2));
+ }
+
+ /**
+ * Test that the verification fails when there are multiple events out of order.
+ */
+ public void testMultipleOutOfOrder() {
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(4, 0, 1, 2, 3);
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ verifyStats(stats, false, 4);
+ List<Integer> indices = getIndices(stats);
+ assertTrue(indices.contains(1));
+ assertTrue(indices.contains(2));
+ assertTrue(indices.contains(3));
+ assertTrue(indices.contains(4));
+ }
+
+ private ISensorVerification getVerification(long ... timestamps) {
+ ISensorVerification verification = new EventOrderingVerification();
+ for (long timestamp : timestamps) {
+ verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ }
+ return verification;
+ }
+
+ private void verifyStats(SensorStats stats, boolean passed, int count) {
+ assertEquals(passed, stats.getValue(EventOrderingVerification.PASSED_KEY));
+ assertEquals(count, stats.getValue(SensorStats.EVENT_OUT_OF_ORDER_COUNT_KEY));
+ assertNotNull(stats.getValue(SensorStats.EVENT_OUT_OF_ORDER_POSITIONS_KEY));
+ }
+
+ private List<Integer> getIndices(SensorStats stats) {
+ int[] primitiveIndices = (int[]) stats.getValue(
+ SensorStats.EVENT_OUT_OF_ORDER_POSITIONS_KEY);
+ List<Integer> indices = new ArrayList<Integer>(primitiveIndices.length);
+ for (int index : primitiveIndices) {
+ indices.add(index);
+ }
+ return indices;
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerification.java
new file mode 100644
index 0000000..030bfeb
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerification.java
@@ -0,0 +1,160 @@
+/*
+ * 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 android.hardware.Sensor;
+import android.hardware.cts.helpers.SensorCtsHelper;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.Assert;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link ISensorVerification} which verifies that the sensor frequency are within the expected
+ * range.
+ */
+public class FrequencyVerification extends AbstractSensorVerification {
+ public static final String PASSED_KEY = "frequency_passed";
+
+ // threshold is (100 - 10)% expected to (100 + 110)% expected
+ private static final int[] DEFAULT_THRESHOLDS = {10, 110};
+
+ // sensorType: lowerThreshold, upperThreshold (% of expected frequency)
+ private final static Map<Integer, int[]> DEFAULTS = new HashMap<Integer, int[]>(12);
+ static {
+ // Use a method so that the @deprecation warning can be set for that method only
+ setDefaults();
+ }
+
+ private final double mExpected;
+ private final double mLowerThreshold;
+ private final double mUpperThreshold;
+
+ private long mMinTimestamp = 0;
+ private long mMaxTimestamp = 0;
+ private int mCount = 0;
+
+ /**
+ * Construct a {@link FrequencyVerification}.
+ *
+ * @param expected the expected frequency in Hz.
+ * @param lowerTheshold the lower threshold in Hz. {@code expected - lower} should be the
+ * slowest acceptable frequency of the sensor.
+ * @param upperThreshold the upper threshold in Hz. {@code expected + upper} should be the
+ * fastest acceptable frequency of the sensor.
+ */
+ public FrequencyVerification(double expected, double lowerTheshold, double upperThreshold) {
+ mExpected = expected;
+ mLowerThreshold = lowerTheshold;
+ mUpperThreshold = upperThreshold;
+ }
+
+ /**
+ * Get the default {@link FrequencyVerification} for a sensor.
+ *
+ * @param sensor a {@link Sensor}
+ * @param rateUs the desired rate of the sensor
+ * @return the verification or null if the verification does not apply to the sensor.
+ */
+ public static FrequencyVerification getDefault(Sensor sensor, int rateUs) {
+ if (!DEFAULTS.containsKey(sensor.getType())) {
+ return null;
+ }
+
+ // Expected frequency in Hz
+ double expected = SensorCtsHelper.getFrequency(SensorCtsHelper.getDelay(sensor, rateUs),
+ TimeUnit.MICROSECONDS);
+ // Expected frequency * threshold percentage
+ double lowerThreshold = expected * DEFAULTS.get(sensor.getType())[0] / 100;
+ double upperThreshold = expected * DEFAULTS.get(sensor.getType())[1] / 100;
+ return new FrequencyVerification(expected, lowerThreshold, upperThreshold);
+ }
+
+ /**
+ * Verify that the frequency is correct. Add {@value #PASSED_KEY} and
+ * {@value SensorStats#FREQUENCY_KEY} keys to {@link SensorStats}.
+ *
+ * @throws AssertionError if the verification failed.
+ */
+ @Override
+ public void verify(SensorStats stats) {
+ if (mCount < 2) {
+ stats.addValue(PASSED_KEY, true);
+ return;
+ }
+
+ double frequency = SensorCtsHelper.getFrequency(
+ ((double) (mMaxTimestamp - mMinTimestamp)) / (mCount - 1), TimeUnit.NANOSECONDS);
+ boolean failed = (frequency <= mExpected - mLowerThreshold
+ || frequency >= mExpected + mUpperThreshold);
+
+ stats.addValue(SensorStats.FREQUENCY_KEY, frequency);
+ stats.addValue(PASSED_KEY, !failed);
+
+ if (failed) {
+ Assert.fail(String.format("Frequency out of range: frequency=%.2fHz, "
+ + "expected=(%.2f-%.2fHz, %.2f+%.2fHz)", frequency, mExpected, mLowerThreshold,
+ mExpected, mUpperThreshold));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public FrequencyVerification clone() {
+ return new FrequencyVerification(mExpected, mLowerThreshold, mUpperThreshold);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addSensorEventInternal(TestSensorEvent event) {
+ if (mCount == 0) {
+ mMinTimestamp = event.timestamp;
+ mMaxTimestamp = event.timestamp;
+ } else {
+ if (mMinTimestamp > event.timestamp) {
+ mMinTimestamp = event.timestamp;
+ }
+ if (mMaxTimestamp < event.timestamp) {
+ mMaxTimestamp = event.timestamp;
+ }
+ }
+ mCount++;
+ }
+
+ @SuppressWarnings("deprecation")
+ private static void setDefaults() {
+ DEFAULTS.put(Sensor.TYPE_ACCELEROMETER, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_GYROSCOPE, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_ORIENTATION, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_PRESSURE, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_GRAVITY, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_LINEAR_ACCELERATION, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_ROTATION_VECTOR, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_GAME_ROTATION_VECTOR, DEFAULT_THRESHOLDS);
+ DEFAULTS.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, DEFAULT_THRESHOLDS);
+ }
+}
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
new file mode 100644
index 0000000..cec09a5
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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 android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link EventOrderingVerification}.
+ */
+public class FrequencyVerificationTest extends TestCase {
+
+ /**
+ * Test that the verifications passes/fails based on threshold given.
+ */
+ public void testVerifification() {
+ long[] timestamps = {0, 1000000, 2000000, 3000000, 4000000}; // 1000Hz
+
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(1000.0, 1.0, 1.0, timestamps);
+ verification.verify(stats);
+ verifyStats(stats, true, 1000.0);
+
+ stats = new SensorStats();
+ verification = getVerification(950.0, 100.0, 100.0, timestamps);
+ verification.verify(stats);
+ verifyStats(stats, true, 1000.0);
+
+ stats = new SensorStats();
+ verification = getVerification(1050.0, 100.0, 100.0, timestamps);
+ verification.verify(stats);
+ verifyStats(stats, true, 1000.0);
+
+ stats = new SensorStats();
+ verification = getVerification(950.0, 100.0, 25.0, timestamps);
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ verifyStats(stats, false, 1000.0);
+
+ stats = new SensorStats();
+ verification = getVerification(1050.0, 25.0, 100.0, timestamps);
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ verifyStats(stats, false, 1000.0);
+ }
+
+ private ISensorVerification getVerification(double expected, double lowerThreshold,
+ double upperThreshold, long ... timestamps) {
+ ISensorVerification verification = new FrequencyVerification(expected, lowerThreshold,
+ upperThreshold);
+ for (long timestamp : timestamps) {
+ verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ }
+ return verification;
+ }
+
+ private void verifyStats(SensorStats stats, boolean passed, double frequency) {
+ assertEquals(passed, stats.getValue(FrequencyVerification.PASSED_KEY));
+ assertEquals(frequency, stats.getValue(SensorStats.FREQUENCY_KEY));
+ }
+}
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
new file mode 100644
index 0000000..07af392
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
@@ -0,0 +1,52 @@
+/*
+ * 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 android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+/**
+ * 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(SensorStats)} should be called after all events are added.
+ */
+public interface ISensorVerification {
+
+ /**
+ * Add a single {@link TestSensorEvent} to be evaluated.
+ */
+ public void addSensorEvent(TestSensorEvent event);
+
+ /**
+ * Add multiple {@link TestSensorEvent}s to be evaluated.
+ */
+ public void addSensorEvents(TestSensorEvent ... events);
+
+ /**
+ * Evaluate all added {@link TestSensorEvent}s and update stats.
+ *
+ * @param stats a {@link SensorStats} object used to keep track of the stats.
+ * @throws AssertionError if the verification fails.
+ */
+ public void verify(SensorStats stats);
+
+ /**
+ * Clones the {@link ISensorVerification}
+ */
+ public ISensorVerification clone();
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
new file mode 100644
index 0000000..7929ee9
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
@@ -0,0 +1,154 @@
+/*
+ * 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 android.hardware.Sensor;
+import android.hardware.cts.helpers.SensorCtsHelper;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link ISensorVerification} which verifies that the sensor jitter is in an acceptable range.
+ */
+public class JitterVerification extends AbstractSensorVerification {
+ public static final String PASSED_KEY = "jitter_passed";
+
+ // sensorType: threshold (% of expected period)
+ private static final Map<Integer, Integer> DEFAULTS = new HashMap<Integer, Integer>(12);
+ static {
+ // Use a method so that the @deprecation warning can be set for that method only
+ setDefaults();
+ }
+
+ private final int mExpected;
+ private final int mThreshold;
+
+ private List<Long> mTimestamps = new LinkedList<Long>();
+
+ /**
+ * Construct a {@link JitterVerification}
+ *
+ * @param expected the expected period in ns
+ * @param threshold the acceptable margin of error as a percentage
+ */
+ public JitterVerification(int expected, int threshold) {
+ mExpected = expected;
+ mThreshold = threshold;
+ }
+
+ /**
+ * Get the default {@link JitterVerification} for a sensor.
+ *
+ * @param sensor a {@link Sensor}
+ * @param rateUs the desired rate of the sensor
+ * @return the verification or null if the verification does not apply to the sensor.
+ */
+ public static JitterVerification getDefault(Sensor sensor, int rateUs) {
+ if (!DEFAULTS.containsKey(sensor.getType())) {
+ return null;
+ }
+
+ int expected = (int) TimeUnit.NANOSECONDS.convert(SensorCtsHelper.getDelay(sensor, rateUs),
+ TimeUnit.MICROSECONDS);
+ return new JitterVerification(expected, DEFAULTS.get(sensor.getType()));
+ }
+
+ /**
+ * Verify that the 95th percentile of the jitter is in the acceptable range. Add
+ * {@value #PASSED_KEY} and {@value SensorStats#JITTER_95_PERCENTILE_KEY} keys to
+ * {@link SensorStats}.
+ *
+ * @throws AssertionError if the verification failed.
+ */
+ @Override
+ public void verify(SensorStats stats) {
+ if (mTimestamps.size() < 2) {
+ stats.addValue(PASSED_KEY, true);
+ return;
+ }
+
+ List<Double> jitters = getJitterValues();
+ double jitter95Percentile = SensorCtsHelper.get95PercentileValue(jitters);
+ boolean failed = (jitter95Percentile > mExpected * (mThreshold / 100.0));
+
+ stats.addValue(PASSED_KEY, !failed);
+ stats.addValue(SensorStats.JITTER_95_PERCENTILE_KEY, jitter95Percentile);
+
+ if (failed) {
+ Assert.fail(String.format("Jitter out of range: jitter at 95th percentile=%.0fns, "
+ + "expected=<%.0fns", jitter95Percentile, mExpected * (mThreshold / 100.0)));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public JitterVerification clone() {
+ return new JitterVerification(mExpected, mThreshold);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addSensorEventInternal(TestSensorEvent event) {
+ mTimestamps.add(event.timestamp);
+ }
+
+ /**
+ * Get the list of all jitter values. Exposed for unit testing.
+ */
+ List<Double> getJitterValues() {
+ List<Long> deltas = new ArrayList<Long>(mTimestamps.size() - 1);
+ for (int i = 1; i < mTimestamps.size(); i++) {
+ deltas.add(mTimestamps.get(i) - mTimestamps.get(i -1));
+ }
+ double deltaMean = SensorCtsHelper.getMean(deltas);
+ List<Double> jitters = new ArrayList<Double>(deltas.size());
+ for (long delta : deltas) {
+ jitters.add(Math.abs(delta - deltaMean));
+ }
+ return jitters;
+ }
+
+ @SuppressWarnings("deprecation")
+ private static void setDefaults() {
+ // Sensors that we don't want to test at this time but still want to record the values.
+ DEFAULTS.put(Sensor.TYPE_ACCELEROMETER, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_GYROSCOPE, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_ORIENTATION, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_PRESSURE, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_GRAVITY, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_LINEAR_ACCELERATION, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_ROTATION_VECTOR, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_GAME_ROTATION_VECTOR, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, Integer.MAX_VALUE);
+ DEFAULTS.put(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, Integer.MAX_VALUE);
+ }
+}
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
new file mode 100644
index 0000000..a9e872a
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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 android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+
+/**
+ * Tests for {@link EventOrderingVerification}.
+ */
+public class JitterVerificationTest extends TestCase {
+
+
+ public void testVerify() {
+ final int SAMPLE_SIZE = 100;
+
+ // 100 samples at 1000Hz
+ long[] timestamps = new long[SAMPLE_SIZE];
+ for (int i = 0; i < SAMPLE_SIZE; i++) {
+ timestamps[i] = i * 100000;
+ }
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(1000, 1, timestamps);
+ verification.verify(stats);
+ verifyStats(stats, true, 0.0);
+
+ // 90 samples at 1000Hz, 10 samples at 2000Hz
+ long timestamp = 0;
+ for (int i = 0; i < SAMPLE_SIZE; i++) {
+ timestamps[i] = timestamp;
+ timestamp += (i % 10 == 0) ? 500000 : 1000000;
+ }
+ stats = new SensorStats();
+ verification = getVerification(1000, 1, timestamps);
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ verifyStats(stats, false, 449494.9494);
+ }
+
+ public void testCalculateJitter() {
+ long[] timestamps = new long[]{0, 1, 2, 3, 4};
+ JitterVerification verification = getVerification(1000, 1, timestamps);
+ List<Double> jitterValues = verification.getJitterValues();
+ assertEquals(4, jitterValues.size());
+ assertEquals(0.0, (double) jitterValues.get(0));
+ assertEquals(0.0, (double) jitterValues.get(1));
+ assertEquals(0.0, (double) jitterValues.get(2));
+ assertEquals(0.0, (double) jitterValues.get(3));
+
+ timestamps = new long[]{0, 0, 2, 4, 4};
+ verification = getVerification(1000, 1, timestamps);
+ jitterValues = verification.getJitterValues();
+ assertEquals(4, jitterValues.size());
+ assertEquals(1.0, (double) jitterValues.get(0));
+ assertEquals(1.0, (double) jitterValues.get(1));
+ assertEquals(1.0, (double) jitterValues.get(2));
+ assertEquals(1.0, (double) jitterValues.get(3));
+
+ timestamps = new long[]{0, 1, 4, 9, 16};
+ verification = getVerification(1000, 1, timestamps);
+ jitterValues = verification.getJitterValues();
+ assertEquals(4, jitterValues.size());
+ assertEquals(4, jitterValues.size());
+ assertEquals(3.0, (double) jitterValues.get(0));
+ assertEquals(1.0, (double) jitterValues.get(1));
+ assertEquals(1.0, (double) jitterValues.get(2));
+ assertEquals(3.0, (double) jitterValues.get(3));
+ }
+
+ private JitterVerification getVerification(int expected, int threshold, long ... timestamps) {
+ JitterVerification verification = new JitterVerification(expected, threshold);
+ for (long timestamp : timestamps) {
+ verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ }
+ return verification;
+ }
+
+ private void verifyStats(SensorStats stats, boolean passed, double jitter95) {
+ assertEquals(passed, stats.getValue(JitterVerification.PASSED_KEY));
+ assertEquals(jitter95, (Double) stats.getValue(SensorStats.JITTER_95_PERCENTILE_KEY), 0.1);
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerification.java
new file mode 100644
index 0000000..d987eef
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerification.java
@@ -0,0 +1,129 @@
+/*
+ * 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 android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.Assert;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link ISensorVerification} which verifies that the mean of the magnitude of the sensors vector
+ * is within the expected range.
+ */
+public class MagnitudeVerification extends AbstractSensorVerification {
+ public static final String PASSED_KEY = "magnitude_passed";
+
+ // sensorType: {expected, threshold}
+ private static Map<Integer, Float[]> DEFAULTS = new HashMap<Integer, Float[]>(3);
+ static {
+ // Use a method so that the @deprecation warning can be set for that method only
+ setDefaults();
+ }
+
+ private final float mExpected;
+ private final float mThreshold;
+
+ private float mSum = 0.0f;
+ private int mCount = 0;
+
+ /**
+ * Construct a {@link MagnitudeVerification}
+ *
+ * @param expected the expected value
+ * @param threshold the threshold
+ */
+ public MagnitudeVerification(float expected, float threshold) {
+ mExpected = expected;
+ mThreshold = threshold;
+ }
+
+ /**
+ * Get the default {@link MagnitudeVerification} for a sensor.
+ *
+ * @param sensor a {@link Sensor}
+ * @return the verification or null if the verification does not apply to the sensor.
+ */
+ public static MagnitudeVerification getDefault(Sensor sensor) {
+ if (!DEFAULTS.containsKey(sensor.getType())) {
+ return null;
+ }
+ Float expected = DEFAULTS.get(sensor.getType())[0];
+ Float threshold = DEFAULTS.get(sensor.getType())[1];
+ return new MagnitudeVerification(expected, threshold);
+ }
+
+ /**
+ * Verify that the magnitude is in the acceptable range. Add {@value #PASSED_KEY} and
+ * {@value SensorStats#MAGNITUDE_KEY} keys to {@link SensorStats}.
+ *
+ * @throws AssertionError if the verification failed.
+ */
+ @Override
+ public void verify(SensorStats stats) {
+ if (mCount < 1) {
+ stats.addValue(PASSED_KEY, true);
+ return;
+ }
+
+ float mean = mSum / mCount;
+ boolean failed = Math.abs(mean - mExpected) > mThreshold;
+
+ stats.addValue(PASSED_KEY, !failed);
+ stats.addValue(SensorStats.MAGNITUDE_KEY, mean);
+
+ if (failed) {
+ Assert.fail(String.format("Magnitude mean out of range: mean=%s, expected=%s+/-%s",
+ mean, mExpected, mThreshold));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public MagnitudeVerification clone() {
+ return new MagnitudeVerification(mExpected, mThreshold);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addSensorEventInternal(TestSensorEvent event) {
+ float sumOfSquares = 0.0f;
+ for (float value : event.values) {
+ sumOfSquares += value * value;
+ }
+ mSum += (float) Math.sqrt(sumOfSquares);
+ mCount++;
+ }
+
+ @SuppressWarnings("deprecation")
+ private static void setDefaults() {
+ DEFAULTS.put(Sensor.TYPE_ACCELEROMETER, new Float[]{SensorManager.STANDARD_GRAVITY, 1.5f});
+ DEFAULTS.put(Sensor.TYPE_GYROSCOPE, new Float[]{0.0f, 1.5f});
+ // Sensors that we don't want to test at this time but still want to record the values.
+ DEFAULTS.put(Sensor.TYPE_GRAVITY,
+ new Float[]{SensorManager.STANDARD_GRAVITY, Float.MAX_VALUE});
+ }
+}
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
new file mode 100644
index 0000000..9a50753
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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 android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link MagnitudeVerification}.
+ */
+public class MagnitudeVerificationTest extends TestCase {
+
+ /**
+ * Test {@link MagnitudeVerification#verify(SensorStats)}.
+ */
+ public void testVerify() {
+ float[][] values = {
+ {0, 3, 4},
+ {4, 0, 3},
+ {3, 4, 0},
+ {0, 0, 4},
+ {6, 0, 0},
+ };
+
+ runStats(5.0f, 0.1f, values, true, 5.0f);
+ runStats(4.5f, 0.6f, values, true, 5.0f);
+ runStats(5.5f, 0.6f, values, true, 5.0f);
+ runStats(4.5f, 0.1f, values, false, 5.0f);
+ runStats(5.5f, 0.1f, values, false, 5.0f);
+ }
+
+ private void runStats(float expected, float threshold, float[][] values, boolean pass, float magnitude) {
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(expected, threshold, values);
+ if (pass) {
+ verification.verify(stats);
+ } else {
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ }
+ assertEquals(pass, stats.getValue(MagnitudeVerification.PASSED_KEY));
+ assertEquals(magnitude, (Float) stats.getValue(SensorStats.MAGNITUDE_KEY), 0.01);
+ }
+
+ private ISensorVerification getVerification(float expected, float threshold,
+ float[] ... values) {
+ ISensorVerification verification = new MagnitudeVerification(expected, threshold);
+ for (float[] value : values) {
+ verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ }
+ return verification;
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java
new file mode 100644
index 0000000..315b3aa
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java
@@ -0,0 +1,148 @@
+/*
+ * 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 android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.cts.helpers.SensorStats;
+
+import junit.framework.Assert;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link ISensorVerification} which verifies that the means matches the expected measurement.
+ */
+public class MeanVerification extends AbstractMeanVerification {
+ public static final String PASSED_KEY = "mean_passed";
+
+ // sensorType: {expected, threshold}
+ private static final Map<Integer, Object[]> DEFAULTS = new HashMap<Integer, Object[]>(5);
+ static {
+ // Use a method so that the @deprecation warning can be set for that method only
+ setDefaults();
+ }
+
+ private final float[] mExpected;
+ private final float[] mThreshold;
+
+ /**
+ * Construct a {@link MeanVerification}
+ *
+ * @param expected the expected values
+ * @param threshold the thresholds
+ */
+ public MeanVerification(float[] expected, float[] threshold) {
+ mExpected = expected;
+ mThreshold = threshold;
+ }
+
+ /**
+ * Get the default {@link MeanVerification} for a sensor.
+ *
+ * @param sensor a {@link Sensor}
+ * @return the verification or null if the verification does not apply to the sensor.
+ */
+ public static MeanVerification getDefault(Sensor sensor) {
+ if (!DEFAULTS.containsKey(sensor.getType())) {
+ return null;
+ }
+ float[] expected = (float[]) DEFAULTS.get(sensor.getType())[0];
+ float[] threshold = (float[]) DEFAULTS.get(sensor.getType())[1];
+ return new MeanVerification(expected, threshold);
+ }
+
+ /**
+ * Verify that the mean is in the acceptable range. Add {@value #PASSED_KEY} and
+ * {@value SensorStats#MEAN_KEY} keys to {@link SensorStats}.
+ *
+ * @throws AssertionError if the verification failed.
+ */
+ @Override
+ public void verify(SensorStats stats) {
+ if (getCount() < 1) {
+ stats.addValue(PASSED_KEY, true);
+ return;
+ }
+
+ float[] means = getMeans();
+
+ boolean failed = false;
+ StringBuilder meanSb = new StringBuilder();
+ StringBuilder expectedSb = new StringBuilder();
+
+ if (means.length > 1) {
+ meanSb.append("(");
+ expectedSb.append("(");
+ }
+ for (int i = 0; i < means.length; i++) {
+ if (Math.abs(means[i] - mExpected[i]) > mThreshold[i]) {
+ failed = true;
+ }
+ meanSb.append(String.format("%.2f", means[i]));
+ if (i != means.length - 1) meanSb.append(", ");
+ expectedSb.append(String.format("%.2f+/-%.2f", mExpected[i], mThreshold[i]));
+ if (i != means.length - 1) expectedSb.append(", ");
+ }
+ if (means.length > 1) {
+ meanSb.append(")");
+ expectedSb.append(")");
+ }
+
+ stats.addValue(PASSED_KEY, !failed);
+ stats.addValue(SensorStats.MEAN_KEY, means);
+
+ if (failed) {
+ Assert.fail(String.format("Mean out of range: mean=%s, expected=%s", meanSb.toString(),
+ expectedSb.toString()));
+ }
+ }
+
+ @Override
+ public MeanVerification clone() {
+ return new MeanVerification(mExpected, mThreshold);
+ }
+
+ @SuppressWarnings("deprecation")
+ private static void setDefaults() {
+ // Sensors that we don't want to test at this time but still want to record the values.
+ // Gyroscope should be 0 for a static device
+ DEFAULTS.put(Sensor.TYPE_GYROSCOPE, new Object[]{
+ new float[]{0.0f, 0.0f, 0.0f},
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}});
+ // Pressure will not be exact in a controlled environment but should be relatively close to
+ // sea level. Second values should always be 0.
+ DEFAULTS.put(Sensor.TYPE_PRESSURE, new Object[]{
+ new float[]{SensorManager.PRESSURE_STANDARD_ATMOSPHERE, 0.0f, 0.0f},
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}});
+ // Linear acceleration should be 0 in all directions for a static device
+ DEFAULTS.put(Sensor.TYPE_LINEAR_ACCELERATION, new Object[]{
+ new float[]{0.0f, 0.0f, 0.0f},
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}});
+ // Game rotation vector should be (0, 0, 0, 1, 0) for a static device
+ DEFAULTS.put(Sensor.TYPE_GAME_ROTATION_VECTOR, new Object[]{
+ new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
+ Float.MAX_VALUE}});
+ // Uncalibrated gyroscope should be 0 for a static device but allow a bigger threshold
+ DEFAULTS.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, new Object[]{
+ new float[]{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
+ Float.MAX_VALUE, Float.MAX_VALUE}});
+ }
+}
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
new file mode 100644
index 0000000..94b6362
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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 android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link MeanVerification}.
+ */
+public class MeanVerificationTest extends TestCase {
+
+ /**
+ * Test {@link MeanVerification#verify(SensorStats)}.
+ */
+ public void testVerify() {
+ float[][] values = {
+ {0, 1, 0},
+ {1, 2, 1},
+ {2, 3, 4},
+ {3, 4, 9},
+ {4, 5, 16},
+ };
+
+ float[] expected = {2.0f, 3.0f, 6.0f};
+ float[] threshold = {0.1f, 0.1f, 0.1f};
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(expected, threshold, values);
+ verification.verify(stats);
+ verifyStats(stats, true, new float[]{2.0f, 3.0f, 6.0f});
+
+ expected = new float[]{2.5f, 2.5f, 5.5f};
+ threshold = new float[]{0.6f, 0.6f, 0.6f};
+ stats = new SensorStats();
+ verification = getVerification(expected, threshold, values);
+ verification.verify(stats);
+ verifyStats(stats, true, new float[]{2.0f, 3.0f, 6.0f});
+
+ expected = new float[]{2.5f, 2.5f, 5.5f};
+ threshold = new float[]{0.1f, 0.6f, 0.6f};
+ stats = new SensorStats();
+ verification = getVerification(expected, threshold, values);
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ verifyStats(stats, false, new float[]{2.0f, 3.0f, 6.0f});
+
+ expected = new float[]{2.5f, 2.5f, 5.5f};
+ threshold = new float[]{0.6f, 0.1f, 0.6f};
+ stats = new SensorStats();
+ verification = getVerification(expected, threshold, values);
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ verifyStats(stats, false, new float[]{2.0f, 3.0f, 6.0f});
+
+ threshold = new float[]{2.5f, 2.5f, 5.5f};
+ threshold = new float[]{0.6f, 0.6f, 0.1f};
+ stats = new SensorStats();
+ verification = getVerification(expected, threshold, values);
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ verifyStats(stats, false, new float[]{2.0f, 3.0f, 6.0f});
+ }
+
+ private ISensorVerification getVerification(float[] expected, float[] threshold,
+ float[] ... values) {
+ ISensorVerification verification = new MeanVerification(expected, threshold);
+ for (float[] value : values) {
+ verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ }
+ return verification;
+ }
+
+ private void verifyStats(SensorStats stats, boolean passed, float[] means) {
+ assertEquals(passed, stats.getValue(MeanVerification.PASSED_KEY));
+ float[] actual = (float[]) stats.getValue(SensorStats.MEAN_KEY);
+ for (int i = 0; i < means.length; i++) {
+ assertEquals(means[i], actual[i], 0.1);
+ }
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/SigNumVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/SigNumVerification.java
new file mode 100644
index 0000000..9417cd3
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/SigNumVerification.java
@@ -0,0 +1,124 @@
+/*
+ * 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 android.hardware.cts.helpers.SensorStats;
+
+import junit.framework.Assert;
+
+/**
+ * A {@link ISensorVerification} which verifies that the sign of each of the sensor values is
+ * correct.
+ * <p>
+ * If the value of the measurement is in [-threshold, threshold], the sign is considered 0. If
+ * it is less than -threshold, it is considered -1. If it is greater than threshold, it is
+ * considered 1.
+ * </p>
+ */
+public class SigNumVerification extends AbstractMeanVerification {
+ public static final String PASSED_KEY = "sig_num_passed";
+
+ private final int[] mExpected;
+ private final float[] mThreshold;
+
+ /**
+ * Construct a {@link SigNumVerification}
+ *
+ * @param expected the expected values
+ * @param threshold the threshold that needs to be crossed to consider a measurement nonzero
+ * @throws IllegalStateException if the expected values are not 0, -1, or 1.
+ */
+ public SigNumVerification(int[] expected, float[] threshold) {
+ for (int i = 0; i < expected.length; i++) {
+ if (!(expected[i] == -1 || expected[i] == 0 || expected[i] == 1)) {
+ throw new IllegalArgumentException("Expected value must be -1, 0, or 1");
+ }
+ }
+
+ mExpected = expected;
+ mThreshold = threshold;
+ }
+
+ /**
+ * Verify that the sign of each of the sensor values is correct. Add {@value #PASSED_KEY} and
+ * {@value SensorStats#MEAN_KEY} keys to {@link SensorStats}.
+ *
+ * @throws AssertionError if the verification failed.
+ */
+ @Override
+ public void verify(SensorStats stats) {
+ if (getCount() < 1) {
+ stats.addValue(PASSED_KEY, true);
+ return;
+ }
+
+ float[] means = getMeans();
+
+ boolean failed = false;
+ StringBuilder meanSb = new StringBuilder();
+ StringBuilder expectedSb = new StringBuilder();
+
+ if (means.length > 1) {
+ meanSb.append("(");
+ expectedSb.append("(");
+ }
+ for (int i = 0; i < means.length; i++) {
+ meanSb.append(String.format("%.2f", means[i]));
+ if (i != means.length - 1) meanSb.append(", ");
+
+ if (mExpected[i] == 0) {
+ if (Math.abs(means[i]) > mThreshold[i]) {
+ failed = true;
+ }
+ expectedSb.append(String.format("[%.2f, %.2f]", -mThreshold[i], mThreshold[i]));
+ } else {
+ if (mExpected[i] > 0) {
+ if (means[i] <= mThreshold[i]) {
+ failed = true;
+ }
+ expectedSb.append(String.format("(%.2f, inf)", mThreshold[i]));
+ } else {
+ if (means[i] >= -1 * mThreshold[i]) {
+ failed = true;
+ }
+ expectedSb.append(String.format("(-inf, %.2f)", -1 * mThreshold[i]));
+ }
+ }
+ if (i != means.length - 1) expectedSb.append(", ");
+ }
+ if (means.length > 1) {
+ meanSb.append(")");
+ expectedSb.append(")");
+ }
+
+ stats.addValue(PASSED_KEY, !failed);
+ stats.addValue(SensorStats.MEAN_KEY, means);
+
+ if (failed) {
+ Assert.fail(String.format("Signum out of range: mean=%s, expected=%s",
+ meanSb.toString(), expectedSb.toString()));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public SigNumVerification clone() {
+ return new SigNumVerification(mExpected, mThreshold);
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/SigNumVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/SigNumVerificationTest.java
new file mode 100644
index 0000000..009ab65
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/SigNumVerificationTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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 android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link SigNumVerification}.
+ */
+public class SigNumVerificationTest extends TestCase {
+
+ /**
+ * Test {@link SigNumVerification#verify(SensorStats)}.
+ */
+ public void testVerify() {
+ float[][] values = {{1.0f, 0.2f, 0.0f, -0.2f, -1.0f}};
+
+ int[] expected = {1, 1, 0, -1, -1};
+ float[] threshold = {0.1f, 0.1f, 0.1f, 0.1f, 0.1f};
+ runVerification(true, expected, threshold, values);
+
+ expected = new int[]{1, 0, 0, 0, -1};
+ threshold = new float[]{0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
+ runVerification(true, expected, threshold, values);
+
+ expected = new int[]{0, 1, 0, -1, 0};
+ threshold = new float[]{1.5f, 0.1f, 0.1f, 0.1f, 1.5f};
+ runVerification(true, expected, threshold, values);
+
+ expected = new int[]{1, 0, 0, 0, 1};
+ threshold = new float[]{0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
+ runVerification(false, expected, threshold, values);
+
+ expected = new int[]{-1, 0, 0, 0, -1};
+ threshold = new float[]{0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
+ runVerification(false, expected, threshold, values);
+ }
+
+ private SigNumVerification getVerification(int[] expected, float[] threshold,
+ float[] ... values) {
+ SigNumVerification verification = new SigNumVerification(expected, threshold);
+ for (float[] value : values) {
+ verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ }
+ return verification;
+ }
+
+ private void runVerification(boolean passed, int[] expected, float[] threshold,
+ float[][] values) {
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(expected, threshold, values);
+ if (passed) {
+ verification.verify(stats);
+ } else {
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ }
+ assertEquals(passed, stats.getValue(SigNumVerification.PASSED_KEY));
+ assertNotNull(stats.getValue(SensorStats.MEAN_KEY));
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java
new file mode 100644
index 0000000..03db067
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java
@@ -0,0 +1,186 @@
+/*
+ * 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 android.hardware.Sensor;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.Assert;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link ISensorVerification} which verifies that the standard deviations is within the expected
+ * range.
+ */
+public class StandardDeviationVerification extends AbstractSensorVerification {
+ public static final String PASSED_KEY = "standard_deviation_passed";
+
+ // sensorType: threshold
+ private static final Map<Integer, float[]> DEFAULTS = new HashMap<Integer, float[]>(12);
+ static {
+ // Use a method so that the @deprecation warning can be set for that method only
+ setDefaults();
+ }
+
+ private final float[] mThreshold;
+
+ private float[] mMeans = null;
+ private float[] mM2s = null;
+ private int mCount = 0;
+
+ /**
+ * Construct a {@link StandardDeviationVerification}
+ *
+ * @param threshold the thresholds
+ */
+ public StandardDeviationVerification(float[] threshold) {
+ mThreshold = threshold;
+ }
+
+ /**
+ * Get the default {@link StandardDeviationVerification} for a sensor.
+ *
+ * @param sensor a {@link Sensor}
+ * @return the verification or null if the verification does not apply to the sensor.
+ */
+ public static StandardDeviationVerification getDefault(Sensor sensor) {
+ if (!DEFAULTS.containsKey(sensor.getType())) {
+ return null;
+ }
+
+ return new StandardDeviationVerification(DEFAULTS.get(sensor.getType()));
+ }
+
+ /**
+ * Verify that the standard deviation is in the acceptable range. Add {@value #PASSED_KEY} and
+ * {@value SensorStats#STANDARD_DEVIATION_KEY} keys to {@link SensorStats}.
+ *
+ * @throws AssertionError if the verification failed.
+ */
+ @Override
+ public void verify(SensorStats stats) {
+ if (mCount < 2) {
+ stats.addValue(PASSED_KEY, true);
+ return;
+ }
+
+ float[] stdDevs = new float[mM2s.length];
+ for (int i = 0; i < mM2s.length; i++) {
+ stdDevs[i] = (float) Math.sqrt(mM2s[i] / (mCount - 1));
+ }
+
+ boolean failed = false;
+ StringBuilder stddevSb = new StringBuilder();
+ StringBuilder expectedSb = new StringBuilder();
+
+ if (stdDevs.length > 1) {
+ stddevSb.append("(");
+ expectedSb.append("(");
+ }
+ for (int i = 0; i < stdDevs.length; i++) {
+ if (stdDevs[i] > mThreshold[i]) {
+ failed = true;
+ }
+ stddevSb.append(String.format("%.2f", stdDevs[i]));
+ if (i != stdDevs.length - 1) stddevSb.append(", ");
+ expectedSb.append(String.format("<%.2f", mThreshold[i]));
+ if (i != stdDevs.length - 1) expectedSb.append(", ");
+ }
+ if (stdDevs.length > 1) {
+ stddevSb.append(")");
+ expectedSb.append(")");
+ }
+
+ stats.addValue(PASSED_KEY, !failed);
+ stats.addValue(SensorStats.STANDARD_DEVIATION_KEY, stdDevs);
+
+ if (failed) {
+ Assert.fail(String.format("Standard deviation out of range: stddev=%s, expected=%s",
+ stddevSb.toString(), expectedSb.toString()));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public StandardDeviationVerification clone() {
+ return new StandardDeviationVerification(mThreshold);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Computes the standard deviation using
+ * <a href="http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm">
+ * Welford's algorith</a>.
+ * </p>
+ */
+ @Override
+ protected void addSensorEventInternal(TestSensorEvent event) {
+ if (mMeans == null || mM2s == null) {
+ mMeans = new float[event.values.length];
+ mM2s = new float[event.values.length];
+ }
+
+ Assert.assertEquals(mMeans.length, event.values.length);
+ Assert.assertEquals(mM2s.length, event.values.length);
+
+ mCount++;
+
+ for (int i = 0; i < event.values.length; i++) {
+ float delta = event.values[i] - mMeans[i];
+ mMeans[i] += delta / mCount;
+ mM2s[i] += delta * (event.values[i] - mMeans[i]);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private static void setDefaults() {
+ DEFAULTS.put(Sensor.TYPE_ACCELEROMETER, new float[]{1.0f, 1.0f, 1.0f});
+ DEFAULTS.put(Sensor.TYPE_GYROSCOPE, new float[]{0.5f, 0.5f, 0.5f});
+ // Sensors that we don't want to test at this time but still want to record the values.
+ DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
+ DEFAULTS.put(Sensor.TYPE_ORIENTATION,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
+ DEFAULTS.put(Sensor.TYPE_PRESSURE,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
+ DEFAULTS.put(Sensor.TYPE_GRAVITY,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
+ DEFAULTS.put(Sensor.TYPE_LINEAR_ACCELERATION,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE});
+ DEFAULTS.put(Sensor.TYPE_ROTATION_VECTOR,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
+ Float.MAX_VALUE});
+ DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
+ Float.MAX_VALUE, Float.MAX_VALUE});
+ DEFAULTS.put(Sensor.TYPE_GAME_ROTATION_VECTOR,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
+ Float.MAX_VALUE});
+ DEFAULTS.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
+ Float.MAX_VALUE, Float.MAX_VALUE});
+ DEFAULTS.put(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR,
+ new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE,
+ Float.MAX_VALUE});
+ }
+}
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
new file mode 100644
index 0000000..0e5fb90
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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 android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEvent;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link StandardDeviationVerification}.
+ */
+public class StandardDeviationVerificationTest extends TestCase {
+
+ /**
+ * Test {@link StandardDeviationVerification#verify(SensorStats)}.
+ */
+ public void testVerify() {
+ // Stddev should be {sqrt(2.5), sqrt(2.5), sqrt(2.5)}
+ float[][] values = {
+ {0, 1, 0},
+ {1, 2, 2},
+ {2, 3, 4},
+ {3, 4, 6},
+ {4, 5, 8},
+ };
+ float[] standardDeviations = {
+ (float) Math.sqrt(2.5), (float) Math.sqrt(2.5), (float) Math.sqrt(10.0)
+ };
+
+ float[] threshold = {2, 2, 4};
+ runVerification(threshold, values, true, standardDeviations);
+
+ threshold = new float[]{1, 2, 4};
+ runVerification(threshold, values, false, standardDeviations);
+
+ threshold = new float[]{2, 1, 4};
+ runVerification(threshold, values, false, standardDeviations);
+
+ threshold = new float[]{2, 2, 3};
+ runVerification(threshold, values, false, standardDeviations);
+ }
+
+ private void runVerification(float[] threshold, float[][] values, boolean pass,
+ float[] standardDeviations) {
+ SensorStats stats = new SensorStats();
+ ISensorVerification verification = getVerification(threshold, values);
+ if (pass) {
+ verification.verify(stats);
+ } else {
+ try {
+ verification.verify(stats);
+ fail("Expected an AssertionError");
+ } catch (AssertionError e) {
+ // Expected;
+ }
+ }
+ assertEquals(pass, stats.getValue(StandardDeviationVerification.PASSED_KEY));
+ float[] actual = (float[]) stats.getValue(SensorStats.STANDARD_DEVIATION_KEY);
+ for (int i = 0; i < standardDeviations.length; i++) {
+ assertEquals(standardDeviations[i], actual[i], 0.1);
+ }
+ }
+
+ private ISensorVerification getVerification(float[] threshold, float[] ... values) {
+ ISensorVerification verification = new StandardDeviationVerification(threshold);
+ for (float[] value : values) {
+ verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ }
+ return verification;
+ }
+}