diff options
23 files changed, 1800 insertions, 911 deletions
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorAccelerometerTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorAccelerometerTest.java deleted file mode 100644 index 2e33a5d292d..00000000000 --- a/tests/tests/hardware/src/android/hardware/cts/SensorAccelerometerTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008 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; - -import android.hardware.Sensor; -import android.hardware.SensorManager; - -public class SensorAccelerometerTest extends SensorCommonTests { - private final int AXIS_COUNT = 3; - - @Override - protected int getMaxFrequencySupportedInuS() { - return 10000; // 100Hz - } - - @Override - protected int getSensorType() { - return Sensor.TYPE_ACCELEROMETER; - } - - /** - * Regress: - * - b/9503957 - * - b/9611609 - */ - @Override - public void testEventValidity() { - final float THRESHOLD = 0.5f; // m / s^2 - validateNormForSensorEvent(SensorManager.STANDARD_GRAVITY, THRESHOLD, AXIS_COUNT); - } - - @Override - public void testStandardDeviationWhileStatic() { - final float STANDARD_DEVIATION = 1f; // m / s^2 - validateStandardDeviationWhileStatic(STANDARD_DEVIATION, AXIS_COUNT); - } -} diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorCommonTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorCommonTests.java deleted file mode 100644 index b535c717e1d..00000000000 --- a/tests/tests/hardware/src/android/hardware/cts/SensorCommonTests.java +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright (C) 2008 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; - -import android.content.Context; - -import android.hardware.Sensor; -import android.hardware.SensorManager; -import android.hardware.TriggerEvent; -import android.hardware.TriggerEventListener; - -import android.hardware.cts.helpers.SensorCtsHelper; -import android.hardware.cts.helpers.TestSensorManager; - -import android.os.PowerManager; - -import android.os.SystemClock; -import android.test.AndroidTestCase; - -import android.util.Log; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.TimeUnit; - -import junit.framework.Assert; - -/** - * Class is not marked public to avoid TestRunner to pick the tests in it - */ -abstract class SensorCommonTests extends AndroidTestCase { - protected final String LOG_TAG = "TestRunner"; - protected TestSensorManager mTestSensorManager; - private PowerManager.WakeLock mWakeLock; - - protected SensorCommonTests() {} - - /** - * Abstract methods needed by concrete sensor classes to provide - */ - protected abstract int getSensorType(); - protected abstract int getMaxFrequencySupportedInuS(); - - /** - * Abstract test methods that sensors need to verify - */ - public abstract void testEventValidity(); - public abstract void testStandardDeviationWhileStatic(); - - /** - * Methods to control the behavior of the tests by concrete sensor tests - */ - protected int getHighNumberOfIterationsToExecute() { - return 100; - } - - protected int getLowNumberOfIterationsToExecute() { - return 10; - } - - protected int getNumberOfThreadsToUse() { - return 5; - } - - /** - * Test execution methods - */ - @Override - protected void setUp() throws Exception { - PowerManager powerManager = (PowerManager) this.getContext().getSystemService( - Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getLogTag()); - mWakeLock.acquire(); - } - - @Override - protected void tearDown() throws Exception { - if(mTestSensorManager != null) { - mTestSensorManager.close(); - mTestSensorManager = null; - } - - releaseWakeLock(); - } - - @Override - public void runBare() throws Throwable { - SensorManager sensorManager = (SensorManager) this.getContext().getSystemService(Context.SENSOR_SERVICE); - assertNotNull("getSystemService#Sensor_Service", sensorManager); - - List<Sensor> availableSensors = sensorManager.getSensorList(this.getSensorType()); - // it is OK if there are no sensors available - for(Sensor sensor : availableSensors) { - mTestSensorManager = new TestSensorManager(this, sensorManager, sensor); - super.runBare(); - } - } - - /** - * Test cases continuous mode. - */ - public void testCanRegisterListener() { - mTestSensorManager.registerListener(SensorManager.SENSOR_DELAY_NORMAL); - } - - public void testNotTriggerSensor() { - TestTriggerListener listener = new TestTriggerListener(); - boolean result = mTestSensorManager.getUnderlyingSensorManager().requestTriggerSensor( - listener, - mTestSensorManager.getSensorUnderTest()); - assertFalse("requestTriggerSensor", result); - } - - public void testCanReceiveEvents() { - mTestSensorManager.collectEvents(SensorManager.SENSOR_DELAY_NORMAL, 5); - } - - public void testMaxFrequency() { - // TODO: verify that events do arrive at the proper rate - mTestSensorManager.registerListener(this.getMaxFrequencySupportedInuS()); - } - - public void testEventsArriveInOrder() { - // TODO: test for other sensor frequencies, rely on helper test classes for sensors - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.collectEvents( - SensorManager.SENSOR_DELAY_FASTEST, - 100); - for(int i = 1; i < events.length; ++i) { - long previousTimestamp = events[i-1].timestamp; - long timestamp = events[i].timestamp; - assertTrue( - String.format("[timestamp:%d] %d >= %d", i, previousTimestamp, timestamp), - previousTimestamp < timestamp); - } - } - - public void testStartStopRepeatedly() { - validateRegisterUnregisterRepeteadly(mTestSensorManager); - } - - public void testUpdateRate() { - // the seed is constant for now, use a random seed when we can log the seed properly - final long seed = 0xABCDE012; - Random generator = new Random(seed); - for(int i = 0; i < this.getHighNumberOfIterationsToExecute(); ++i) { - int rate; - switch(generator.nextInt(5)) { - case 0: - rate = SensorManager.SENSOR_DELAY_FASTEST; - break; - case 1: - rate = SensorManager.SENSOR_DELAY_GAME; - break; - case 2: - rate = SensorManager.SENSOR_DELAY_NORMAL; - break; - case 3: - rate = SensorManager.SENSOR_DELAY_UI; - break; - case 4: - default: - rate = this.getMaxFrequencySupportedInuS() * generator.nextInt(10); - } - - // TODO: check that the rate has indeed changed - mTestSensorManager.collectEvents( - rate, - generator.nextInt(5) + 1, - String.format("iteration:%d, rate:%d", i, rate)); - } - } - - public void testOneClientSeveralThreads() throws InterruptedException { - Runnable operation = new Runnable() { - @Override - public void run() { - validateRegisterUnregisterRepeteadly(mTestSensorManager); - } - }; - SensorCtsHelper.performOperationInThreads(this.getNumberOfThreadsToUse(), operation); - } - - public void testSeveralClients() throws InterruptedException { - final Assert assertionObject = this; - Runnable operation = new Runnable() { - @Override - public void run() { - TestSensorManager testSensorManager = new TestSensorManager( - assertionObject, - mTestSensorManager.getUnderlyingSensorManager(), - mTestSensorManager.getSensorUnderTest()); - validateRegisterUnregisterRepeteadly(testSensorManager); - } - }; - SensorCtsHelper.performOperationInThreads(this.getNumberOfThreadsToUse(), operation); - } - - public void testStoppingOtherClients() { - // TODO: use a higher test abstraction and move these to integration tests - final int EVENT_COUNT = 1; - final int SECOND_EVENT_COUNT = 5; - TestSensorManager sensorManager2 = new TestSensorManager( - this, - mTestSensorManager.getUnderlyingSensorManager(), - mTestSensorManager.getSensorUnderTest()); - - mTestSensorManager.registerListener(SensorManager.SENSOR_DELAY_NORMAL); - - // is receiving events - mTestSensorManager.getEvents(EVENT_COUNT); - - // operate in a different client - sensorManager2.collectEvents(SensorManager.SENSOR_DELAY_FASTEST, SECOND_EVENT_COUNT); - - // verify first client is still operating - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.getEvents(EVENT_COUNT); - assertTrue( - String.format("Events| expected:%d, actual:%d", EVENT_COUNT, events.length), - events.length >= EVENT_COUNT); - } - - public void testStoppingOtherClientsBatching() { - final int EVENT_COUNT = 1; - final int SECOND_EVENT_COUNT = 5; - TestSensorManager sensorManager2 = new TestSensorManager( - this, - mTestSensorManager.getUnderlyingSensorManager(), - mTestSensorManager.getSensorUnderTest()); - - mTestSensorManager.registerListener(SensorManager.SENSOR_DELAY_NORMAL); - - // is receiving events - mTestSensorManager.getEvents(EVENT_COUNT); - - // operate in a different client - sensorManager2.collectBatchEvents( - SensorManager.SENSOR_DELAY_FASTEST, - SensorCtsHelper.getSecondsAsMicroSeconds(1), - SECOND_EVENT_COUNT); - - // verify first client is still operating - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.getEvents(EVENT_COUNT); - assertTrue( - String.format("Events| expected:%d, actual:%d", EVENT_COUNT, events.length), - events.length >= EVENT_COUNT); - } - - /** - * Test cases batching mode. - */ - public void testRegisterForBatchingZeroReport() { - releaseWakeLock(); - // TODO: use test wrappers to verify for reportLatency ==0 !=0 - mTestSensorManager.collectBatchEvents(SensorManager.SENSOR_DELAY_NORMAL, 0, 10); - } - - public void testCanReceiveBatchEvents() { - releaseWakeLock(); - mTestSensorManager.collectBatchEvents( - SensorManager.SENSOR_DELAY_NORMAL, - SensorCtsHelper.getSecondsAsMicroSeconds(5), - 10 /*eventCount*/); - } - - /** - * Regress: - * -b/10790905 - */ - public void ignore_testBatchingReportLatency() { - long startTime = SystemClock.elapsedRealtimeNanos(); - // TODO: define the sensor frequency per sensor - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.collectBatchEvents( - SensorCtsHelper.getSecondsAsMicroSeconds(1), - SensorCtsHelper.getSecondsAsMicroSeconds(5), - 1 /*eventCount*/); - long elapsedTime = SystemClock.elapsedRealtimeNanos() - startTime; - long expectedTime = - TimeUnit.NANOSECONDS.convert(5, TimeUnit.SECONDS) + - TimeUnit.NANOSECONDS.convert(500, TimeUnit.MILLISECONDS); - - // TODO: ensure the proper batching time considers the size of the FIFO (fifoMaxEventCount), - // and make sure that no other application is registered - assertTrue( - String.format("WaitTime| expected:%d, actual:%d", expectedTime, elapsedTime), - elapsedTime <= expectedTime); - } - - public void testBatchEventsArriveInOrder() { - releaseWakeLock(); - - // TODO: identify if we can reuse code from the non-batching case, same for other batch tests - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.collectBatchEvents( - SensorManager.SENSOR_DELAY_NORMAL, - SensorCtsHelper.getSecondsAsMicroSeconds(5), - 100); - for(int i = 1; i < events.length; ++i) { - long previousTimestamp = events[i-1].timestamp; - long timestamp = events[i].timestamp; - assertTrue( - String.format("[timestamp:%d] %d >= %d", i, previousTimestamp, timestamp), - previousTimestamp < timestamp); - } - } - - public void testStartStopBatchingRepeatedly() { - releaseWakeLock(); - validateRegisterUnregisterRepeteadlyBatching(mTestSensorManager); - } - - public void testUpdateBatchRate() { - releaseWakeLock(); - - // use a constant seed until it can be logged properly - final long seed = 0xFEDCBA98; - Random generator = new Random(seed); - for(int i = 0; i < this.getHighNumberOfIterationsToExecute(); ++i) { - int rate; - switch(generator.nextInt(5)) { - case 0: - rate = SensorManager.SENSOR_DELAY_FASTEST; - break; - case 1: - rate = SensorManager.SENSOR_DELAY_GAME; - break; - case 2: - rate = SensorManager.SENSOR_DELAY_NORMAL; - break; - case 3: - rate = SensorManager.SENSOR_DELAY_UI; - break; - case 4: - default: - rate = this.getMaxFrequencySupportedInuS() * generator.nextInt(10); - } - - String iterationInfo = String.format("iteration:%d, rate:%d", i, rate); - mTestSensorManager.collectBatchEvents( - rate, - generator.nextInt(SensorCtsHelper.getSecondsAsMicroSeconds(5)), - generator.nextInt(5) + 1, - iterationInfo); - } - } - - public void testOneClientSeveralThreadsBatching() throws InterruptedException { - Runnable operation = new Runnable() { - @Override - public void run() { - validateRegisterUnregisterRepeteadlyBatching(mTestSensorManager); - } - }; - SensorCtsHelper.performOperationInThreads(this.getNumberOfThreadsToUse(), operation); - } - - public void testSeveralClientsBatching() throws InterruptedException { - final Assert assertionObject = this; - Runnable operation = new Runnable() { - @Override - public void run() { - TestSensorManager testSensorManager = new TestSensorManager( - assertionObject, - mTestSensorManager.getUnderlyingSensorManager(), - mTestSensorManager.getSensorUnderTest()); - validateRegisterUnregisterRepeteadlyBatching(testSensorManager); - } - }; - SensorCtsHelper.performOperationInThreads(this.getNumberOfThreadsToUse(), operation); - } - - public void testBatchingStoppingOtherClients() { - final int EVENT_COUNT = 1; - final int SECOND_EVENT_COUNT = 5; - TestSensorManager sensorManager2 = new TestSensorManager( - this, - mTestSensorManager.getUnderlyingSensorManager(), - mTestSensorManager.getSensorUnderTest()); - - mTestSensorManager.registerBatchListener( - SensorManager.SENSOR_DELAY_NORMAL, - SensorCtsHelper.getSecondsAsMicroSeconds(5)); - - // is receiving events - mTestSensorManager.getEvents(EVENT_COUNT); - - // operate in a different client - sensorManager2.collectEvents(SensorManager.SENSOR_DELAY_FASTEST, SECOND_EVENT_COUNT); - - // verify first client is still operating - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.getEvents(EVENT_COUNT); - assertTrue( - String.format("Events| expected:%d, actual:%d", EVENT_COUNT, events.length), - events.length >= EVENT_COUNT); - } - - public void testBatchingStoppingOtherClientsBatching() { - final int EVENT_COUNT = 1; - final int SECOND_EVENT_COUNT = 5; - TestSensorManager sensorManager2 = new TestSensorManager( - this, - mTestSensorManager.getUnderlyingSensorManager(), - mTestSensorManager.getSensorUnderTest()); - - mTestSensorManager.registerBatchListener( - SensorManager.SENSOR_DELAY_NORMAL, - SensorCtsHelper.getSecondsAsMicroSeconds(5)); - - // is receiving events - mTestSensorManager.getEvents(EVENT_COUNT); - - // operate in a different client - sensorManager2.collectBatchEvents( - SensorManager.SENSOR_DELAY_FASTEST, - SensorCtsHelper.getSecondsAsMicroSeconds(1), - SECOND_EVENT_COUNT); - - // verify first client is still operating - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.getEvents(EVENT_COUNT); - assertTrue( - String.format("Events| expected:%d, actual:%d", EVENT_COUNT, events.length), - events.length >= EVENT_COUNT); - } - - /** - * Tests for sensor characteristics. - */ - public void ignore_testEventJittering() { - final long EXPECTED_TIMESTAMP_NS = this.getMaxFrequencySupportedInuS() * 1000; - final long THRESHOLD_IN_NS = EXPECTED_TIMESTAMP_NS / 10; // 10% - - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.collectEvents( - this.getMaxFrequencySupportedInuS(), - 100); - ArrayList<Double> jitterValues = new ArrayList<Double>(); - double jitterMean = SensorCtsHelper.getJitterMean(events, jitterValues); - double percentile95InNs = SensorCtsHelper.get95PercentileValue(jitterValues); - - if(percentile95InNs > THRESHOLD_IN_NS) { - for(double jitter : jitterValues) { - Log.e(LOG_TAG, "Jitter: " + jitter); - } - double actualPercentValue = (percentile95InNs * 100) / jitterMean; - String message = String.format( - "95%% Jitter| 10%%:%dns, actual:%fns(%.2f%%)", - THRESHOLD_IN_NS, - percentile95InNs, - actualPercentValue); - fail(message); - } - } - - public void ignore_testFrequencyAccuracy() { - final long EXPECTED_TIMESTAMP_NS = this.getMaxFrequencySupportedInuS() * 1000; - final long THRESHOLD_IN_NS = EXPECTED_TIMESTAMP_NS / 10; // 10% - - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.collectEvents( - this.getMaxFrequencySupportedInuS(), - 100); - ArrayList<Long> timestampDelayValues = new ArrayList<Long>(); - Double frequencyMean = SensorCtsHelper.getAverageTimestampDelayWithValues( - events, - timestampDelayValues); - if(Math.abs(EXPECTED_TIMESTAMP_NS - frequencyMean) > THRESHOLD_IN_NS) { - for(long value : timestampDelayValues) { - Log.e(LOG_TAG, "TimestampDelay: " + value); - } - String message = String.format( - "Frequency| expected:%d, actual:%f", - EXPECTED_TIMESTAMP_NS, - frequencyMean); - fail(message); - } - } - - /** - * Private helpers. - */ - private String getLogTag() { - return this.getClass().getSimpleName(); - } - - private void releaseWakeLock() { - PowerManager.WakeLock wakeLock = mWakeLock; - mWakeLock = null; - - if(wakeLock != null) { - wakeLock.release(); - } - } - - /** - * Test method helper implementations - */ - protected void validateNormForSensorEvent(float reference, float threshold, int axisCount) { - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.collectEvents( - SensorManager.SENSOR_DELAY_FASTEST, - 1); - TestSensorManager.SensorEventForTest event = events[0]; - - StringBuilder valuesBuilder = new StringBuilder(); - double norm = 0.0; - for(int i = 0; i < axisCount; ++i) { - float value = event.values[i]; - norm += Math.pow(value, 2); - - valuesBuilder.append(value); - valuesBuilder.append(", "); - } - norm = Math.sqrt(norm); - - String message = String.format( - "Norm| expected:%f, threshold:%f, actual:%f (%s)", - reference, - threshold, - norm, - valuesBuilder.toString()); - assertTrue(message, Math.abs(reference - norm) <= threshold); - } - - protected void validateRegisterUnregisterRepeteadly(TestSensorManager testSensorManager) { - for(int i = 0; i < this.getLowNumberOfIterationsToExecute(); ++i) { - String iterationInfo = String.format("iteration:%d", i); - testSensorManager.collectEvents(SensorManager.SENSOR_DELAY_FASTEST, 1, iterationInfo); - } - } - - protected void validateRegisterUnregisterRepeteadlyBatching( - TestSensorManager testSensorManager) { - // TODO: refactor if allowed with test wrapper abstractions - for(int i = 0; i < this.getLowNumberOfIterationsToExecute(); ++i) { - testSensorManager.collectBatchEvents( - SensorManager.SENSOR_DELAY_FASTEST, - SensorCtsHelper.getSecondsAsMicroSeconds(5), - 5 /*eventCont*/, - String.format("iteration:%d", i)); - } - } - - protected void validateStandardDeviationWhileStatic( - float expectedStandardDeviation, - int axisCount) { - // TODO: refactor the report parameter with test wrappers if available - TestSensorManager.SensorEventForTest[] events = mTestSensorManager.collectEvents( - this.getMaxFrequencySupportedInuS(), - 100); - - for(int i = 0; i < axisCount; ++i) { - ArrayList<Float> values = new ArrayList<Float>(); - for(TestSensorManager.SensorEventForTest event : events) { - values.add(event.values[i]); - } - - double standardDeviation = SensorCtsHelper.getStandardDeviation(values); - String message = String.format( - "StandardDeviation| axis:%d, expected:%f, actual:%f", - i, - expectedStandardDeviation, - standardDeviation); - assertTrue(message, standardDeviation <= expectedStandardDeviation); - } - } - - /** - * Private class definitions to support test of event handlers. - */ - private class TestTriggerListener extends TriggerEventListener { - @Override - public void onTrigger(TriggerEvent event) { - } - } -} diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorEventOrderingTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorEventOrderingTests.java new file mode 100644 index 00000000000..9efa71dfd35 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/SensorEventOrderingTests.java @@ -0,0 +1,112 @@ +/* + * 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; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import android.hardware.Sensor; +import android.hardware.SensorManager; + +import android.hardware.cts.helpers.SensorTestCase; + +import android.hardware.cts.helpers.sensorTestOperations.VerifyEventOrderingOperation; + +/** + * Verifies the proper ordering in time of sensor events. + */ +public class SensorEventOrderingTests extends SensorTestCase { + /** + * Builder for the test suite. + * This is the method that will build dynamically the set of test cases to execute. + * Each 'base' test case is composed by three parts: + * - the matrix definition + * - the test method that will execute the test case + * - a static method that will combine both and add test case instances to the test suite + */ + public static Test suite() { + TestSuite testSuite = new TestSuite(); + + // add test generation routines + createEventOrderingTestCases(testSuite); + + return testSuite; + } + + /** + * Event ordering test cases. + */ + private int mSensorType; + private int mSamplingRateInUs; + private int mReportLatencyInUs; + + private static void createEventOrderingTestCases(TestSuite testSuite) { + int testDefinitionMatrix[][] = { + // { SensorType, SamplingRateInUs, ReportLatencyInUs }, + { Sensor.TYPE_ACCELEROMETER, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_GYROSCOPE, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_MAGNETIC_FIELD, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_LIGHT, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_PRESSURE, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_PROXIMITY, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_GRAVITY, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_LINEAR_ACCELERATION, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_ROTATION_VECTOR, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_RELATIVE_HUMIDITY, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_AMBIENT_TEMPERATURE, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_GAME_ROTATION_VECTOR, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_GYROSCOPE_UNCALIBRATED, SensorManager.SENSOR_DELAY_FASTEST, 0 }, + { Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, SensorManager.SENSOR_DELAY_FASTEST,0 }, + }; + + for(int definition[] : testDefinitionMatrix) { + SensorEventOrderingTests test = new SensorEventOrderingTests(); + test.mSensorType = definition[0]; + test.mSamplingRateInUs = definition[1]; + test.mReportLatencyInUs = definition[2]; + test.setName("testEventOrdering"); + testSuite.addTest(test); + } + } + + /** + * This test verifies the ordering of the sampled data reported by the Sensor under test. + * This test is used to guarantee that sensor data is reported in the order it occurs, and that + * events are always reported in order. + * + * The test takes a set of samples from the Sensor under test, and then it verifies that each + * event's timestamp is in the future compared with the previous event. At the end of the + * validation, the full set of events is verified to be ordered by timestamp as they are + * generated. + * + * The test can be susceptible to errors if the sensor sampled data is not timestamped at the + * Hardware level. Or events sampled at high rates are added to the FIFO without controlling the + * appropriate ordering of the events. + * + * The assertion associated with the test provides the information of the two consecutive events + * that cause the test to fail. + */ + public void testEventOrdering() throws Throwable { + VerifyEventOrderingOperation operation = new VerifyEventOrderingOperation( + this, + mSensorType, + mSamplingRateInUs, + mReportLatencyInUs); + operation.execute(); + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorFrequencyTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorFrequencyTests.java new file mode 100644 index 00000000000..c829c36e203 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/SensorFrequencyTests.java @@ -0,0 +1,206 @@ +/* + * 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; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import android.hardware.Sensor; + +import android.hardware.cts.helpers.SensorCtsHelper; +import android.hardware.cts.helpers.SensorTestCase; + +import android.hardware.cts.helpers.sensorTestOperations.VerifyJitteringOperation; +import android.hardware.cts.helpers.sensorTestOperations.VerifyMaximumFrequencyOperation; + +/** + * Verifies several properties of the sampling rate of the different sensors in the platform. + */ +public class SensorFrequencyTests extends SensorTestCase { + private int mSensorType; + private int mReportLatencyInUs; + private int mThresholdPercentageOfNs; + + /** + * Builder for the test suite. + * This is the method that will build dynamically the set of test cases to execute. + * Each 'base' test case is composed by three parts: + * - the matrix definition + * - the test method that will execute the test case + * - a static method that will combine both and add test case instances to the test suite + */ + public static Test suite() { + TestSuite testSuite = new TestSuite(); + + // add test generation routines + createMaxFrequencyExpectedTestCases(testSuite); + // TODO: tests are a unreliable in the lab + //createMaxFrequencyTestCases(testSuite); + //createJitteringTestCases(testSuite); + + return testSuite; + } + + /** + * Max frequency test cases. + */ + private static void createMaxFrequencyTestCases(TestSuite testSuite) { + int testDefinitionMatrix[][] = { + // { SensorType, ReportLatencyInUs, ThresholdPercentageOfNs }, + { Sensor.TYPE_ACCELEROMETER, 0, 10 }, + { Sensor.TYPE_GYROSCOPE, 0, 10 }, + { Sensor.TYPE_MAGNETIC_FIELD, 0, 10 }, + }; + + for(int definition[] : testDefinitionMatrix) { + SensorFrequencyTests test = new SensorFrequencyTests(); + test.mSensorType = definition[0]; + test.mReportLatencyInUs = definition[1]; + test.mThresholdPercentageOfNs = definition[2]; + test.setName("testMaxFrequency"); + testSuite.addTest(test); + } + } + + /** + * This test verifies that the Sensor under test can sample and report data at the Maximum + * frequency (sampling rate) it advertises. + * + * The test takes a set of samples from the sensor under test, and calculates the mean of the + * frequency at which the events are reported. The frequency between events is calculated by + * looking at the delta between the timestamps associated with each event. + * + * The test is susceptible to errors if the Sensor is not capable to sample data at the maximum + * rate it supports, or the sensor events are not timestamped at the Hardware level. + * + * The assertion associated with the test provides the required data to identify: + * - the thread id on which the failure occurred + * - the sensor type and sensor handle that caused the failure + * - the expected frequency + * - the observed frequency + * In addition to that, the device's debug output (adb logcat) dumps the set of timestamp deltas + * associated with the set of data gathered from the Sensor under test. + */ + public void testMaxFrequency() throws Throwable { + VerifyMaximumFrequencyOperation operation = new VerifyMaximumFrequencyOperation( + this, + mSensorType, + mReportLatencyInUs, + mThresholdPercentageOfNs); + operation.execute(); + } + + /** + * Jittering test cases. + */ + private static void createJitteringTestCases(TestSuite testSuite) { + int testDefinitionMatrix[][] = { + // { SensorType, ReportLatencyInUs, ThresholdPercentageOfNs }, + { Sensor.TYPE_ACCELEROMETER, 0, 10 }, + { Sensor.TYPE_GYROSCOPE, 0, 10 }, + { Sensor.TYPE_MAGNETIC_FIELD, 0, 10 }, + }; + + for(int definition[] : testDefinitionMatrix) { + SensorFrequencyTests test = new SensorFrequencyTests(); + test.mSensorType = definition[0]; + test.mReportLatencyInUs = definition[1]; + test.mThresholdPercentageOfNs = definition[2]; + test.setName("testJittering"); + testSuite.addTest(test); + } + } + + /** + * This test verifies that the event jittering associated with the sampled data reported by the + * Sensor under test, aligns with the requirements imposed in the CDD. + * This test characterizes how the sensor behaves while sampling data at a specific rate. + * + * The test takes a set of samples from the sensor under test, using the maximum sampling rate + * advertised by the Sensor under test. It then compares the 95%ile associated with the + * jittering of the timestamps, with an expected value. + * + * The test is susceptible to errors if the sensor events are not timestamped at the Hardware + * level. + * + * The assertion associated with the failure provides the following information: + * - the thread id on which the failure occurred + * - the sensor type and sensor handle that caused the failure + * - the expectation of the test with respect of the 95%ile + * - the calculated 95%ile jittering + * Additionally, the device's debug output (adb logcat) dumps the set of jitter values + * calculated. + */ + public void testJittering() throws Throwable { + VerifyJitteringOperation operation = new VerifyJitteringOperation( + this, + mSensorType, + mReportLatencyInUs, + mThresholdPercentageOfNs); + operation.execute(); + } + + /** + * Max Frequency expected Test Cases. + */ + private int mExpectedSamplingRateInUs; + + private static void createMaxFrequencyExpectedTestCases(TestSuite testSuite) { + int testDefinitionMatrix[][] = { + // { SensorType, ExpectedSamplingRateInUs }, + { Sensor.TYPE_ACCELEROMETER, 10000 /* 100 Hz */ }, + { Sensor.TYPE_GYROSCOPE, 10000 /* 100 Hz */ }, + { Sensor.TYPE_MAGNETIC_FIELD, 100000 /* 10 Hz */ }, + }; + + for(int definition[] : testDefinitionMatrix) { + SensorFrequencyTests test = new SensorFrequencyTests(); + test.mSensorType = definition[0]; + test.mExpectedSamplingRateInUs = definition[1]; + test.setName("testMaxFrequencyExpected"); + testSuite.addTest(test); + } + } + + /** + * This test verifies that the sensor's maximum advertised frequency (sampling rate) complies + * with the required frequency set in the CDD. + * This characterizes that the sensor is able to provide data at the rate the platform requires + * it. + * + * The test simply compares the sampling rate specified in the CDD with the maximum sampling + * rate advertised by the Sensor under test. + * + * The test can fail if the Sensor Hardware does not support the sampling rate required by the + * platform. + * + * The assertion associated with the test failure contains: + * - the thread id on which the failure occurred + * - the sensor type and sensor handle that caused the failure + * - the expected maximum sampling rate + * - the observed maximum sampling rate + */ + public void testMaxFrequencyExpected() { + Sensor sensor = SensorCtsHelper.getSensor(this, mSensorType); + int samplingRateInUs = sensor.getMinDelay(); + String message = String.format( + "samplingRateInUs| expected:%d, actual:%d", + mExpectedSamplingRateInUs, + samplingRateInUs); + assertTrue(message, mExpectedSamplingRateInUs >= samplingRateInUs); + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorGyroscopeTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorGyroscopeTest.java deleted file mode 100644 index b7c082e219e..00000000000 --- a/tests/tests/hardware/src/android/hardware/cts/SensorGyroscopeTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2008 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; - -import android.hardware.Sensor; - -public class SensorGyroscopeTest extends SensorCommonTests { - private final int AXIS_COUNT = 3; - - @Override - protected int getMaxFrequencySupportedInuS() { - return 10000; // 100Hz - } - - @Override - protected int getSensorType() { - return Sensor.TYPE_GYROSCOPE; - } - - @Override - public void testEventValidity() { - final float THRESHOLD = 0.1f; // dps - validateNormForSensorEvent(0 /*reference*/, THRESHOLD, AXIS_COUNT); - } - - @Override - public void testStandardDeviationWhileStatic() { - final float STANDARD_DEVIATION = 0.5f; // dps - validateStandardDeviationWhileStatic(STANDARD_DEVIATION, AXIS_COUNT); - } -} diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java index 7272d7231a8..0612c03d10a 100644 --- a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java +++ b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * 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. @@ -15,114 +15,257 @@ */ package android.hardware.cts; -import android.content.Context; +import junit.framework.Test; +import junit.framework.TestSuite; import android.hardware.Sensor; import android.hardware.SensorManager; import android.hardware.cts.helpers.SensorCtsHelper; -import android.hardware.cts.helpers.TestSensorManager; +import android.hardware.cts.helpers.SensorTestCase; +import android.hardware.cts.helpers.SensorTestInformation; +import android.hardware.cts.helpers.SensorTestOperation; -import android.os.PowerManager; +import android.hardware.cts.helpers.sensorTestOperations.ParallelCompositeSensorTestOperation; +import android.hardware.cts.helpers.sensorTestOperations.RepeatingSensorTestOperation; +import android.hardware.cts.helpers.sensorTestOperations.SequentialCompositeSensorTestOperation; +import android.hardware.cts.helpers.sensorTestOperations.VerifyEventOrderingOperation; -import android.test.AndroidTestCase; +import java.util.Random; -import java.util.List; -import java.util.concurrent.TimeUnit; +/** + * Set of tests that verifies proper interaction of the sensors in the platform. + * + * To execute these test cases, the following command can be used: + * $ adb shell am instrument -e class android.hardware.cts.SensorIntegrationTests \ + * -w com.android.cts.hardware/android.test.InstrumentationCtsTestRunner + */ +public class SensorIntegrationTests extends SensorTestCase { + /** + * Builder for the test suite. + * This is the method that will build dynamically the set of test cases to execute. + * Each 'base' test case is composed by three parts: + * - the matrix definition + * - the test method that will execute the test case + * - a static method that will combine both and add test case instances to the test suite + */ + public static Test suite() { + TestSuite testSuite = new TestSuite(); -public class SensorIntegrationTests extends AndroidTestCase { - protected final String LOG_TAG = "SensorIntegrationTests"; - private PowerManager.WakeLock mWakeLock; - private SensorManager mSensorManager; + // add test generation routines + addTestToSuite(testSuite, "testSensorsWithSeveralClients"); + addTestToSuite(testSuite, "testSensorsMovingRates"); + createStoppingTestCases(testSuite); + + return testSuite; + } /** - * Test execution methods + * This test focuses in the interaction of continuous and batching clients for the same Sensor + * under test. The verification ensures that sensor clients can interact with the System and + * not affect other clients in the way. + * + * The test verifies for each client that the a set of sampled data arrives in order. However + * each client in the test has different set of parameters that represent different types of + * clients in the real world. + * + * A test failure might indicate that the HAL implementation does not respect the assumption + * that the sensors must be independent. Activating one sensor should not cause another sensor + * to deactivate or to change behavior. + * It is however, acceptable that when a client is activated at a higher sampling rate, it would + * cause other clients to receive data at a faster sampling rate. A client causing other clients + * to receive data at a lower sampling rate is, however, not acceptable. + * + * The assertion associated with the test failure provides: + * - the thread id on which the failure occurred + * - the sensor type and sensor handle that caused the failure + * - the event that caused the issue + * It is important to look at the internals of the Sensor HAL to identify how the interaction + * of several clients can lead to the failing state. */ - @Override - protected void setUp() throws Exception { - PowerManager powerManager = (PowerManager) this.getContext().getSystemService( - Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); - mWakeLock.acquire(); - - mSensorManager = (SensorManager) this.getContext().getSystemService( - Context.SENSOR_SERVICE); - } + public void testSensorsWithSeveralClients() throws Throwable { + final int ITERATIONS = 50; + final int BATCHING_RATE_IN_SECONDS = 5; - @Override - protected void tearDown() throws Exception { - mSensorManager = null; + int sensorTypes[] = { + Sensor.TYPE_ACCELEROMETER, + Sensor.TYPE_MAGNETIC_FIELD, + Sensor.TYPE_GYROSCOPE }; - mWakeLock.release(); - mWakeLock = null; + ParallelCompositeSensorTestOperation operation = new ParallelCompositeSensorTestOperation(); + for(int sensorType : sensorTypes) { + SensorTestOperation continuousOperation = new VerifyEventOrderingOperation( + this, + sensorType, + SensorManager.SENSOR_DELAY_NORMAL, + 0 /* reportLatencyInUs */); + operation.add(new RepeatingSensorTestOperation(continuousOperation, ITERATIONS)); + + SensorTestOperation batchingOperation = new VerifyEventOrderingOperation( + this, + sensorType, + SensorTestInformation.getMaxSamplingRateInUs(this, sensorType), + SensorCtsHelper.getSecondsAsMicroSeconds(BATCHING_RATE_IN_SECONDS)); + operation.add(new RepeatingSensorTestOperation(batchingOperation, ITERATIONS)); + } + operation.execute(); } /** - * Test cases. + * This test focuses in the interaction of several sensor Clients. The test characterizes by + * using clients for different Sensors under Test that vary the sampling rates and report + * latencies for the requests. + * The verification ensures that the sensor clients can vary the parameters of their requests + * without affecting other clients. + * + * The test verifies for each client that a set of sampled data arrives in order. However each + * client in the test has different set of parameters that represent different types of clients + * in the real world. + * + * The test can be susceptible to issues when several clients interacting with the system + * actually affect the operation of other clients. + * + * The assertion associated with the test failure provides: + * - the thread id on which the failure occurred + * - the sensor type and sensor handle that caused the failure + * - the event that caused the issue + * It is important to look at the internals of the Sensor HAL to identify how the interaction + * of several clients can lead to the failing state. */ + public void testSensorsMovingRates() throws Throwable { + // use at least two instances to ensure more than one client of any given sensor is in play + final int INSTANCES_TO_USE = 5; + final int ITERATIONS_TO_EXECUTE = 100; + + ParallelCompositeSensorTestOperation operation = new ParallelCompositeSensorTestOperation(); + int sensorTypes[] = { + Sensor.TYPE_ACCELEROMETER, + Sensor.TYPE_MAGNETIC_FIELD, + Sensor.TYPE_GYROSCOPE }; + + for(int sensorType : sensorTypes) { + for(int instance = 0; instance < INSTANCES_TO_USE; ++instance) { + SequentialCompositeSensorTestOperation sequentialOperation = + new SequentialCompositeSensorTestOperation(); + for(int iteration = 0; iteration < ITERATIONS_TO_EXECUTE; ++iteration) { + VerifyEventOrderingOperation sensorOperation = new VerifyEventOrderingOperation( + this, + sensorType, + this.generateSamplingRateInUs(sensorType), + this.generateReportLatencyInUs()); + sequentialOperation.add(sensorOperation); + } + operation.add(sequentialOperation); + } + } + + operation.execute(); + } /** * Regress: * - b/10641388 */ - public void testAccelerometerDoesNotStopGyroscope() { - validateSensorCanBeStoppedIndependently(Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_GYROSCOPE); - } + private int mSensorTypeTester; + private int mSensorTypeTestee; - public void testAccelerometerDoesNotStopMagnetometer() { - validateSensorCanBeStoppedIndependently( + private static void createStoppingTestCases(TestSuite testSuite) { + int sensorTypes[] = { Sensor.TYPE_ACCELEROMETER, - Sensor.TYPE_MAGNETIC_FIELD); - } + Sensor.TYPE_GYROSCOPE, + Sensor.TYPE_MAGNETIC_FIELD}; - public void testGyroscopeDoesNotStopAccelerometer() { - validateSensorCanBeStoppedIndependently(Sensor.TYPE_GYROSCOPE, Sensor.TYPE_ACCELEROMETER); + for(int sensorTypeTester : sensorTypes) { + for(int sensorTypeTestee : sensorTypes) { + SensorIntegrationTests test = new SensorIntegrationTests(); + test.mSensorTypeTester = sensorTypeTester; + test.mSensorTypeTestee = sensorTypeTestee; + test.setName("testSensorStoppingInteraction"); + testSuite.addTest(test); + } + } } - public void testGyroscopeDoesNotStopMagnetometer() { - validateSensorCanBeStoppedIndependently(Sensor.TYPE_GYROSCOPE, Sensor.TYPE_MAGNETIC_FIELD); - } + /** + * This test verifies that starting/stopping a particular Sensor client in the System does not + * affect other sensor clients. + * the test is used to validate that starting/stopping operations are independent on several + * sensor clients. + * + * The test verifies for each client that the a set of sampled data arrives in order. However + * each client in the test has different set of parameters that represent different types of + * clients in the real world. + * + * The test can be susceptible to issues when several clients interacting with the system + * actually affect the operation of other clients. + * + * The assertion associated with the test failure provides: + * - the thread id on which the failure occurred + * - the sensor type and sensor handle that caused the failure + * - the event that caused the issue + * It is important to look at the internals of the Sensor HAL to identify how the interaction + * of several clients can lead to the failing state. + */ + public void testSensorStoppingInteraction() throws Throwable { + SensorTestOperation tester = new VerifyEventOrderingOperation( + this, + mSensorTypeTester, + SensorManager.SENSOR_DELAY_NORMAL, + 0 /*reportLatencyInUs*/); + tester.start(); - public void testMagnetometerDoesNotStopAccelerometer() { - validateSensorCanBeStoppedIndependently( - Sensor.TYPE_MAGNETIC_FIELD, - Sensor.TYPE_ACCELEROMETER); - } + SensorTestOperation testee = new VerifyEventOrderingOperation( + this, + mSensorTypeTestee, + SensorManager.SENSOR_DELAY_UI, + 0 /*reportLatencyInUs*/); + testee.start(); - public void testMagnetometerDoesNotStopGyroscope() { - validateSensorCanBeStoppedIndependently(Sensor.TYPE_MAGNETIC_FIELD, Sensor.TYPE_GYROSCOPE); + testee.waitForCompletion(); + tester.waitForCompletion(); + + testee.execute(); } /** - * Private methods for sensor validation. + * Private helpers. */ - public void validateSensorCanBeStoppedIndependently(int sensorTypeTester, int sensorTypeTestee) { - // if any of the required sensors is not supported, skip the test - Sensor sensorTester = mSensorManager.getDefaultSensor(sensorTypeTester); - if(sensorTester == null) { - return; - } - Sensor sensorTestee = mSensorManager.getDefaultSensor(sensorTypeTestee); - if(sensorTestee == null) { - return; - } - - TestSensorManager tester = new TestSensorManager(this, mSensorManager, sensorTester); - tester.registerListener(SensorManager.SENSOR_DELAY_NORMAL); + private final Random mGenerator = new Random(); - TestSensorManager testee = new TestSensorManager(this, mSensorManager, sensorTestee); - testee.registerBatchListener( - (int) TimeUnit.MICROSECONDS.convert(200, TimeUnit.MILLISECONDS), - SensorCtsHelper.getSecondsAsMicroSeconds(10)); - - testee.getEvents(10); - tester.getEvents(5); + private int generateSamplingRateInUs(int sensorType) { + int rate; + switch(mGenerator.nextInt(5)) { + case 0: + rate = SensorManager.SENSOR_DELAY_FASTEST; + break; + case 1: + rate = SensorManager.SENSOR_DELAY_GAME; + break; + case 2: + rate = SensorManager.SENSOR_DELAY_NORMAL; + break; + case 3: + rate = SensorManager.SENSOR_DELAY_UI; + break; + case 4: + default: + int maxSamplingRate = SensorTestInformation.getMaxSamplingRateInUs( + this, + sensorType); + rate = maxSamplingRate * mGenerator.nextInt(10); + } + return rate; + } - tester.unregisterListener(); - testee.getEvents(5); + private int generateReportLatencyInUs() { + int reportLatency = SensorCtsHelper.getSecondsAsMicroSeconds( + mGenerator.nextInt(5) + 1); + return reportLatency; + } - // clean up - tester.close(); - testee.close(); + private static void addTestToSuite(TestSuite testSuite, String testName) { + SensorIntegrationTests test = new SensorIntegrationTests(); + test.setName(testName); + testSuite.addTest(test); } } diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorMagneticFieldTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorMagneticFieldTest.java deleted file mode 100644 index e4041d6a5f2..00000000000 --- a/tests/tests/hardware/src/android/hardware/cts/SensorMagneticFieldTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2008 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; - -import android.hardware.Sensor; -import android.hardware.SensorManager; - -public class SensorMagneticFieldTest extends SensorCommonTests { - private final int AXIS_COUNT = 3; - - @Override - protected int getMaxFrequencySupportedInuS() { - return 100000; // 10Hz - } - - @Override - protected int getSensorType() { - return Sensor.TYPE_MAGNETIC_FIELD; - } - - @Override - public void testEventValidity() { - validateNormForSensorEvent( - SensorManager.MAGNETIC_FIELD_EARTH_MAX, - SensorManager.MAGNETIC_FIELD_EARTH_MIN, - AXIS_COUNT); - } - - @Override - public void testStandardDeviationWhileStatic() { - final float STANDARD_DEVIATION = 2f; // uT - validateStandardDeviationWhileStatic(STANDARD_DEVIATION, AXIS_COUNT); - } -} diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorMeasurementTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorMeasurementTests.java new file mode 100644 index 00000000000..7251fba1d41 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/SensorMeasurementTests.java @@ -0,0 +1,172 @@ +/* + * 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; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import android.hardware.Sensor; +import android.hardware.SensorManager; + +import android.hardware.cts.helpers.SensorTestCase; + +import android.hardware.cts.helpers.sensorTestOperations.VerifyNormOperation; +import android.hardware.cts.helpers.sensorTestOperations.VerifyStandardDeviationOperation; + +/** + * Verifies several properties of the sensor measurements. + */ +public class SensorMeasurementTests extends SensorTestCase { + private int mSensorType; + private int mSamplingRateInUs; + + /** + * Builder for the test suite. + * This is the method that will build dynamically the set of test cases to execute. + * Each 'base' test case is composed by three parts: + * - the matrix definition + * - the test method that will execute the test case + * - a static method that will combine both and add test case instances to the test suite + */ + public static Test suite() { + TestSuite testSuite = new TestSuite(); + + // add test generation routines + createEventNormTestCases(testSuite); + createStandardDeviationTestCases(testSuite); + + return testSuite; + } + + /** + * SensorEvent Norm test cases. + * + * Regress: + * - b/9503957 + * - b/9611609 + */ + private float mReferenceValue; + private float mThreshold; + + private static void createEventNormTestCases(TestSuite testSuite) { + Object testDefinitionMatrix[][] = { + // { SensorType, SamplingRateInUs, ReferenceValue, Threshold }, + { Sensor.TYPE_ACCELEROMETER, + SensorManager.SENSOR_DELAY_FASTEST, + SensorManager.STANDARD_GRAVITY, + 1.5f /* m / s^2 */}, + { Sensor.TYPE_GYROSCOPE, SensorManager.SENSOR_DELAY_FASTEST, 0.0f, 2.5f /* dps */ }, + }; + + for(Object definition[] : testDefinitionMatrix) { + SensorMeasurementTests test = new SensorMeasurementTests(); + test.mSensorType = (Integer)definition[0]; + test.mSamplingRateInUs = (Integer)definition[1]; + test.mReferenceValue = (Float)definition[2]; + test.mThreshold = (Float)definition[3]; + test.setName("testEventNorm"); + testSuite.addTest(test); + } + } + + /** + * This test verifies that the Norm of the sensor data is close to the expected reference value. + * The units of the reference value are dependent on the type of sensor. + * This test is used to verify that the data reported by the sensor is close to the expected + * range and scale. + * + * The test takes a sample from the sensor under test and calculates the Euclidean Norm of the + * vector represented by the sampled data. It then compares it against the test expectations + * that are represented by a reference value and a threshold. + * + * The test is susceptible to errors when the Sensor under test is uncalibrated, or the units in + * which the data are reported and the expectations are set are different. + * + * The assertion associated with the test provides the required data needed to identify any + * possible issue. It provides: + * - the thread id on which the failure occurred + * - the sensor type and sensor handle that caused the failure + * - the values representing the expectation of the test + * - the values sampled from the sensor + */ + public void testEventNorm() throws Throwable { + VerifyNormOperation operation = new VerifyNormOperation( + this, + mSensorType, + mSamplingRateInUs, + mReferenceValue, + mThreshold); + operation.execute(); + } + + /** + * SensorEvent Standard Deviation test cases. + */ + private int mReportLatencyInUs; + private float mExpectedStandardDeviation; + + private static void createStandardDeviationTestCases(TestSuite testSuite) { + Object testDefinitionMatrix[][] = { + // { SensorType, SamplingRateInUs, ReportLatencyInUs, ExpectedStandardDeviation }, + { Sensor.TYPE_ACCELEROMETER, SensorManager.SENSOR_DELAY_FASTEST, 0, 1f /* m/s^2 */ }, + { Sensor.TYPE_GYROSCOPE, SensorManager.SENSOR_DELAY_FASTEST, 0, 0.5f /* dps */ }, + }; + + for(Object definition[] : testDefinitionMatrix) { + SensorMeasurementTests test = new SensorMeasurementTests(); + test.mSensorType = (Integer)definition[0]; + test.mSamplingRateInUs = (Integer)definition[1]; + test.mReportLatencyInUs = (Integer)definition[2]; + test.mExpectedStandardDeviation = (Float)definition[3]; + test.setName("testStandardDeviation"); + testSuite.addTest(test); + } + } + + /** + * This test verifies that the standard deviation of a set of sampled data from a particular + * sensor falls into the expectations defined in the CDD. The verification applies to each axis + * of the sampled data reported by the Sensor under test. + * This test is used to validate the requirement imposed by the CDD to Sensors in Android. And + * characterizes how the Sensor behaves while static. + * + * The test takes a set of samples from the sensor under test, and calculates the Standard + * Deviation for each of the axes the Sensor reports data for. The StdDev is compared against + * the expected value documented in the CDD. + * + * The test is susceptible to errors if the device is moving while the test is running, or if + * the Sensor's sampled data indeed falls into a large StdDev. + * + * The assertion associated with the test provides the required data to identify any possible + * issue. It provides: + * - the thread id on which the failure occurred + * - the sensor type and sensor handle that caused the failure + * - the expectation of the test + * - the std dev calculated and the axis it applies to + * Additionally, the device's debug output (adb logcat) dumps the set of values associated with + * the failure to help track down the issue. + */ + public void testStandardDeviation() throws Throwable { + VerifyStandardDeviationOperation operation = new VerifyStandardDeviationOperation( + this, + mSensorType, + mSamplingRateInUs, + mReportLatencyInUs, + mExpectedStandardDeviation); + operation.execute(); + } +} 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 5abdd064606..47b3973c4c8 100644 --- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * 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. @@ -15,7 +15,15 @@ */ package android.hardware.cts.helpers; +import android.content.Context; + +import android.hardware.Sensor; +import android.hardware.SensorManager; + import android.os.Environment; + +import android.test.AndroidTestCase; + import android.util.Log; import java.io.DataOutputStream; @@ -94,9 +102,7 @@ public class SensorCtsHelper { * @param jitterValues The Collection that will contain the computed jitter values. * @return The mean of the jitter Values. */ - public static double getJitterMean( - TestSensorManager.SensorEventForTest events[], - Collection<Double> jitterValues) { + public static double getJitterMean(TestSensorEvent events[], Collection<Double> jitterValues) { ArrayList<Long> timestampDelayValues = new ArrayList<Long>(); double averageTimestampDelay = SensorCtsHelper.getAverageTimestampDelayWithValues(events, timestampDelayValues); @@ -116,7 +122,7 @@ public class SensorCtsHelper { * @return The mean of the frequency values. */ public static double getAverageTimestampDelayWithValues( - TestSensorManager.SensorEventForTest events[], + TestSensorEvent events[], Collection<Long> timestampDelayValues) { for(int i = 1; i < events.length; ++i) { long previousTimestamp = events[i-1].timestamp; @@ -133,7 +139,12 @@ public class SensorCtsHelper { } /** - * NOTE: The bug report is usually written to /sdcard/Downloads + * NOTE: + * - The bug report is usually written to /sdcard/Downloads + * - In order for the test Instrumentation to gather useful data the following permissions are + * required: + * . android.permission.READ_LOGS + * . android.permission.DUMP */ public static void collectBugreport(String collectorId) throws IOException, InterruptedException { @@ -173,17 +184,55 @@ public class SensorCtsHelper { } } - public static void performOperationInThreads(int numberOfThreadsToUse, Runnable operation) - throws InterruptedException { - ArrayList<Thread> threads = new ArrayList<Thread>(); - for(int i = 0; i < numberOfThreadsToUse; ++i) { - threads.add(new Thread(operation)); + public static Sensor getSensor(AndroidTestCase testCase, int sensorType) { + SensorManager sensorManager = (SensorManager)testCase.getContext().getSystemService( + Context.SENSOR_SERVICE); + testCase.assertNotNull(sensorManager); + Sensor sensor = sensorManager.getDefaultSensor(sensorType); + if(sensor == null) { + throw new SensorNotSupportedException(sensorType); } + return sensor; + } + + public static <TReference extends Number> double getFrequencyInHz(TReference samplingRateInUs) { + return 1000000000 / samplingRateInUs.doubleValue(); + } - while(!threads.isEmpty()) { - Thread thread = threads.remove(0); - thread.join(); + public static String formatAssertionMessage( + String verificationName, + Sensor sensor, + String format, + Object ... params) { + return formatAssertionMessage(verificationName, null, sensor, format, params); + } + + public static String formatAssertionMessage( + String verificationName, + SensorTestOperation test, + Sensor sensor, + String format, + Object ... params) { + StringBuilder builder = new StringBuilder(); + + // identify the verification + builder.append(verificationName); + builder.append("| "); + // add test context information + if(test != null) { + builder.append(test.toString()); + builder.append("| "); } + // add context information + builder.append( + SensorTestInformation.getSensorName(sensor.getType())); + builder.append(", handle:"); + builder.append(sensor.getHandle()); + builder.append("| "); + // add the custom formatting + builder.append(String.format(format, params)); + + return builder.toString(); } /** @@ -195,7 +244,3 @@ public class SensorCtsHelper { } } } - - - - diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorManagerTestVerifier.java index 98a0af06168..f7f55c9e5d2 100644 --- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorManagerTestVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * 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. @@ -16,12 +16,15 @@ 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 android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; +import android.test.AndroidTestCase; import java.io.Closeable; @@ -35,150 +38,146 @@ 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. - * 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. + * 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. */ -public class TestSensorManager implements Closeable { +public class SensorManagerTestVerifier implements Closeable { private final int WAIT_TIMEOUT_IN_SECONDS = 30; - private Assert mAssert; - private SensorManager mSensorManager; - private Sensor mSensorUnderTest; + private final Assert mAssert; + private final SensorManager mSensorManager; + private final Sensor mSensorUnderTest; + private final int mSamplingRateInUs; + private final int mReportLatencyInUs; + private TestSensorListener mEventListener; - public TestSensorManager(Assert assertionObject, SensorManager sensorManager, Sensor sensor) { - mAssert = assertionObject; - mSensorManager = sensorManager; - mSensorUnderTest = sensor; + /** + * Construction methods. + */ + public SensorManagerTestVerifier( + AndroidTestCase testCase, + int sensorType, + int samplingRateInUs, + int reportLatencyInUs) { + mAssert = testCase; + + mSensorManager = (SensorManager)testCase.getContext().getSystemService( + Context.SENSOR_SERVICE); + mSensorUnderTest = SensorCtsHelper.getSensor(testCase, sensorType); + mSamplingRateInUs = samplingRateInUs; + mReportLatencyInUs = reportLatencyInUs; - mEventListener = new TestSensorListener(); + mEventListener = new TestSensorListener(mSensorUnderTest); } + /** + * Members + */ public void close() { this.unregisterListener(); mEventListener = null; - mSensorUnderTest = null; - } - - public SensorManager getUnderlyingSensorManager() { - return mSensorManager; } - public Sensor getSensorUnderTest() { + public Sensor getUnderlyingSensor() { return mSensorUnderTest; } - public void registerListener(int delay, String debugInfo) { - mAssert.assertTrue( - "registerListener| " + debugInfo, - mSensorManager.registerListener(mEventListener, mSensorUnderTest, delay)); - } - - public void registerListener(int delay) { - registerListener(delay, ""); - } - - public void registerBatchListener(int delay, int reportLatency, String debugInfo) { + public void registerListener(String debugInfo) { boolean result = mSensorManager.registerListener( mEventListener, mSensorUnderTest, - delay, - reportLatency); - mAssert.assertTrue("registerBatchListener| " + debugInfo, result); + mSamplingRateInUs, + mReportLatencyInUs); + String message = SensorCtsHelper.formatAssertionMessage( + "registerListener", + mSensorUnderTest, + debugInfo); + mAssert.assertTrue(message, result); } - public void registerBatchListener(int delay, int reportLatency) { - registerBatchListener(delay, reportLatency, ""); + public void registerListener() { + this.registerListener(""); } public void unregisterListener() { mSensorManager.unregisterListener(mEventListener, mSensorUnderTest); } - public SensorEventForTest[] getEvents(int count, String debugInfo) { + public TestSensorEvent[] getEvents(int count, String debugInfo) { mEventListener.waitForEvents(count, debugInfo); - SensorEventForTest[] events = mEventListener.getAllEvents(); + TestSensorEvent[] events = mEventListener.getAllEvents(); mEventListener.clearEvents(); return events; } - public SensorEventForTest[] getEvents(int count) { + public TestSensorEvent[] getEvents(int count) { return this.getEvents(count, ""); } - public SensorEventForTest[] collectEvents( - int collectionDelay, - int eventCount, - String debugInfo) { - this.registerListener(collectionDelay, debugInfo); - SensorEventForTest[] events = this.getEvents(eventCount, debugInfo); + public TestSensorEvent[] collectEvents(int eventCount, String debugInfo) { + this.registerListener(debugInfo); + TestSensorEvent[] events = this.getEvents(eventCount, debugInfo); this.unregisterListener(); return events; } - public SensorEventForTest[] collectEvents(int collectionDelay, int eventCount) { - return this.collectEvents(collectionDelay, eventCount, ""); + public TestSensorEvent[] collectEvents(int eventCount) { + return this.collectEvents(eventCount, ""); } - public SensorEventForTest[] collectBatchEvents( - int collectionDelay, - int batchReportLatency, - int eventCount, - String debugInfo) { - this.registerBatchListener(collectionDelay, batchReportLatency, debugInfo); - SensorEventForTest[] events = this.getEvents(eventCount, debugInfo); - this.unregisterListener(); - - return events; - } - - public SensorEventForTest[] collectBatchEvents( - int collectionDelay, - int batchReportLatency, - int eventCount) { - return this.collectBatchEvents(collectionDelay, batchReportLatency, eventCount, ""); + public void startFlush() { + String message = SensorCtsHelper.formatAssertionMessage( + "Flush", + mSensorUnderTest, + "" /* format */); + mAssert.assertTrue(message, mSensorManager.flush(mEventListener)); } public void waitForFlush() throws InterruptedException { - mAssert.assertTrue( - String.format("flush| sensorType:%d", mSensorUnderTest.getType()), - mSensorManager.flush(mEventListener)); mEventListener.waitForFlushComplete(); } + public void flush() throws InterruptedException { + this.startFlush(); + this.waitForFlush(); + } + /** - * Definition of support test classes. + * Support methods for clients of this class. */ - public class SensorEventForTest { - public final Sensor sensor; - public final long timestamp; - public final int accuracy; - public final float values[]; - - public SensorEventForTest(SensorEvent event) { - values = new float[event.values.length]; - System.arraycopy(event.values, 0, values, 0, event.values.length); - - sensor = event.sensor; - timestamp = event.timestamp; - accuracy = event.accuracy; - } + public Assert verifier() { + return mAssert; + } + + public int getUnderlyingType() { + return mSensorUnderTest.getType(); } + /** + * Definition of support test classes. + */ private class TestSensorListener implements SensorEventListener2 { - private final ConcurrentLinkedDeque<SensorEventForTest> mSensorEventsList = - new ConcurrentLinkedDeque<SensorEventForTest>(); + private final Sensor mSensorUnderTest; + + private final ConcurrentLinkedDeque<TestSensorEvent> mSensorEventsList = + new ConcurrentLinkedDeque<TestSensorEvent>(); + private volatile CountDownLatch mEventLatch; private volatile CountDownLatch mFlushLatch = new CountDownLatch(1); + public TestSensorListener(Sensor sensor) { + mSensorUnderTest = sensor; + } + @Override public void onSensorChanged(SensorEvent event) { CountDownLatch latch = mEventLatch; if(latch != null) { // copy the event because there is no better way to do this in the platform - mSensorEventsList.addLast(new SensorEventForTest(event)); + mSensorEventsList.addLast(new TestSensorEvent(event)); latch.countDown(); } } @@ -200,9 +199,11 @@ public class TestSensorManager implements Closeable { public void waitForFlushComplete() throws InterruptedException { CountDownLatch latch = mFlushLatch; if(latch != null) { - mAssert.assertTrue( + String message = SensorCtsHelper.formatAssertionMessage( "WaitForFlush", - latch.await(WAIT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)); + mSensorUnderTest, + "" /* format */); + mAssert.assertTrue(message, latch.await(WAIT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)); } } @@ -216,24 +217,26 @@ public class TestSensorManager implements Closeable { boolean awaitCompleted = mEventLatch.await(WAIT_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); // TODO: can we collect bug reports on error based only if needed? env var? - String assertMessage = String.format( - "WaitForEvents| count:%d, available:%d, %s", + String message = SensorCtsHelper.formatAssertionMessage( + "WaitForEvents", + mSensorUnderTest, + "count:%d, available:%d, %s", eventCount, mSensorEventsList.size(), timeoutInfo); - mAssert.assertTrue(assertMessage, awaitCompleted); + mAssert.assertTrue(message, awaitCompleted); } catch(InterruptedException e) { } finally { mEventLatch = null; } } - public SensorEventForTest getLastEvent() { + public TestSensorEvent getLastEvent() { return mSensorEventsList.getLast(); } - public SensorEventForTest[] getAllEvents() { - return mSensorEventsList.toArray(new SensorEventForTest[0]); + public TestSensorEvent[] getAllEvents() { + return mSensorEventsList.toArray(new TestSensorEvent[0]); } public void clearEvents() { diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorNotSupportedException.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorNotSupportedException.java new file mode 100644 index 00000000000..4c413d7346d --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorNotSupportedException.java @@ -0,0 +1,31 @@ +/* + * 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; + +/** + * Exception that indicates that a given sensor is not supported in the device. + * This exception can be caught in tests to safely ignore test cases that are not necessary in a + * given environment. + */ +public class SensorNotSupportedException extends RuntimeException { + public SensorNotSupportedException(int sensorType) { + super(String.format( + "Sensor '%s' of type %d is not supported.", + SensorTestInformation.getSensorName(sensorType), + sensorType)); + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestCase.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestCase.java new file mode 100644 index 00000000000..4bd0eed2e6a --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestCase.java @@ -0,0 +1,40 @@ +/* + * 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 android.test.AndroidTestCase; + +import android.util.Log; + +/** + * Test Case class that handles gracefully sensors that are not available in the device. + */ +public abstract class SensorTestCase extends AndroidTestCase { + protected final String LOG_TAG = "TestRunner"; + + protected SensorTestCase() {} + + @Override + public void runTest() throws Throwable { + try { + super.runTest(); + } catch (SensorNotSupportedException e) { + // the sensor is not supported/available in the device, log a warning and skip the test + Log.w(LOG_TAG, e.getMessage()); + } + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestInformation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestInformation.java new file mode 100644 index 00000000000..f7bdbb70d09 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestInformation.java @@ -0,0 +1,152 @@ +/* + * 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 android.hardware.Sensor; + +import android.test.AndroidTestCase; + +import java.security.InvalidParameterException; + +/** + * A 'property' bag of sensor information used for testing purposes. + */ +public class SensorTestInformation { + private SensorTestInformation() {} + + public static int getAxisCount(int sensorType) { + switch(sensorType) { + case Sensor.TYPE_ACCELEROMETER: + return 3; + case Sensor.TYPE_MAGNETIC_FIELD: + return 3; +// case Sensor.TYPE_ORIENTATION: +// return "Orientation"; + case Sensor.TYPE_GYROSCOPE: + return 3; +// case Sensor.TYPE_LIGHT: +// return "Light"; +// case Sensor.TYPE_PRESSURE: +// return "Pressure"; +// case Sensor.TYPE_TEMPERATURE: +// return "Temperature"; +// case Sensor.TYPE_PROXIMITY: +// return "Proximity"; +// case Sensor.TYPE_GRAVITY: +// return "Gravity"; +// case Sensor.TYPE_LINEAR_ACCELERATION: +// return "Linear Acceleration"; +// case Sensor.TYPE_ROTATION_VECTOR: +// return "Rotation Vector"; +// case Sensor.TYPE_RELATIVE_HUMIDITY: +// return "Relative Humidity"; +// case Sensor.TYPE_AMBIENT_TEMPERATURE: +// return "Ambient Temperature"; +// case Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED: +// return "Magnetic Field Uncalibrated"; +// case Sensor.TYPE_GAME_ROTATION_VECTOR: +// return "Game Rotation Vector"; +// case Sensor.TYPE_GYROSCOPE_UNCALIBRATED: +// return "Gyroscope Uncalibrated"; +// case Sensor.TYPE_SIGNIFICANT_MOTION: +// return "Significant Motion"; +// case Sensor.TYPE_STEP_DETECTOR: +// return "Step Detector"; +// case Sensor.TYPE_STEP_COUNTER: +// return "Step Counter"; +// case Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR: +// return "Geomagnetic Rotation Vector"; + default: + throw new InvalidParameterException( + String.format("Invalid sensorType:%d", sensorType)); + } + } + + public static String getSensorName(int sensorType) { + String name; + switch(sensorType) { + case Sensor.TYPE_ACCELEROMETER: + name = "Accelerometer"; + break; + case Sensor.TYPE_MAGNETIC_FIELD: + name = "Magnetic Field"; + break; + case Sensor.TYPE_ORIENTATION: + name = "Orientation"; + break; + case Sensor.TYPE_GYROSCOPE: + name = "Gyroscope"; + break; + case Sensor.TYPE_LIGHT: + name = "Light"; + break; + case Sensor.TYPE_PRESSURE: + name = "Pressure"; + break; + case Sensor.TYPE_TEMPERATURE: + name = "Temperature"; + break; + case Sensor.TYPE_PROXIMITY: + name = "Proximity"; + break; + case Sensor.TYPE_GRAVITY: + name = "Gravity"; + break; + case Sensor.TYPE_LINEAR_ACCELERATION: + name = "Linear Acceleration"; + break; + case Sensor.TYPE_ROTATION_VECTOR: + name = "Rotation Vector"; + break; + case Sensor.TYPE_RELATIVE_HUMIDITY: + name = "Relative Humidity"; + break; + case Sensor.TYPE_AMBIENT_TEMPERATURE: + name = "Ambient Temperature"; + break; + case Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED: + name = "Magnetic Field Uncalibrated"; + break; + case Sensor.TYPE_GAME_ROTATION_VECTOR: + name = "Game Rotation Vector"; + break; + case Sensor.TYPE_GYROSCOPE_UNCALIBRATED: + name = "Gyroscope Uncalibrated"; + break; + case Sensor.TYPE_SIGNIFICANT_MOTION: + name = "Significant Motion"; + break; + case Sensor.TYPE_STEP_DETECTOR: + name = "Step Detector"; + break; + case Sensor.TYPE_STEP_COUNTER: + name = "Step Counter"; + break; + case Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR: + name = "Geomagnetic Rotation Vector"; + break; + default: + name = "<Unknown>"; + } + return String.format("%s (%d)", name, sensorType); + } + + public static int getMaxSamplingRateInUs(AndroidTestCase testCase, int sensorType) { + Sensor sensor = SensorCtsHelper.getSensor(testCase, sensorType); + return sensor.getMinDelay(); + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestOperation.java new file mode 100644 index 00000000000..11b113fab21 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestOperation.java @@ -0,0 +1,118 @@ +/* + * 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; + +/** + * Base test class that supports a basic test operation performed in a sensor. + * The class follows a command patter as a base for its work. + * + * Remarks: + * - The class wraps verifications and test checks that are needed to verify the operation. + * - The operation runs in a background thread where it performs the bulk of its work. + */ +public abstract class SensorTestOperation { + private final SensorTestExceptionHandler mExceptionHandler = new SensorTestExceptionHandler(); + + protected final String LOG_TAG = "TestRunner"; + protected final int WAIT_TIMEOUT_IN_MILLISECONDS = 30 * 1000; + + private Thread mThread; + + protected int mIterationCount; + + /** + * Public API definition. + */ + public synchronized void start() throws Throwable { + if(mThread != null) { + throw new IllegalStateException("The operation has already been started."); + } + + mThread = new Thread() { + @Override + public void run() { + try { + doWork(); + } catch (Throwable e) { + // log the exception so it can be sent back to the appropriate test thread + this.getUncaughtExceptionHandler().uncaughtException(this, e); + } + } + }; + + ++mIterationCount; + mThread.setUncaughtExceptionHandler(mExceptionHandler); + mThread.start(); + } + + public synchronized void waitForCompletion() throws Throwable { + if(mThread == null) { + // let a wait on a stopped operation to be no-op + return; + } + mThread.join(WAIT_TIMEOUT_IN_MILLISECONDS); + mThread = null; + mExceptionHandler.rethrow(); + } + + public void execute() throws Throwable { + this.start(); + this.waitForCompletion(); + } + + @Override + public String toString() { + return String.format("ThreadId:%d, Iteration:%d", mThread.getId(), mIterationCount); + } + + /** + * Subclasses implement this method to perform the work associated with the operation they + * represent. + */ + protected abstract void doWork() throws Throwable; + + /** + * Private helpers. + */ + private class SensorTestExceptionHandler implements Thread.UncaughtExceptionHandler { + private final Object mLock = new Object(); + + private Throwable mThrowable; + + @Override + public void uncaughtException(Thread thread, Throwable throwable) { + synchronized(mLock) { + // the fist exception is in general the one that is more interesting + if(mThrowable != null) { + return; + } + mThrowable = throwable; + } + } + + public void rethrow() throws Throwable { + Throwable throwable; + synchronized(mLock) { + throwable = mThrowable; + mThrowable = null; + } + if(throwable != null) { + throw throwable; + } + } + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java new file mode 100644 index 00000000000..1a2cdfe7f60 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java @@ -0,0 +1,41 @@ +/* + * 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 android.hardware.Sensor; +import android.hardware.SensorEvent; + +/** + * Test class to wrap SensorEvent. + * It currently only provides a way to clone SensorEvent data, but in the future it can contain + * verifications and test checks. + */ +public class TestSensorEvent { + public final Sensor sensor; + public final long timestamp; + public final int accuracy; + public final float values[]; + + public TestSensorEvent(SensorEvent event) { + values = new float[event.values.length]; + System.arraycopy(event.values, 0, values, 0, event.values.length); + + sensor = event.sensor; + timestamp = event.timestamp; + accuracy = event.accuracy; + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/ParallelCompositeSensorTestOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/ParallelCompositeSensorTestOperation.java new file mode 100644 index 00000000000..3730f4be715 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/ParallelCompositeSensorTestOperation.java @@ -0,0 +1,54 @@ +/* + * 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.sensorTestOperations; + +import android.hardware.cts.helpers.SensorTestOperation; + +import java.util.ArrayList; + +/** + * A test operation that groups a set of SensorTestOperations and allows to execute them all in + * parallel. + * This class can be combined to compose other primitive SensorTestOperations. + */ +public class ParallelCompositeSensorTestOperation extends SensorTestOperation { + private final ArrayList<SensorTestOperation> mOperations = new ArrayList<SensorTestOperation>(); + + /** + * There is no synchronization + * @param operations + */ + public void add(SensorTestOperation ... operations) { + synchronized (mOperations) { + for(SensorTestOperation operation : operations) { + mOperations.add(operation); + } + } + } + + @Override + protected void doWork() throws Throwable { + synchronized (mOperations) { + for(SensorTestOperation operation : mOperations) { + operation.start(); + } + for(SensorTestOperation operation : mOperations) { + operation.waitForCompletion(); + } + } + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/RepeatingSensorTestOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/RepeatingSensorTestOperation.java new file mode 100644 index 00000000000..7a3c45018b4 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/RepeatingSensorTestOperation.java @@ -0,0 +1,39 @@ +/* + * 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.sensorTestOperations; + +import android.hardware.cts.helpers.SensorTestOperation; + +/** + * High level SensorTestOperation that executes the inner operation in a loop. + */ +public class RepeatingSensorTestOperation extends SensorTestOperation { + private final SensorTestOperation mSensorTestOperation; + private final int mRepetitionCount; + + public RepeatingSensorTestOperation(SensorTestOperation operation, int repetitionCount) { + mSensorTestOperation = operation; + mRepetitionCount = repetitionCount; + } + + @Override + protected void doWork() throws Throwable { + for(int i = 0; i < mRepetitionCount; ++i) { + mSensorTestOperation.execute(); + } + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/SequentialCompositeSensorTestOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/SequentialCompositeSensorTestOperation.java new file mode 100644 index 00000000000..4b921680eae --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/SequentialCompositeSensorTestOperation.java @@ -0,0 +1,51 @@ +/* + * 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.sensorTestOperations; + +import android.hardware.cts.helpers.SensorTestOperation; + +import java.util.ArrayList; + +/** + * A test operation that groups a set of SensorTestOperations and allows to execute them in a + * sequence, each operation executes in the order they are added to the composite container. + * This class can be combined to compose other primitive SensorTestOperations. + */ +public class SequentialCompositeSensorTestOperation extends SensorTestOperation { + private final ArrayList<SensorTestOperation> mOperations = new ArrayList<SensorTestOperation>(); + + /** + * There is no synchronization + * @param operations + */ + public void add(SensorTestOperation ... operations) { + synchronized (mOperations) { + for(SensorTestOperation operation : operations) { + mOperations.add(operation); + } + } + } + + @Override + protected void doWork() throws Throwable { + synchronized (mOperations) { + for(SensorTestOperation operation : mOperations) { + operation.execute(); + } + } + } +} 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 new file mode 100644 index 00000000000..a4e5642c8d8 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyEventOrderingOperation.java @@ -0,0 +1,61 @@ +/* + * 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.sensorTestOperations; + +import android.hardware.cts.helpers.SensorCtsHelper; +import android.hardware.cts.helpers.SensorManagerTestVerifier; +import android.hardware.cts.helpers.SensorTestOperation; +import android.hardware.cts.helpers.TestSensorEvent; + +import android.test.AndroidTestCase; + +/** + * Test Operation class that validates the ordering of sensor events. + */ +public class VerifyEventOrderingOperation extends SensorTestOperation { + private SensorManagerTestVerifier mSensor; + + public VerifyEventOrderingOperation( + AndroidTestCase testCase, + int sensorType, + int samplingRateInUs, + int reportLatencyInUs) { + mSensor = new SensorManagerTestVerifier( + testCase, + sensorType, + samplingRateInUs, + reportLatencyInUs); + } + + @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; + String message = SensorCtsHelper.formatAssertionMessage( + "Ordering", + this, + mSensor.getUnderlyingSensor(), + "position:%d, previous:%d, timestamp:%d", + i, + previousTimestamp, + timestamp); + mSensor.verifier().assertTrue(message, previousTimestamp < timestamp); + } + } +} 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 new file mode 100644 index 00000000000..79b835caa70 --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyJitteringOperation.java @@ -0,0 +1,93 @@ +/* + * 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.sensorTestOperations; + +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.TestSensorEvent; + +import android.test.AndroidTestCase; + +import android.util.Log; + +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +/** + * Test Operation class that validates the sampling rate jittering of a given sensor. + * + * Remarks: + * - In order to guarantee proper results in any environment, the maximum sampling rate supported by + * the Sensor is used, this guarantees the frequency reference for the test. + */ +public class VerifyJitteringOperation extends SensorTestOperation { + protected SensorManagerTestVerifier mSensor; + protected long mExpectedtimestampInNs; + protected long mThresholdPercentage; + protected long mThresholdInNs; + + public VerifyJitteringOperation( + AndroidTestCase testCase, + int sensorType, + int reportLatencyInUs, + int thresholdPercentageOfNs) throws InvalidParameterException { + if(thresholdPercentageOfNs < 0) { + throw new InvalidParameterException("thresholdPercentageOfNs needs to be >= 0"); + } + // use the max sampling frequency the sensor reports to guarantee the results + int maxSamplingRateInUs = SensorTestInformation.getMaxSamplingRateInUs(testCase, sensorType); + mSensor = new SensorManagerTestVerifier( + testCase, + sensorType, + maxSamplingRateInUs, + reportLatencyInUs); + // set expectations + mExpectedtimestampInNs = TimeUnit.NANOSECONDS.convert( + maxSamplingRateInUs, + TimeUnit.MICROSECONDS); + mThresholdPercentage = thresholdPercentageOfNs; + mThresholdInNs = mExpectedtimestampInNs / mThresholdPercentage; + } + + @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)", + this, + mSensor.getUnderlyingSensor(), + "expected:%dns(%d%%), actual:%fns(%.2f%%)", + mThresholdInNs, + mThresholdPercentage, + percentile95InNs, + actualPercentValue); + mSensor.verifier().fail(message); + } + } +} 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 new file mode 100644 index 00000000000..1ff8cde531a --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyMaximumFrequencyOperation.java @@ -0,0 +1,96 @@ +/* + * 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.sensorTestOperations; + +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.TestSensorEvent; + +import android.test.AndroidTestCase; + +import android.util.Log; + +import java.security.InvalidParameterException; +import java.util.ArrayList; + +import java.util.concurrent.TimeUnit; + +/** + * Test Operation class that validates the max sampling rate of a given sensor. + * + * Remarks: + * - In order to guarantee proper results in any environment, the maximum sampling rate supported by + * the Sensor is used, this guarantees the frequency reference for the test. + */ +public class VerifyMaximumFrequencyOperation extends SensorTestOperation { + protected SensorManagerTestVerifier mSensor; + protected long mExpectedTimestampInNs; + protected long mThresholdPercentage; + protected long mThresholdInNs; + + public VerifyMaximumFrequencyOperation( + AndroidTestCase testCase, + int sensorType, + int reportLatencyInUs, + int thresholdPercentageOfNs) throws InvalidParameterException { + if(thresholdPercentageOfNs < 0) { + throw new InvalidParameterException("thresholdPercentageOfNs needs to be >= 0"); + } + // use the max sampling frequency the sensor reports to guarantee the results + int maxSamplingRateInUs = SensorTestInformation.getMaxSamplingRateInUs(testCase, sensorType); + mSensor = new SensorManagerTestVerifier( + testCase, + sensorType, + maxSamplingRateInUs, + reportLatencyInUs); + // set expectations + mExpectedTimestampInNs = TimeUnit.NANOSECONDS.convert( + maxSamplingRateInUs, + TimeUnit.MICROSECONDS); + mThresholdPercentage = thresholdPercentageOfNs; + mThresholdInNs = mExpectedTimestampInNs / mThresholdPercentage; + } + + @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( + "Frequency", + this, + mSensor.getUnderlyingSensor(), + "expected:%dns(%.2fHz), actual:%fns(%.2fHz), threshold:%dns(%d%%)", + mExpectedTimestampInNs, + SensorCtsHelper.getFrequencyInHz(mExpectedTimestampInNs), + frequencyMeanInUs, + SensorCtsHelper.getFrequencyInHz(frequencyMeanInUs), + mThresholdInNs, + mThresholdPercentage); + mSensor.verifier().fail(message); + } + } +} diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyNormOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyNormOperation.java new file mode 100644 index 00000000000..75998db2c4f --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyNormOperation.java @@ -0,0 +1,80 @@ +/* + * Copyri 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.sensorTestOperations; + +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.TestSensorEvent; + +import android.test.AndroidTestCase; + +/** + * 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 { + private SensorManagerTestVerifier mSensor; + private int mAxisCount; + private double mReferenceValue; + private double mThreshold; + + public VerifyNormOperation( + AndroidTestCase testCase, + int sensorType, + int samplingRateInUs, + float referenceValue, + float threshold) { + mSensor = new SensorManagerTestVerifier( + testCase, + sensorType, + samplingRateInUs, + 0 /*reportLatencyInUs*/); + // set expectations + mAxisCount = SensorTestInformation.getAxisCount(mSensor.getUnderlyingType()); + mReferenceValue = referenceValue; + mThreshold = threshold; + } + + @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(", "); + } + norm = Math.sqrt(norm); + + String message = SensorCtsHelper.formatAssertionMessage( + "Norm", + this, + mSensor.getUnderlyingSensor(), + "expected:%f, threshold:%f, actual:%f ( %s)", + mReferenceValue, + mThreshold, + norm, + valuesBuilder.toString()); + mSensor.verifier().assertTrue(message, Math.abs(mReferenceValue - norm) <= mThreshold); + } +} 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 new file mode 100644 index 00000000000..dd4df7242be --- /dev/null +++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorTestOperations/VerifyStandardDeviationOperation.java @@ -0,0 +1,81 @@ +/* + * 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.sensorTestOperations; + +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.TestSensorEvent; + +import android.test.AndroidTestCase; + +import android.util.Log; + +import java.util.ArrayList; + +/** + * Test Operation class that validates the standard deviation of a given sensor. + */ +public class VerifyStandardDeviationOperation extends SensorTestOperation { + private SensorManagerTestVerifier mSensor; + private int mAxisCount; + private double mExpectedStandardDeviation; + + public VerifyStandardDeviationOperation( + AndroidTestCase testCase, + int sensorType, + int samplingRateInUs, + int reportLatencyInUs, + float expectedStandardDeviation) { + mSensor = new SensorManagerTestVerifier( + testCase, + sensorType, + samplingRateInUs, + reportLatencyInUs); + // set expectations + mAxisCount = SensorTestInformation.getAxisCount(mSensor.getUnderlyingType()); + mExpectedStandardDeviation = 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); + mSensor.verifier().fail(message); + } + } + } +} |