blob: e94ddbfb92c68c8bfb98497307b2eef3854af5b4 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cts.helpers.sensorverification;
import junit.framework.Assert;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.Log;
import android.hardware.Sensor;
import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
import android.util.SparseIntArray;
import com.android.compatibility.common.util.Stat;
import java.util.LinkedList;
import java.util.List;
/**
* A {@link ISensorVerification} which verifies that the sensor jitter is in an acceptable range.
*/
public class JitterVerification extends AbstractSensorVerification {
public static final String PASSED_KEY = "jitter_passed";
// sensorType: threshold (% of expected period)
private static final SparseIntArray DEFAULTS = new SparseIntArray(12);
// Max allowed jitter (in percentage).
private static final int GRACE_FACTOR = 2;
private static final int THRESHOLD_PERCENT_FOR_HIFI_SENSORS = 1 * GRACE_FACTOR;
static {
// Use a method so that the @deprecation warning can be set for that method only
setDefaults();
}
private final int mThresholdAsPercentage;
private final List<Long> mTimestamps = new LinkedList<Long>();
/**
* Construct a {@link JitterVerification}
*
* @param thresholdAsPercentage the acceptable margin of error as a percentage
*/
public JitterVerification(int thresholdAsPercentage) {
mThresholdAsPercentage = thresholdAsPercentage;
}
/**
* Get the default {@link JitterVerification} for a sensor.
*
* @param environment the test environment
* @return the verification or null if the verification does not apply to the sensor.
*/
public static JitterVerification getDefault(TestSensorEnvironment environment) {
int sensorType = environment.getSensor().getType();
int threshold = DEFAULTS.get(sensorType, -1);
if (threshold == -1) {
return null;
}
boolean hasHifiSensors = environment.getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_HIFI_SENSORS);
if (hasHifiSensors) {
threshold = THRESHOLD_PERCENT_FOR_HIFI_SENSORS;
}
return new JitterVerification(threshold);
}
/**
* Verify that the 95th percentile of the jitter is in the acceptable range. Add
* {@value #PASSED_KEY} and {@value SensorStats#JITTER_95_PERCENTILE_PERCENT_KEY} keys to
* {@link SensorStats}.
*
* @throws AssertionError if the verification failed.
*/
@Override
public void verify(TestSensorEnvironment environment, SensorStats stats) {
int timestampsCount = mTimestamps.size();
if (timestampsCount < 2 || environment.isSensorSamplingRateOverloaded()) {
// the verification is not reliable in environments under load
stats.addValue(PASSED_KEY, true);
return;
}
double[] jitters = getJitterValues();
double jitter95PercentileNs = Stat.get95PercentileValue(jitters);
long firstTimestamp = mTimestamps.get(0);
long lastTimestamp = mTimestamps.get(timestampsCount - 1);
long measuredPeriodNs = (lastTimestamp - firstTimestamp) / (timestampsCount - 1);
double jitter95PercentilePercent = (jitter95PercentileNs * 100.0) / measuredPeriodNs;
stats.addValue(SensorStats.JITTER_95_PERCENTILE_PERCENT_KEY, jitter95PercentilePercent);
boolean success = (jitter95PercentilePercent < mThresholdAsPercentage);
stats.addValue(PASSED_KEY, success);
if (!success) {
String message = String.format(
"Jitter out of range: measured period=%dns, jitter(95th percentile)=%.2f%%"
+ " (expected < %d%%)",
measuredPeriodNs,
jitter95PercentilePercent,
mThresholdAsPercentage);
Assert.fail(message);
}
}
/**
* {@inheritDoc}
*/
@Override
public JitterVerification clone() {
return new JitterVerification(mThresholdAsPercentage);
}
/**
* {@inheritDoc}
*/
@Override
protected void addSensorEventInternal(TestSensorEvent event) {
mTimestamps.add(event.timestamp);
}
/**
* Get the list of all jitter values. Exposed for unit testing.
*/
double[] getJitterValues() {
int length = mTimestamps.size() - 1;
double[] deltas = new double[length];
for (int i = 0; i < length; i++) {
deltas[i] = mTimestamps.get(i + 1) - mTimestamps.get(i);
}
double deltaMean = Stat.getAverage(deltas);
double[] jitters = new double[length];
for (int i = 0; i < length; i++) {
jitters[i] = Math.abs(deltas[i] - deltaMean);
}
return jitters;
}
@SuppressWarnings("deprecation")
private static void setDefaults() {
DEFAULTS.put(Sensor.TYPE_ACCELEROMETER, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_GYROSCOPE, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_ORIENTATION, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_PRESSURE, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_GRAVITY, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_LINEAR_ACCELERATION, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_ROTATION_VECTOR, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_GAME_ROTATION_VECTOR, Integer.MAX_VALUE);
DEFAULTS.put(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, Integer.MAX_VALUE);
}
}