Refactor test framework for better verification

Code review was done in master with change-id:
I9f05df85f1becd95283d4b1db6dd6bc3345a12f1

Change-Id: Iba6ef7d3df5de99277727652436baab836448b97
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 df15b66..4bcdd56 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
@@ -89,7 +89,7 @@
     private void verifyMeasurements(
             String scenarioInstructions,
             boolean usePortraitOrientation,
-            double ... expectations) throws Throwable {
+            int ... expectations) throws Throwable {
         final String orientation = usePortraitOrientation ? "Portrait": "Landscape";
         appendText(String.format("\n[Device orientation]: %s", orientation));
         appendText(String.format("Press 'Next' and %s.", scenarioInstructions));
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 713710d..ffed1ab 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
@@ -21,7 +21,7 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorManager;
 import android.hardware.cts.helpers.SensorManagerTestVerifier;
-import android.hardware.cts.helpers.sensorTestOperations.VerifyNormOperation;
+import android.hardware.cts.helpers.sensorTestOperations.VerifyMagnitudeOperation;
 import android.hardware.cts.helpers.sensorTestOperations.VerifyStandardDeviationOperation;
 
 /**
@@ -91,7 +91,7 @@
                 (SensorManager.MAGNETIC_FIELD_EARTH_MAX + SensorManager.MAGNETIC_FIELD_EARTH_MIN) / 2;
         float magneticFieldEarthThreshold =
                 expectedMagneticFieldEarth - SensorManager.MAGNETIC_FIELD_EARTH_MIN;
-        VerifyNormOperation verifyNorm = new VerifyNormOperation(
+        VerifyMagnitudeOperation verifyNorm = new VerifyMagnitudeOperation(
                 this.getApplicationContext(),
                 Sensor.TYPE_MAGNETIC_FIELD,
                 SensorManager.SENSOR_DELAY_FASTEST,
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorMeasurementTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorMeasurementTests.java
index ea025ba..859b26d 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorMeasurementTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorMeasurementTests.java
@@ -24,7 +24,7 @@
 
 import android.hardware.cts.helpers.SensorTestCase;
 
-import android.hardware.cts.helpers.sensorTestOperations.VerifyNormOperation;
+import android.hardware.cts.helpers.sensorTestOperations.VerifyMagnitudeOperation;
 import android.hardware.cts.helpers.sensorTestOperations.VerifyStandardDeviationOperation;
 
 /**
@@ -104,7 +104,7 @@
      * - the values sampled from the sensor
      */
     public void testEventNorm() throws Throwable {
-        VerifyNormOperation operation = new VerifyNormOperation(
+        VerifyMagnitudeOperation operation = new VerifyMagnitudeOperation(
                 this.getContext(),
                 mSensorType,
                 mSamplingRateInUs,
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 c8733ba..9d860cd 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
@@ -16,65 +16,109 @@
 package android.hardware.cts.helpers;
 
 import android.content.Context;
-
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
-
 import android.os.Environment;
-
 import android.util.Log;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
-
 import java.text.SimpleDateFormat;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
-
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 /**
  * Set of static helper methods for CTS tests.
  */
 public class SensorCtsHelper {
+
     /**
-     * This is an static class.
+     * Private constructor for static class.
      */
     private SensorCtsHelper() {}
 
-    public static <TValue extends Comparable> TValue get95PercentileValue(
+    /**
+     * Get the value of the 95th percentile using nearest rank algorithm.
+     *
+     * @throws IllegalArgumentException if the collection is null or empty
+     */
+    public static <TValue extends Comparable<? super TValue>> TValue get95PercentileValue(
             Collection<TValue> collection) {
         validateCollection(collection);
 
-        ArrayList<TValue> arrayCopy = new ArrayList<TValue>(collection);
+        List<TValue> arrayCopy = new ArrayList<TValue>(collection);
         Collections.sort(arrayCopy);
 
         // zero-based array index
-        int arrayIndex = (int)(arrayCopy.size() * 0.95) - 1;
-        if(arrayIndex < 0) {
-            arrayIndex = 0;
-        }
+        int arrayIndex = (int) Math.round(arrayCopy.size() * 0.95 + .5) - 1;
 
         return arrayCopy.get(arrayIndex);
     }
 
     /**
      * Calculates the mean for each of the values in the set of TestSensorEvents.
+     *
+     * @throws IllegalArgumentException if there are no events
      */
-    public static void getMeans(TestSensorEvent events[], double means[]) {
-        for(TestSensorEvent event : events) {
-            for(int i = 0; i < means.length; ++i) {
+    public static double[] getMeans(TestSensorEvent[] events) {
+        if (events.length == 0) {
+            throw new IllegalArgumentException("Events cannot be empty");
+        }
+
+        double[] means = new double[events[0].values.length];
+        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) {
+        for (int i = 0; i < means.length; i++) {
             means[i] /= events.length;
         }
+        return means;
     }
 
+    /**
+     * Calculates the variance for each of the values in the set of TestSensorEvents.
+     *
+     * @throws IllegalArgumentException if there are no events
+     */
+    public static double[] getVariances(TestSensorEvent[] events) {
+        double[] means = getMeans(events);
+        double[] variances = new double[means.length];
+        for (int i = 0; i < means.length; i++) {
+            Collection<Double> squaredDiffs = new ArrayList<Double>(events.length);
+            for (TestSensorEvent event : events) {
+                double diff = event.values[i] - means[i];
+                squaredDiffs.add(diff * diff);
+            }
+            variances[i] = getMean(squaredDiffs);
+        }
+        return variances;
+    }
+
+    /**
+     * Calculates the standard deviation for each of the values in the set of TestSensorEvents.
+     *
+     * @throws IllegalArgumentException if there are no events
+     */
+    public static double[] getStandardDeviations(TestSensorEvent[] events) {
+        double[] variances = getVariances(events);
+        double[] stdDevs = new double[variances.length];
+        for (int i = 0; i < variances.length; i++) {
+            stdDevs[i] = Math.sqrt(variances[i]);
+        }
+        return stdDevs;
+    }
+
+    /**
+     * Calculate the mean of a collection.
+     *
+     * @throws IllegalArgumentException if the collection is null or empty
+     */
     public static <TValue extends Number> double getMean(Collection<TValue> collection) {
         validateCollection(collection);
 
@@ -85,6 +129,11 @@
         return sum / collection.size();
     }
 
+    /**
+     * Calculate the variance of a collection.
+     *
+     * @throws IllegalArgumentException if the collection is null or empty
+     */
     public static <TValue extends Number> double getVariance(Collection<TValue> collection) {
         validateCollection(collection);
 
@@ -95,58 +144,52 @@
             squaredDifferences.add(Math.pow(difference, 2));
         }
 
-        double variance = getMean(squaredDifferences);
-        return variance;
-    }
-
-    public static <TValue extends Number> double getStandardDeviation(Collection<TValue> collection) {
-        validateCollection(collection);
-
-        double variance = getVariance(collection);
-        return Math.sqrt(variance);
+        return getMean(squaredDifferences);
     }
 
     /**
-     * Gets the jitter values associated with a set of sensor events.
+     * Calculate the standard deviation of a collection.
      *
-     * @param events The events to use to obtain the jittering information.
-     * @param jitterValues The Collection that will contain the computed jitter values.
-     * @return The mean of the jitter Values.
+     * @throws IllegalArgumentException if the collection is null or empty
      */
-    public static double getJitterMean(TestSensorEvent events[], Collection<Double> jitterValues) {
-        ArrayList<Long> timestampDelayValues = new ArrayList<Long>();
-        double averageTimestampDelay = SensorCtsHelper.getAverageTimestampDelayWithValues(events,
-                timestampDelayValues);
-        for(long frequency : timestampDelayValues) {
-            jitterValues.add(Math.abs(averageTimestampDelay - frequency));
-        }
-
-        double jitterMean = SensorCtsHelper.getMean(timestampDelayValues);
-        return jitterMean;
+    public static <TValue extends Number> double getStandardDeviation(
+            Collection<TValue> collection) {
+        return Math.sqrt(getVariance(collection));
     }
 
     /**
-     * Gets the frequency values associated with a set of sensor events.
+     * Get a list containing the delay between sensor events.
      *
-     * @param events The events to use to obtain the frequency information.
-     * @param timestampDelayValues The Collection that will contain the computed frequency values.
-     * @return The mean of the frequency values.
+     * @param events The array of {@link TestSensorEvent}.
+     * @return A list containing the delay between sensor events in nanoseconds.
      */
-    public static double getAverageTimestampDelayWithValues(
-            TestSensorEvent events[],
-            Collection<Long> timestampDelayValues) {
-        for(int i = 1; i < events.length; ++i) {
-            long previousTimestamp = events[i-1].timestamp;
-            long timestamp = events[i].timestamp;
-            timestampDelayValues.add(timestamp - previousTimestamp);
+    public static List<Long> getTimestampDelayValues(TestSensorEvent[] events) {
+        if (events.length < 2) {
+            return new ArrayList<Long>();
         }
-
-        double timestampDelayMean = SensorCtsHelper.getMean(timestampDelayValues);
-        return timestampDelayMean;
+        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;
     }
 
-    public static int getSecondsAsMicroSeconds(int seconds) {
-        return (int) TimeUnit.MICROSECONDS.convert(seconds, TimeUnit.SECONDS);
+    /**
+     * 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;
     }
 
     /**
@@ -197,12 +240,11 @@
         return outputFile;
     }
 
+    /**
+     * Get the default sensor for a given type.
+     */
     public static Sensor getSensor(Context context, int sensorType) {
-        SensorManager sensorManager = (SensorManager)context.getSystemService(
-                Context.SENSOR_SERVICE);
-        if(sensorManager == null) {
-            throw new IllegalStateException("SensorService is not present in the system.");
-        }
+        SensorManager sensorManager = getSensorManager(context);
         Sensor sensor = sensorManager.getDefaultSensor(sensorType);
         if(sensor == null) {
             throw new SensorNotSupportedException(sensorType);
@@ -210,10 +252,48 @@
         return sensor;
     }
 
-    public static <TReference extends Number> double getFrequencyInHz(TReference samplingRateInUs) {
-        return 1000000000 / samplingRateInUs.doubleValue();
+    /**
+     * Get all the sensors for a given type.
+     */
+    public static List<Sensor> getSensors(Context context, int sensorType) {
+        SensorManager sensorManager = getSensorManager(context);
+        List<Sensor> sensors = sensorManager.getSensorList(sensorType);
+        if (sensors.size() == 0) {
+            throw new SensorNotSupportedException(sensorType);
+        }
+        return sensors;
     }
 
+    /**
+     * Convert a period to frequency in Hz.
+     */
+    public static <TValue extends Number> double getFrequency(TValue period, TimeUnit unit) {
+        return 1000000000 / (TimeUnit.NANOSECONDS.convert(1, unit) * period.doubleValue());
+    }
+
+    /**
+     * Convert a frequency in Hz into a period.
+     */
+    public static <TValue extends Number> double getPeriod(TValue frequency, TimeUnit unit) {
+        return 1000000000 / (TimeUnit.NANOSECONDS.convert(1, unit) * frequency.doubleValue());
+    }
+
+    /**
+     * Convert number of seconds to number of microseconds.
+     */
+    public static int getSecondsAsMicroSeconds(int seconds) {
+        return (int) TimeUnit.MICROSECONDS.convert(seconds, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Format an assertion message.
+     *
+     * @param verificationName The verification name
+     * @param sensor The sensor under test
+     * @param format The additional format string, use "" if blank
+     * @param params The additional format params
+     * @return The formatted string.
+     */
     public static String formatAssertionMessage(
             String verificationName,
             Sensor sensor,
@@ -222,6 +302,16 @@
         return formatAssertionMessage(verificationName, null, sensor, format, params);
     }
 
+    /**
+     * Format an assertion message.
+     *
+     * @param verificationName The verification name
+     * @param test The test, optional
+     * @param sensor The sensor under test
+     * @param format The additional format string, use "" if blank
+     * @param params The additional format params
+     * @return The formatted string.
+     */
     public static String formatAssertionMessage(
             String verificationName,
             SensorTestOperation test,
@@ -239,8 +329,7 @@
             builder.append("| ");
         }
         // add context information
-        builder.append(
-                SensorTestInformation.getSensorName(sensor.getType()));
+        builder.append(SensorTestInformation.getSensorName(sensor.getType()));
         builder.append(", handle:");
         builder.append(sensor.getHandle());
         builder.append("| ");
@@ -251,11 +340,27 @@
     }
 
     /**
-     * Private helpers
+     * Validate that a collection is not null or empty.
+     *
+     * @throws IllegalStateException if collection is null or empty.
      */
-    private static void validateCollection(Collection collection) {
+    private static <T> void validateCollection(Collection<T> collection) {
         if(collection == null || collection.size() == 0) {
             throw new IllegalStateException("Collection cannot be null or empty");
         }
     }
+
+    /**
+     * Get the SensorManager.
+     *
+     * @throws IllegalStateException if the SensorManager is not present in the system.
+     */
+    private static SensorManager getSensorManager(Context context) {
+        SensorManager sensorManager = (SensorManager) context.getSystemService(
+                Context.SENSOR_SERVICE);
+        if(sensorManager == null) {
+            throw new IllegalStateException("SensorService is not present in the system.");
+        }
+        return sensorManager;
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelperTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelperTest.java
new file mode 100644
index 0000000..ccfaf2a
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelperTest.java
@@ -0,0 +1,266 @@
+/*
+ * 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 junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Unit tests for the {@link SensorCtsHelper} class.
+ */
+public class SensorCtsHelperTest extends TestCase {
+
+    /**
+     * Test {@link SensorCtsHelper#get95PercentileValue(Collection)}.
+     */
+    public void testGet95PercentileValue() {
+        Collection<Integer> values = new HashSet<Integer>();
+        for (int i = 0; i < 100; i++) {
+            values.add(i);
+        }
+        assertEquals(95, (int) SensorCtsHelper.get95PercentileValue(values));
+
+        values = new HashSet<Integer>();
+        for (int i = 0; i < 1000; i++) {
+            values.add(i);
+        }
+        assertEquals(950, (int) SensorCtsHelper.get95PercentileValue(values));
+
+        values = new HashSet<Integer>();
+        for (int i = 0; i < 100; i++) {
+            values.add(i * i);
+        }
+        assertEquals(95 * 95, (int) SensorCtsHelper.get95PercentileValue(values));
+    }
+
+    /**
+     * Test {@link SensorCtsHelper#getMeans(TestSensorEvent[])}.
+     */
+    public void testGetMeans() {
+        long[] timestamps = {0, 1, 2, 3, 4};
+
+        float[] values = {0, 1, 2, 3, 4};  // 2.0
+        double[] 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.0
+        double[] variances = SensorCtsHelper.getVariances(getSensorEvents(timestamps, values));
+        assertEquals(1, variances.length);
+        assertEquals(2.0, variances[0], 0.00001);
+
+        float[] values1 = {0, 1, 2, 3, 4};  // 2.0
+        float[] values2 = {1, 2, 3, 4, 5};  // 2.0
+        float[] values3 = {0, 2, 4, 6, 8};  // 8.0
+        variances = SensorCtsHelper.getVariances(
+                getSensorEvents(timestamps, values1, values2, values3));
+        assertEquals(3, variances.length);
+        assertEquals(2.0, variances[0], 0.00001);
+        assertEquals(2.0, variances[1], 0.00001);
+        assertEquals(8.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.0)
+        double[] stddev = SensorCtsHelper.getStandardDeviations(
+                getSensorEvents(timestamps, values));
+        assertEquals(1, stddev.length);
+        assertEquals(Math.sqrt(2.0), stddev[0], 0.00001);
+
+        float[] values1 = {0, 1, 2, 3, 4};  // sqrt(2.0)
+        float[] values2 = {1, 2, 3, 4, 5};  // sqrt(2.0)
+        float[] values3 = {0, 2, 4, 6, 8};  // sqrt(8.0)
+        stddev = SensorCtsHelper.getStandardDeviations(
+                getSensorEvents(timestamps, values1, values2, values3));
+        assertEquals(3, stddev.length);
+        assertEquals(Math.sqrt(2.0), stddev[0], 0.00001);
+        assertEquals(Math.sqrt(2.0), stddev[1], 0.00001);
+        assertEquals(Math.sqrt(8.0), stddev[2], 0.00001);
+    }
+
+    /**
+     * Test {@link SensorCtsHelper#getMean(Collection)}.
+     */
+    public void testGetMean() {
+        List<Integer> values = Arrays.asList(0, 1, 2, 3, 4);
+        double mean = SensorCtsHelper.getMean(values);
+        assertEquals(2.0, mean, 0.00001);
+
+        values = Arrays.asList(1, 2, 3, 4, 5);
+        mean = SensorCtsHelper.getMean(values);
+        assertEquals(3.0, mean, 0.00001);
+
+        values = Arrays.asList(0, 1, 4, 9, 16);
+        mean = SensorCtsHelper.getMean(values);
+        assertEquals(6.0, mean, 0.00001);
+    }
+
+    /**
+     * Test {@link SensorCtsHelper#getVariance(Collection)}.
+     */
+    public void testGetVariance() {
+        List<Integer> values = Arrays.asList(0, 1, 2, 3, 4);
+        double variance = SensorCtsHelper.getVariance(values);
+        assertEquals(2.0, variance, 0.00001);
+
+        values = Arrays.asList(1, 2, 3, 4, 5);
+        variance = SensorCtsHelper.getVariance(values);
+        assertEquals(2.0, variance, 0.00001);
+
+        values = Arrays.asList(0, 2, 4, 6, 8);
+        variance = SensorCtsHelper.getVariance(values);
+        assertEquals(8.0, variance, 0.00001);
+    }
+
+    /**
+     * Test {@link SensorCtsHelper#getStandardDeviation(Collection)}.
+     */
+    public void testGetStandardDeviation() {
+        List<Integer> values = Arrays.asList(0, 1, 2, 3, 4);
+        double stddev = SensorCtsHelper.getStandardDeviation(values);
+        assertEquals(Math.sqrt(2.0), stddev, 0.00001);
+
+        values = Arrays.asList(1, 2, 3, 4, 5);
+        stddev = SensorCtsHelper.getStandardDeviation(values);
+        assertEquals(Math.sqrt(2.0), stddev, 0.00001);
+
+        values = Arrays.asList(0, 2, 4, 6, 8);
+        stddev = SensorCtsHelper.getStandardDeviation(values);
+        assertEquals(Math.sqrt(8.0), stddev, 0.00001);
+    }
+
+    /**
+     * 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() {
+        assertEquals(1.0, SensorCtsHelper.getFrequency(1, TimeUnit.SECONDS), 0.001);
+        assertEquals(10.0, SensorCtsHelper.getFrequency(0.1, TimeUnit.SECONDS), 0.001);
+        assertEquals(10.0, SensorCtsHelper.getFrequency(100, TimeUnit.MILLISECONDS), 0.001);
+        assertEquals(1000.0, SensorCtsHelper.getFrequency(1, TimeUnit.MILLISECONDS), 0.001);
+        assertEquals(10000.0, SensorCtsHelper.getFrequency(0.1, TimeUnit.MILLISECONDS), 0.001);
+        assertEquals(10000.0, SensorCtsHelper.getFrequency(100, TimeUnit.MICROSECONDS), 0.001);
+        assertEquals(1000000.0, SensorCtsHelper.getFrequency(1, TimeUnit.MICROSECONDS), 0.001);
+        assertEquals(10000000.0, SensorCtsHelper.getFrequency(0.1, TimeUnit.MICROSECONDS), 0.001);
+        assertEquals(10000000.0, SensorCtsHelper.getFrequency(100, TimeUnit.NANOSECONDS), 0.001);
+        assertEquals(1000000000.0, SensorCtsHelper.getFrequency(1, TimeUnit.NANOSECONDS), 0.001);
+    }
+
+    /**
+     * Test {@link SensorCtsHelper#getPeriod(Number, TimeUnit)}.
+     */
+    public void testGetPeriod() {
+        assertEquals(1.0, SensorCtsHelper.getPeriod(1, TimeUnit.SECONDS), 0.001);
+        assertEquals(0.1, SensorCtsHelper.getPeriod(10, TimeUnit.SECONDS), 0.001);
+        assertEquals(100, SensorCtsHelper.getPeriod(10, TimeUnit.MILLISECONDS), 0.001);
+        assertEquals(1, SensorCtsHelper.getPeriod(1000, TimeUnit.MILLISECONDS), 0.001);
+        assertEquals(0.1, SensorCtsHelper.getPeriod(10000, TimeUnit.MILLISECONDS), 0.001);
+        assertEquals(100, SensorCtsHelper.getPeriod(10000, TimeUnit.MICROSECONDS), 0.001);
+        assertEquals(1, SensorCtsHelper.getPeriod(1000000, TimeUnit.MICROSECONDS), 0.001);
+        assertEquals(0.1, SensorCtsHelper.getPeriod(10000000, TimeUnit.MICROSECONDS), 0.001);
+        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/SensorManagerTestVerifier.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorManagerTestVerifier.java
index 6e8b758..85f4f0e 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorManagerTestVerifier.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorManagerTestVerifier.java
@@ -17,25 +17,23 @@
 package android.hardware.cts.helpers;
 
 import android.content.Context;
-
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener2;
 import android.hardware.SensorManager;
 
-import java.io.Closeable;
+import junit.framework.Assert;
 
+import java.io.Closeable;
 import java.security.InvalidParameterException;
 import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import junit.framework.Assert;
-
 /**
  * Test class to wrap SensorManager with verifications and test checks.
  * This class allows to perform operations in the Sensor Manager and performs all the expected test
- * verification on behalf of th owner.
+ * verification on behalf of the owner.
  * An object can be used to quickly writing tests that focus on the scenario that needs to be
  * verified, and not in the implicit verifications that need to take place at any step.
  */
@@ -66,30 +64,52 @@
     }
 
     /**
-     * Public listeners for Sensor events, these are available for subclasses to implement if they
-     * need access to the raw eventing model.
+     * {@inheritDoc}
+     * <p>
+     * Available for subclasses to implement if they need access to the raw eventing model.
+     * </p>
      */
     @Override
     public void onAccuracyChanged(Sensor sensor, int accuracy) {}
 
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Available for subclasses to implement if they need access to the raw eventing model.
+     * </p>
+     */
     @Override
     public void onSensorChanged(SensorEvent event) {}
 
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Available for subclasses to implement if they need access to the raw eventing model.
+     * </p>
+     */
     @Override
     public void onFlushCompleted(Sensor sensor) {}
 
     /**
-     * Members
+     * Closes the {@link SensorManagerTestVerifier} and unregister the listener.
      */
+    @Override
     public void close() {
         this.unregisterListener();
         mEventListener = null;
     }
 
+    /**
+     * Get the sensor under test.
+     */
     public Sensor getUnderlyingSensor() {
         return mSensorUnderTest;
     }
 
+    /**
+     * Register the
+     * @param debugInfo
+     */
     public void registerListener(String debugInfo) {
         boolean result = mSensorManager.registerListener(
                 mEventListener,
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelper.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelper.java
new file mode 100644
index 0000000..d1013e0
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelper.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2013 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.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Set of static helper methods to verify sensor CTS tests.
+ */
+public class SensorVerificationHelper {
+
+    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 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("count", indices.size());
+        result.putValue("positions", 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 threshold The acceptable margin of error in Hz
+     * @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 threshold) {
+        VerificationResult result = new VerificationResult();
+        List<Long> timestampDelayValues = SensorCtsHelper.getTimestampDelayValues(events);
+        double frequency = SensorCtsHelper.getFrequency(
+                SensorCtsHelper.getMean(timestampDelayValues), TimeUnit.NANOSECONDS);
+        result.putValue("frequency", frequency);
+
+        if (Math.abs(frequency - expected) > threshold) {
+            result.fail("Frequency out of range: frequency=%.2fHz, expected=%.2f+/-%.2fHz",
+                    frequency, expected, threshold);
+        }
+        return result;
+    }
+
+    /**
+     * Verify that the jitter is in an acceptable range
+     *
+     * @param events The array of {@link TestSensorEvent}
+     * @param threshold The acceptable margin of error in nanoseconds
+     * @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, double threshold) {
+        VerificationResult result = new VerificationResult();
+        List<Double> jitterValues = SensorCtsHelper.getJitterValues(events);
+        double jitter95Percentile = SensorCtsHelper.get95PercentileValue(jitterValues);
+        result.putValue("jitter", jitterValues);
+        result.putValue("jitter95Percentile", jitter95Percentile);
+
+        if (jitter95Percentile > threshold) {
+            result.fail("Jitter out of range: jitter at 95th percentile=%.0fns, expected=<%.0fns",
+                    jitter95Percentile, threshold);
+        }
+        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, double[] expected,
+            double[] threshold) {
+        VerificationResult result = new VerificationResult();
+        double[] means = SensorCtsHelper.getMeans(events);
+        result.putValue("means", 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 && !failed; 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, double expected,
+            double threshold) {
+        VerificationResult result = new VerificationResult();
+        Collection<Double> magnitudes = new ArrayList<Double>(events.length);
+
+        for (TestSensorEvent event : events) {
+            double norm = 0;
+            for (int i = 0; i < event.values.length; i++) {
+                norm += event.values[i] * event.values[i];
+            }
+            magnitudes.add(Math.sqrt(norm));
+        }
+
+        double mean = SensorCtsHelper.getMean(magnitudes);
+        result.putValue("magnitude", 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,
+            double[] 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");
+            }
+        }
+        double[] means = SensorCtsHelper.getMeans(events);
+        result.putValue("means", 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,
+            double[] threshold) {
+        VerificationResult result = new VerificationResult();
+        double[] standardDeviations = SensorCtsHelper.getStandardDeviations(events);
+        result.putValue("stddevs", standardDeviations);
+
+        boolean failed = false;
+        StringBuilder meanSb = new StringBuilder();
+        StringBuilder expectedSb = new StringBuilder();
+
+        if (standardDeviations.length > 1) {
+            meanSb.append("(");
+            expectedSb.append("(");
+        }
+        for (int i = 0; i < standardDeviations.length && !failed; i++) {
+            if (standardDeviations[i] > threshold[i]) {
+                failed = true;
+            }
+            meanSb.append(String.format("%.2f", standardDeviations[i]));
+            if (i != standardDeviations.length - 1) meanSb.append(", ");
+            expectedSb.append(String.format("0+/-%.2f", threshold[i]));
+            if (i != standardDeviations.length - 1) expectedSb.append(", ");
+        }
+        if (standardDeviations.length > 1) {
+            meanSb.append(")");
+            expectedSb.append(")");
+        }
+
+        if (failed) {
+            result.fail("Standard deviation out of range: mean=%s, expected=%s",
+                    meanSb.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
new file mode 100644
index 0000000..94ea57d
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorVerificationHelperTest.java
@@ -0,0 +1,284 @@
+/*
+ * 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("count"));
+
+        long[] timestamps2 = {0, 1, 2, 3, 4};
+        TestSensorEvent[] events2 = getSensorEvents(timestamps2, values);
+        result = SensorVerificationHelper.verifyEventOrdering(events2);
+        assertFalse(result.isFailed());
+        assertEquals(0, result.getValue("count"));
+
+        long[] timestamps3 = {0, 2, 1, 3, 4};
+        TestSensorEvent[] events3 = getSensorEvents(timestamps3, values);
+        result = SensorVerificationHelper.verifyEventOrdering(events3);
+        assertTrue(result.isFailed());
+        assertEquals(1, result.getValue("count"));
+        List<Integer> indices = (List<Integer>) result.getValue("positions");
+        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("count"));
+        indices = (List<Integer>) result.getValue("positions");
+        assertTrue(indices.contains(1));
+        assertTrue(indices.contains(2));
+        assertTrue(indices.contains(3));
+        assertTrue(indices.contains(4));
+    }
+
+    /**
+     * Test {@link SensorVerificationHelper#verifyFrequency(TestSensorEvent[], 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);
+        assertFalse(result.isFailed());
+        assertEquals(1000.0, (Double) result.getValue("frequency"), 0.01);
+
+        result = SensorVerificationHelper.verifyFrequency(events, 950.0, 100.0);
+        assertFalse(result.isFailed());
+        assertEquals(1000.0, (Double) result.getValue("frequency"), 0.01);
+
+        result = SensorVerificationHelper.verifyFrequency(events, 1050.0, 100.0);
+        assertFalse(result.isFailed());
+        assertEquals(1000.0, (Double) result.getValue("frequency"), 0.01);
+
+        result = SensorVerificationHelper.verifyFrequency(events, 950.0, 25.0);
+        assertTrue(result.isFailed());
+        assertEquals(1000.0, (Double) result.getValue("frequency"), 0.01);
+    }
+
+    /**
+     * Test {@link SensorVerificationHelper#verifyJitter(TestSensorEvent[], double)}.
+     */
+    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, 100000);
+        assertFalse(result.isFailed());
+        assertEquals(0.0, (Double) result.getValue("jitter95Percentile"), 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, 100000);
+        assertTrue(result.isFailed());
+        assertNotNull(result.getValue("jitter"));
+        assertNotNull(result.getValue("jitter95Percentile"));
+    }
+
+    /**
+     * Test {@link SensorVerificationHelper#verifyMean(TestSensorEvent[], double[], double[])}.
+     */
+    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);
+
+        double[] expected1 = {2.0, 3.0, 6.0};
+        double[] threshold1 = {0.1, 0.1, 0.1};
+        VerificationResult result = SensorVerificationHelper.verifyMean(events, expected1,
+                threshold1);
+        assertFalse(result.isFailed());
+        double[] means = (double[]) result.getValue("means");
+        assertEquals(2.0, means[0], 0.01);
+        assertEquals(3.0, means[1], 0.01);
+        assertEquals(6.0, means[2], 0.01);
+
+        double[] expected2 = {2.5, 2.5, 5.5};
+        double[] threshold2 = {0.6, 0.6, 0.6};
+        result = SensorVerificationHelper.verifyMean(events, expected2, threshold2);
+        assertFalse(result.isFailed());
+
+        double[] expected3 = {2.5, 2.5, 5.5};
+        double[] threshold3 = {0.1, 0.6, 0.6};
+        result = SensorVerificationHelper.verifyMean(events, expected3, threshold3);
+        assertTrue(result.isFailed());
+
+        double[] expected4 = {2.5, 2.5, 5.5};
+        double[] threshold4 = {0.6, 0.1, 0.6};
+        result = SensorVerificationHelper.verifyMean(events, expected4, threshold4);
+        assertTrue(result.isFailed());
+
+        double[] expected5 = {2.5, 2.5, 5.5};
+        double[] threshold5 = {0.6, 0.6, 0.1};
+        result = SensorVerificationHelper.verifyMean(events, expected5, threshold5);
+        assertTrue(result.isFailed());
+    }
+
+    /**
+     * Test {@link SensorVerificationHelper#verifyMagnitude(TestSensorEvent[], double, double)}.
+     */
+    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);
+
+        double expected = 5.0;
+        double threshold = 0.1;
+        VerificationResult result = SensorVerificationHelper.verifyMagnitude(events, expected,
+                threshold);
+        assertFalse(result.isFailed());
+        assertEquals(5.0, (Double) result.getValue("norm"), 0.01);
+
+        expected = 4.5;
+        threshold = 0.6;
+        result = SensorVerificationHelper.verifyMagnitude(events, expected, threshold);
+        assertFalse(result.isFailed());
+
+        expected = 5.5;
+        threshold = 0.6;
+        result = SensorVerificationHelper.verifyMagnitude(events, expected, threshold);
+        assertFalse(result.isFailed());
+
+        expected = 4.5;
+        threshold = 0.1;
+        result = SensorVerificationHelper.verifyMagnitude(events, expected, threshold);
+        assertTrue(result.isFailed());
+
+        expected = 5.5;
+        threshold = 0.1;
+        result = SensorVerificationHelper.verifyMagnitude(events, expected, threshold);
+        assertTrue(result.isFailed());
+    }
+
+    /**
+     * Test {@link SensorVerificationHelper#verifySignum(TestSensorEvent[], int[], double[])}.
+     */
+    public void testVerifySignum() {
+        long[] timestamps = {0};
+        float[][] values = {{1}, {0.2f}, {0}, {-0.2f}, {-1}};
+        TestSensorEvent[] events = getSensorEvents(timestamps, values);
+
+        int[] expected1 = {1, 1, 0, -1, -1};
+        double[] threshold1 = {0.1, 0.1, 0.1, 0.1, 0.1};
+        VerificationResult result = SensorVerificationHelper.verifySignum(events, expected1,
+                threshold1);
+        assertFalse(result.isFailed());
+        assertNotNull(result.getValue("means"));
+
+        int[] expected2 = {1, 0, 0, 0, -1};
+        double[] threshold2 = {0.5, 0.5, 0.5, 0.5, 0.5};
+        result = SensorVerificationHelper.verifySignum(events, expected2, threshold2);
+        assertFalse(result.isFailed());
+
+        int[] expected3 = {0, 1, 0, -1, 0};
+        double[] threshold3 = {1.5, 0.1, 0.1, 0.1, 1.5};
+        result = SensorVerificationHelper.verifySignum(events, expected3, threshold3);
+        assertFalse(result.isFailed());
+
+        int[] expected4 = {1, 0, 0, 0, 1};
+        double[] threshold4 = {0.5, 0.5, 0.5, 0.5, 0.5};
+        result = SensorVerificationHelper.verifySignum(events, expected4, threshold4);
+        assertTrue(result.isFailed());
+
+        int[] expected5 = {-1, 0, 0, 0, -1};
+        double[] threshold5 = {0.5, 0.5, 0.5, 0.5, 0.5};
+        result = SensorVerificationHelper.verifySignum(events, expected5, threshold5);
+        assertTrue(result.isFailed());
+    }
+
+    /**
+     * Test {@link SensorVerificationHelper#verifyStandardDeviation(TestSensorEvent[], double[])}.
+     */
+    public void testVerifyStandardDeviation() {
+        long[] timestamps = {0, 1, 2, 3, 4};
+        float[] values1 = {0, 1, 2, 3, 4};  // sqrt(2.0)
+        float[] values2 = {1, 2, 3, 4, 5};  // sqrt(2.0)
+        float[] values3 = {0, 2, 4, 6, 8};  // sqrt(8.0)
+        TestSensorEvent[] events = getSensorEvents(timestamps, values1, values2, values3);
+
+        double[] threshold1 = {2, 2, 3};
+        VerificationResult result = SensorVerificationHelper.verifyStandardDeviation(events,
+                threshold1);
+        assertFalse(result.isFailed());
+        double[] means = (double[]) result.getValue("stddevs");
+        assertEquals(Math.sqrt(2.0), means[0], 0.01);
+        assertEquals(Math.sqrt(2.0), means[1], 0.01);
+        assertEquals(Math.sqrt(8.0), means[2], 0.01);
+
+        double[] threshold2 = {1, 2, 3};
+        result = SensorVerificationHelper.verifyStandardDeviation(events, threshold2);
+        assertTrue(result.isFailed());
+
+        double[] threshold3 = {2, 1, 3};
+        result = SensorVerificationHelper.verifyStandardDeviation(events, threshold3);
+        assertTrue(result.isFailed());
+
+        double[] threshold4 = {2, 2, 2};
+        result = SensorVerificationHelper.verifyStandardDeviation(events, threshold4);
+        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 1a2cdfe..48bc1d3 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
@@ -38,4 +38,14 @@
         timestamp = event.timestamp;
         accuracy = event.accuracy;
     }
+
+    /**
+     * Constructor for TestSensorEvent. Exposed for unit testing.
+     */
+    protected TestSensorEvent(Sensor sensor, long timestamp, int accuracy, float[] values) {
+        this.sensor = sensor;
+        this.timestamp = timestamp;
+        this.accuracy = accuracy;
+        this.values = values;
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyEventOrderingOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyEventOrderingOperation.java
index bb43b01..03d0f9af 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyEventOrderingOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyEventOrderingOperation.java
@@ -16,15 +16,16 @@
 
 package android.hardware.cts.helpers.sensorTestOperations;
 
-import junit.framework.Assert;
-
 import android.content.Context;
-
 import android.hardware.cts.helpers.SensorCtsHelper;
 import android.hardware.cts.helpers.SensorManagerTestVerifier;
 import android.hardware.cts.helpers.SensorTestOperation;
+import android.hardware.cts.helpers.SensorVerificationHelper;
+import android.hardware.cts.helpers.SensorVerificationHelper.VerificationResult;
 import android.hardware.cts.helpers.TestSensorEvent;
 
+import junit.framework.Assert;
+
 /**
  * Test Operation class that validates the ordering of sensor events.
  */
@@ -45,23 +46,14 @@
 
     @Override
     public void doWork() {
-        TestSensorEvent events[] = mSensor.collectEvents(100);
-        for(int i = 1; i < events.length; ++i) {
-            long previousTimestamp = events[i-1].timestamp;
-            long timestamp = events[i].timestamp;
-            // allow two identical timestamps to be considered in order, in case the resolution of
-            // the timestamp is not granular enough
-            if(previousTimestamp > timestamp) {
-                String message = SensorCtsHelper.formatAssertionMessage(
-                        "Ordering",
-                        this,
-                        mSensor.getUnderlyingSensor(),
-                        "position:%d, previous:%d, timestamp:%d",
-                        i,
-                        previousTimestamp,
-                        timestamp);
-                Assert.fail(message);
-            }
+        TestSensorEvent[] events = mSensor.collectEvents(100);
+        VerificationResult result = SensorVerificationHelper.verifyEventOrdering(events);
+        if (result.isFailed()) {
+            Assert.fail(SensorCtsHelper.formatAssertionMessage(
+                    "Ordering",
+                    this,
+                    mSensor.getUnderlyingSensor(),
+                    result.getFailureMessage()));
         }
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyJitteringOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyJitteringOperation.java
index 6f1c03a..303dc9b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyJitteringOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyJitteringOperation.java
@@ -16,21 +16,18 @@
 
 package android.hardware.cts.helpers.sensorTestOperations;
 
-import junit.framework.Assert;
-
 import android.content.Context;
 import android.hardware.cts.helpers.SensorCtsHelper;
 import android.hardware.cts.helpers.SensorManagerTestVerifier;
 import android.hardware.cts.helpers.SensorTestInformation;
 import android.hardware.cts.helpers.SensorTestOperation;
+import android.hardware.cts.helpers.SensorVerificationHelper;
+import android.hardware.cts.helpers.SensorVerificationHelper.VerificationResult;
 import android.hardware.cts.helpers.TestSensorEvent;
 
-import android.util.Log;
+import junit.framework.Assert;
 
 import java.security.InvalidParameterException;
-
-import java.util.ArrayList;
-
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -71,26 +68,14 @@
 
     @Override
     public void doWork() {
-        TestSensorEvent events[] = mSensor.collectEvents(100);
-        ArrayList<Double> jitterValues = new ArrayList<Double>();
-        double jitterMean = SensorCtsHelper.getJitterMean(events, jitterValues);
-        double percentile95InNs = SensorCtsHelper.get95PercentileValue(jitterValues);
-
-        if(percentile95InNs > mThresholdInNs) {
-            for(double jitter : jitterValues) {
-                Log.e(LOG_TAG, "Jitter: " + jitter);
-            }
-            double actualPercentValue = (percentile95InNs * 100) / jitterMean;
-            String message = SensorCtsHelper.formatAssertionMessage(
-                    "Jitter(95%%ile)",
+        TestSensorEvent[] events = mSensor.collectEvents(100);
+        VerificationResult result = SensorVerificationHelper.verifyJitter(events, mThresholdInNs);
+        if (result.isFailed()) {
+            Assert.fail(SensorCtsHelper.formatAssertionMessage(
+                    "Jitter(95%ile)",
                     this,
                     mSensor.getUnderlyingSensor(),
-                    "expected:%dns(%d%%), actual:%fns(%.2f%%)",
-                    mThresholdInNs,
-                    mThresholdPercentage,
-                    percentile95InNs,
-                    actualPercentValue);
-            Assert.fail(message);
+                    result.getFailureMessage()));
         }
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyNormOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMagnitudeOperation.java
similarity index 67%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyNormOperation.java
rename to tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMagnitudeOperation.java
index cce3412..cbcff6a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyNormOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMagnitudeOperation.java
@@ -16,27 +16,28 @@
 
 package android.hardware.cts.helpers.sensorTestOperations;
 
-import junit.framework.Assert;
-
 import android.content.Context;
-
 import android.hardware.cts.helpers.SensorCtsHelper;
 import android.hardware.cts.helpers.SensorManagerTestVerifier;
 import android.hardware.cts.helpers.SensorTestInformation;
 import android.hardware.cts.helpers.SensorTestOperation;
+import android.hardware.cts.helpers.SensorVerificationHelper;
+import android.hardware.cts.helpers.SensorVerificationHelper.VerificationResult;
 import android.hardware.cts.helpers.TestSensorEvent;
 
+import junit.framework.Assert;
+
 /**
  * Test Operation class that validates the norm of a given sensor.
  * The operation relies in the number of axes each sensor type reports.
  */
-public class VerifyNormOperation extends SensorTestOperation {
+public class VerifyMagnitudeOperation extends SensorTestOperation {
     private SensorManagerTestVerifier mSensor;
     private int mAxisCount;
     private double mReferenceValue;
     private double mThreshold;
 
-    public VerifyNormOperation(
+    public VerifyMagnitudeOperation(
             Context context,
             int sensorType,
             int samplingRateInUs,
@@ -55,28 +56,15 @@
 
     @Override
     public void doWork() {
-        TestSensorEvent event = mSensor.collectEvents(1)[0];
-        StringBuilder valuesBuilder = new StringBuilder();
-        double norm = 0.0;
-
-        for(int i = 0; i < mAxisCount; ++i) {
-            float value = event.values[i];
-            norm += Math.pow(value, 2);
-
-            valuesBuilder.append(value);
-            valuesBuilder.append(", ");
+        TestSensorEvent[] events = mSensor.collectEvents(1);
+        VerificationResult result = SensorVerificationHelper.verifyMagnitude(events, mReferenceValue,
+                mThreshold);
+        if (result.isFailed()) {
+            Assert.fail(SensorCtsHelper.formatAssertionMessage(
+                    "Norm",
+                    this,
+                    mSensor.getUnderlyingSensor(),
+                    result.getFailureMessage()));
         }
-        norm = Math.sqrt(norm);
-
-        String message = SensorCtsHelper.formatAssertionMessage(
-                "Norm",
-                this,
-                mSensor.getUnderlyingSensor(),
-                "expected:%f, threshold:%f, actual:%f ( %s)",
-                mReferenceValue,
-                mThreshold,
-                norm,
-                valuesBuilder.toString());
-        Assert.assertTrue(message, Math.abs(mReferenceValue - norm) <= mThreshold);
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMaximumFrequencyOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMaximumFrequencyOperation.java
index 3cdffe0..0af15a24 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMaximumFrequencyOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMaximumFrequencyOperation.java
@@ -16,21 +16,18 @@
 
 package android.hardware.cts.helpers.sensorTestOperations;
 
-import junit.framework.Assert;
-
 import android.content.Context;
-
 import android.hardware.cts.helpers.SensorCtsHelper;
 import android.hardware.cts.helpers.SensorManagerTestVerifier;
 import android.hardware.cts.helpers.SensorTestInformation;
 import android.hardware.cts.helpers.SensorTestOperation;
+import android.hardware.cts.helpers.SensorVerificationHelper;
+import android.hardware.cts.helpers.SensorVerificationHelper.VerificationResult;
 import android.hardware.cts.helpers.TestSensorEvent;
 
-import android.util.Log;
+import junit.framework.Assert;
 
 import java.security.InvalidParameterException;
-import java.util.ArrayList;
-
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -71,28 +68,15 @@
 
     @Override
     public void doWork() {
-        TestSensorEvent events[] = mSensor.collectEvents(100);
-        ArrayList<Long> timestampDelayValues = new ArrayList<Long>();
-        Double frequencyMeanInUs = SensorCtsHelper.getAverageTimestampDelayWithValues(
-                events,
-                timestampDelayValues);
-
-        if(Math.abs(mExpectedTimestampInNs - frequencyMeanInUs) > mThresholdInNs) {
-            for(long value : timestampDelayValues) {
-                Log.e(LOG_TAG, "TimestampDelay: " + value);
-            }
-            String message = SensorCtsHelper.formatAssertionMessage(
+        TestSensorEvent[] events = mSensor.collectEvents(100);
+        VerificationResult result = SensorVerificationHelper.verifyFrequency(events,
+                mExpectedTimestampInNs, mThresholdInNs);
+        if (result.isFailed()) {
+            Assert.fail(SensorCtsHelper.formatAssertionMessage(
                     "Frequency",
                     this,
                     mSensor.getUnderlyingSensor(),
-                    "expected:%dns(%.2fHz), actual:%fns(%.2fHz), threshold:%dns(%d%%)",
-                    mExpectedTimestampInNs,
-                    SensorCtsHelper.getFrequencyInHz(mExpectedTimestampInNs),
-                    frequencyMeanInUs,
-                    SensorCtsHelper.getFrequencyInHz(frequencyMeanInUs),
-                    mThresholdInNs,
-                    mThresholdPercentage);
-            Assert.fail(message);
+                    result.getFailureMessage()));
         }
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMeasurementsOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMeasurementsOperation.java
index d0c991b3..2368eb4 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMeasurementsOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMeasurementsOperation.java
@@ -16,16 +16,17 @@
 
 package android.hardware.cts.helpers.sensorTestOperations;
 
-import junit.framework.Assert;
-
 import android.content.Context;
-
 import android.hardware.cts.helpers.SensorCtsHelper;
 import android.hardware.cts.helpers.SensorManagerTestVerifier;
 import android.hardware.cts.helpers.SensorTestInformation;
 import android.hardware.cts.helpers.SensorTestOperation;
+import android.hardware.cts.helpers.SensorVerificationHelper;
+import android.hardware.cts.helpers.SensorVerificationHelper.VerificationResult;
 import android.hardware.cts.helpers.TestSensorEvent;
 
+import junit.framework.Assert;
+
 import java.security.InvalidParameterException;
 
 /**
@@ -37,8 +38,8 @@
 public class VerifyMeasurementsOperation extends SensorTestOperation {
     private final SensorManagerTestVerifier mSensor;
     private final int mAxisCount;
-    private final double mReferenceValues[];
-    private final double mThreshold;
+    private final double[] mReferenceValues;
+    private final double[] mThreshold;
 
     public VerifyMeasurementsOperation(
             Context context,
@@ -59,39 +60,23 @@
                 reportLatencyInUs);
         // set expectations
         mReferenceValues = referenceValues;
-        mThreshold = threshold;
+        mThreshold = new double[mAxisCount];
+        for (int i = 0; i < mThreshold.length; i++) {
+            mThreshold[i] = threshold;
+        }
     }
 
     @Override
     public void doWork() {
-        final String VALUE_SEPARATOR = ", ";
-        TestSensorEvent events[] = mSensor.collectEvents(100);
-        double measuredValues[] = new double[mReferenceValues.length];
-        SensorCtsHelper.getMeans(events, measuredValues);
-
-        boolean success = true;
-        StringBuilder referenceValuesBuilder = new StringBuilder();
-        StringBuilder measuredValuesBuilder = new StringBuilder();
-        for(int i = 0; i < mReferenceValues.length; i++) {
-            double reference = mReferenceValues[i];
-            double measurement = measuredValues[i];
-            double delta = Math.abs(reference - measurement);
-            success &= (delta <= mThreshold);
-            referenceValuesBuilder.append(reference);
-            referenceValuesBuilder.append(VALUE_SEPARATOR);
-            measuredValuesBuilder.append(measurement);
-            measuredValuesBuilder.append(VALUE_SEPARATOR);
-        }
-        if(!success) {
-            String message = SensorCtsHelper.formatAssertionMessage(
+        TestSensorEvent[] events = mSensor.collectEvents(100);
+        VerificationResult result = SensorVerificationHelper.verifyMean(events, mReferenceValues,
+                mThreshold);
+        if (result.isFailed()) {
+            Assert.fail(SensorCtsHelper.formatAssertionMessage(
                     "Measurement",
                     this,
                     mSensor.getUnderlyingSensor(),
-                    "expected:( %s), threshold:%f, actual: ( %s)",
-                    referenceValuesBuilder.toString(),
-                    mThreshold,
-                    measuredValuesBuilder.toString());
-            Assert.fail(message);
+                    result.getFailureMessage()));
         }
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifySignumOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifySignumOperation.java
index 0ccf92a..f58baa1 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifySignumOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifySignumOperation.java
@@ -16,15 +16,17 @@
 
 package android.hardware.cts.helpers.sensorTestOperations;
 
-import junit.framework.Assert;
-
 import android.content.Context;
 import android.hardware.cts.helpers.SensorCtsHelper;
 import android.hardware.cts.helpers.SensorManagerTestVerifier;
 import android.hardware.cts.helpers.SensorTestInformation;
 import android.hardware.cts.helpers.SensorTestOperation;
+import android.hardware.cts.helpers.SensorVerificationHelper;
+import android.hardware.cts.helpers.SensorVerificationHelper.VerificationResult;
 import android.hardware.cts.helpers.TestSensorEvent;
 
+import junit.framework.Assert;
+
 import java.security.InvalidParameterException;
 
 /**
@@ -34,8 +36,8 @@
 public class VerifySignumOperation extends SensorTestOperation {
     private final SensorManagerTestVerifier mSensor;
     private final int mAxisCount;
-    private final double mReferenceValues[];
-    private final double mNoiseThreshold;
+    private final int mReferenceValues[];
+    private final double mNoiseThresholds[];
 
     /**
      * @param noiseThreshold Defines the threshold that needs to be crossed to consider a
@@ -45,7 +47,7 @@
             Context context,
             int sensorType,
             int samplingRateInUs,
-            double referenceValues[],
+            int referenceValues[],
             double noiseThreshold) {
         mAxisCount = SensorTestInformation.getAxisCount(sensorType);
         if(mAxisCount != referenceValues.length) {
@@ -53,7 +55,7 @@
                     String.format("%d reference values are expected.", mAxisCount));
         }
         for(int i = 0; i < referenceValues.length; ++i) {
-            double value = referenceValues[i];
+            int value = referenceValues[i];
             if(value != 0 && value != -1 && value != +1) {
                 throw new InvalidParameterException(
                         "A ReferenceValue can only be one of the following: -1, 0, +1");
@@ -66,46 +68,23 @@
                 0 /*reportLatencyInUs*/);
         // set expectations
         mReferenceValues = referenceValues;
-        mNoiseThreshold = noiseThreshold;
+        mNoiseThresholds = new double[mReferenceValues.length];
+        for (int i = 0; i < mNoiseThresholds.length; i++) {
+            mNoiseThresholds[i] = noiseThreshold;
+        }
     }
 
     @Override
     public void doWork() {
-        final String VALUE_SEPARATOR = ", ";
-        TestSensorEvent events[] = mSensor.collectEvents(100);
-        double measuredValues[] = new double[mReferenceValues.length];
-        SensorCtsHelper.getMeans(events, measuredValues);
-
-        boolean success = true;
-        StringBuilder referenceValuesBuilder = new StringBuilder();
-        StringBuilder measuredValuesBuilder = new StringBuilder();
-        for(int i = 0; i < mReferenceValues.length; i++) {
-            double reference = mReferenceValues[i];
-            double measurement = measuredValues[i];
-            if(reference == 0) {
-                success &= Math.abs(measurement) < mNoiseThreshold;
-            } else {
-                double combinedValue = reference * measurement;
-                if(combinedValue < mNoiseThreshold) {
-                    combinedValue = 0;
-                }
-                success &= combinedValue > 0;
-            }
-            referenceValuesBuilder.append(reference);
-            referenceValuesBuilder.append(VALUE_SEPARATOR);
-            measuredValuesBuilder.append(measurement);
-            measuredValuesBuilder.append(VALUE_SEPARATOR);
-        }
-        if(!success) {
-            String message = SensorCtsHelper.formatAssertionMessage(
+        TestSensorEvent[] events = mSensor.collectEvents(100);
+        VerificationResult result = SensorVerificationHelper.verifySignum(events, mReferenceValues,
+                mNoiseThresholds);
+        if (result.isFailed()) {
+            Assert.fail(SensorCtsHelper.formatAssertionMessage(
                     "Measurement",
                     this,
                     mSensor.getUnderlyingSensor(),
-                    "expected:( %s), actual:( %s), noiseThreshold:%f",
-                    referenceValuesBuilder.toString(),
-                    measuredValuesBuilder.toString(),
-                    mNoiseThreshold);
-            Assert.fail(message);
+                    result.getFailureMessage()));
         }
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyStandardDeviationOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyStandardDeviationOperation.java
index 89cff94..05b92e0 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyStandardDeviationOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyStandardDeviationOperation.java
@@ -16,19 +16,16 @@
 
 package android.hardware.cts.helpers.sensorTestOperations;
 
-import junit.framework.Assert;
-
 import android.content.Context;
-
 import android.hardware.cts.helpers.SensorCtsHelper;
 import android.hardware.cts.helpers.SensorManagerTestVerifier;
 import android.hardware.cts.helpers.SensorTestInformation;
 import android.hardware.cts.helpers.SensorTestOperation;
+import android.hardware.cts.helpers.SensorVerificationHelper;
+import android.hardware.cts.helpers.SensorVerificationHelper.VerificationResult;
 import android.hardware.cts.helpers.TestSensorEvent;
 
-import android.util.Log;
-
-import java.util.ArrayList;
+import junit.framework.Assert;
 
 /**
  * Test Operation class that validates the standard deviation of a given sensor.
@@ -36,7 +33,7 @@
 public class VerifyStandardDeviationOperation extends SensorTestOperation {
     private SensorManagerTestVerifier mSensor;
     private int mAxisCount;
-    private double mExpectedStandardDeviation;
+    private double[] mExpectedStandardDeviation;
 
     public VerifyStandardDeviationOperation(
             Context context,
@@ -51,33 +48,23 @@
                 reportLatencyInUs);
         // set expectations
         mAxisCount = SensorTestInformation.getAxisCount(mSensor.getUnderlyingSensor().getType());
-        mExpectedStandardDeviation = expectedStandardDeviation;
+        mExpectedStandardDeviation = new double[mAxisCount];
+        for (int i = 0; i < mExpectedStandardDeviation.length; i++) {
+            mExpectedStandardDeviation[i] = expectedStandardDeviation;
+        }
     }
 
     @Override
     public void doWork() {
-        TestSensorEvent events[] = mSensor.collectEvents(100);
-        for(int i = 0; i < mAxisCount; ++i) {
-            ArrayList<Float> values = new ArrayList<Float>();
-            for(TestSensorEvent event : events) {
-                values.add(event.values[i]);
-            }
-
-            double standardDeviation = SensorCtsHelper.getStandardDeviation(values);
-            if(standardDeviation > mExpectedStandardDeviation) {
-                for(float value : values) {
-                    Log.e(LOG_TAG, String.format("SensorValue:%f", value));
-                }
-                String message = SensorCtsHelper.formatAssertionMessage(
-                        "StandardDeviation",
-                        this,
-                        mSensor.getUnderlyingSensor(),
-                        "axis:%d, expected:%f, actual:%f",
-                        i,
-                        mExpectedStandardDeviation,
-                        standardDeviation);
-                Assert.fail(message);
-            }
+        TestSensorEvent[] events = mSensor.collectEvents(100);
+        VerificationResult result = SensorVerificationHelper.verifyStandardDeviation(events,
+                mExpectedStandardDeviation);
+        if (result.isFailed()) {
+            Assert.fail(SensorCtsHelper.formatAssertionMessage(
+                    "StandardDeviation",
+                    this,
+                    mSensor.getUnderlyingSensor(),
+                    result.getFailureMessage()));
         }
     }
 }