blob: 6915db3ac40d21bbfd86893756462dd89833174d [file] [log] [blame]
/*
* Copyright (C) 2016 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.SensorAdditionalInfo;
import android.hardware.SensorEventCallback;
import android.hardware.SensorManager;
import android.hardware.cts.helpers.SensorCtsHelper;
import android.util.Log;
import android.content.pm.PackageManager;
import java.lang.Math;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Checks Sensor Additional Information feature functionality.
*/
public class SensorAdditionalInfoTest extends SensorTestCase {
private static final String TAG = "SensorAdditionalInfoTest";
private static final int ALLOWED_ADDITIONAL_INFO_DELIVER_SEC = 3;
private static final int REST_PERIOD_BEFORE_TEST_SEC = 3;
private static final double EPSILON = 1E-6;
private SensorManager mSensorManager;
@Override
protected void setUp() throws Exception {
mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
}
public void testSensorAdditionalInfo() {
if (mSensorManager == null) {
return;
}
List<Sensor> list = mSensorManager.getSensorList(Sensor.TYPE_ALL);
List<String> errors = new ArrayList<String>();
for (Sensor s : list) {
// Only test sensor additional info for Accelerometer, Gyroscope and Magnetometer.
if (s.getType() != Sensor.TYPE_ACCELEROMETER &&
s.getType() != Sensor.TYPE_GYROSCOPE &&
s.getType() != Sensor.TYPE_MAGNETIC_FIELD) {
continue;
}
if (!s.isAdditionalInfoSupported()) {
// check SensorAdditionalInfo is supported for Automotive sensors.
if (getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_AUTOMOTIVE)) {
errors.add("Sensor: " + s.getName() +
", error: AdditionalSensorInfo not supported for Automotive sensor.");
}
continue;
}
try {
runSensorAdditionalInfoTest(s);
} catch (AssertionError e) {
errors.add("Sensor: " + s.getName() + ", error: " + e.getMessage());
}
}
if (errors.size() > 0) {
StringBuilder sb = new StringBuilder();
sb.append("Failed for following reasons: [");
int i = 0;
for (String error : errors) {
sb.append(String.format("%d. %s; ", i++, error));
}
sb.append("]");
fail(sb.toString());
}
}
private void runSensorAdditionalInfoTest(Sensor s) throws AssertionError {
waitBeforeTestStarts();
AdditionalInfoVerifier verifier = new AdditionalInfoVerifier(s);
verifier.reset(false /*flushPending*/);
assertTrue(String.format("Register sensor listener for %s failed.", s.getName()),
mSensorManager.registerListener(verifier, s, SensorManager.SENSOR_DELAY_NORMAL));
try {
assertTrue("Missing additional info at registration: (" + verifier.getState() + ")",
verifier.verify());
assertFalse("Duplicate TYPE_FRAME_BEGIN at: (" +
verifier.getState() + ")", verifier.beginFrameDuplicate());
if (verifier.internalTemperature()) {
assertFalse("Duplicate TYPE_INTERNAL_TEMPERATURE at: (" +
verifier.getState() + ")", verifier.internalTemperatureDuplicate());
}
if (verifier.sampling()) {
assertFalse("Duplicate TYPE_SAMPLING_TEMPERATURE at: (" +
verifier.getState() + ")", verifier.samplingDuplicate());
}
// verify TYPE_SENSOR_PLACEMENT for Automotive.
if (getContext().getPackageManager().
hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
assertTrue("Missing TYPE_SENSOR_PLACEMENT at: (" + verifier.getState() + ")",
verifier.sensorPlacement());
}
if(verifier.sensorPlacement()) {
assertFalse("Duplicate TYPE_SENSOR_PLACEMENT at: (" +
verifier.getState() + ")", verifier.sensorPlacementDuplicate());
assertTrue("Incorrect size of TYPE_SENSOR_PLACEMENT at: (" +
verifier.getState() + ")", verifier.sensorPlacementSizeValid());
if (verifier.sensorPlacementSizeValid()) {
assertTrue("Incorrect rotation matrix of TYPE_SENSOR_PLACEMENT at: (" +
verifier.getState() + ")", verifier.sensorPlacementRotationValid());
}
}
if (verifier.untrackedDelay()) {
assertFalse("Duplicate TYPE_UNTRACKED_DELAY at: (" +
verifier.getState() + ")", verifier.untrackedDelayDuplicate());
}
if (verifier.vec3Calibration()) {
assertFalse("Duplicate TYPE_VEC3_CALIBRATION at: (" +
verifier.getState() + ")", verifier.vec3CalibrationDuplicate());
}
verifier.reset(true /*flushPending*/);
assertTrue("Flush sensor failed.", mSensorManager.flush(verifier));
assertTrue("Missing additional info after flushing: (" + verifier.getState() + ")",
verifier.verify());
} finally {
mSensorManager.unregisterListener(verifier);
}
}
private void waitBeforeTestStarts() {
// wait for sensor system to come to a rest after previous test to avoid flakiness.
try {
SensorCtsHelper.sleep(REST_PERIOD_BEFORE_TEST_SEC, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private class AdditionalInfoVerifier extends SensorEventCallback {
private boolean mBeginFrame = false;
private boolean mBeginFrameDuplicate = false;
private boolean mEndFrame = false;
private boolean mFlushPending = false;
private boolean mInternalTemperature = false;
private boolean mInternalTemperatureDuplicate = false;
private boolean mSampling = false;
private boolean mSamplingDuplicate = false;
private boolean mSensorPlacement = false;
private boolean mSensorPlacementDuplicate = false;
private boolean mIsSensorPlacementSizeValid = false;
private boolean mIsSensorPlacementRotationValid = false;
private boolean mUntrackedDelay = false;
private boolean mUntrackedDelayDuplicate = false;
private boolean mVec3Calibration = false;
private boolean mVec3CalibrationDuplicate = false;
private CountDownLatch mDone;
private final Sensor mSensor;
public AdditionalInfoVerifier(Sensor s) {
mSensor = s;
}
@Override
public void onFlushCompleted(Sensor sensor) {
if (sensor == mSensor) {
mFlushPending = false;
}
}
@Override
public void onSensorAdditionalInfo(SensorAdditionalInfo info) {
if (info.sensor == mSensor && !mFlushPending) {
if (info.type == SensorAdditionalInfo.TYPE_FRAME_BEGIN) {
if (mBeginFrame) {
mBeginFrameDuplicate = true;
return;
}
mBeginFrame = true;
} else if (mBeginFrame &&
info.type == SensorAdditionalInfo.TYPE_INTERNAL_TEMPERATURE) {
if (mInternalTemperature) {
mInternalTemperatureDuplicate = true;
return;
}
mInternalTemperature = true;
} else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_SAMPLING) {
if (mSampling) {
mSamplingDuplicate = true;
return;
}
mSampling = true;
} else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_SENSOR_PLACEMENT) {
if (mSensorPlacement) {
mSensorPlacementDuplicate = true;
return;
}
mSensorPlacement = true;
verifySensorPlacementData(info.floatValues);
} else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_UNTRACKED_DELAY) {
if (mUntrackedDelay) {
mUntrackedDelayDuplicate = true;
return;
}
mUntrackedDelay = true;
} else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_VEC3_CALIBRATION) {
if (mVec3Calibration) {
mVec3CalibrationDuplicate = true;
return;
}
mVec3Calibration = true;
} else if (info.type == SensorAdditionalInfo.TYPE_FRAME_END && mBeginFrame) {
mEndFrame = true;
mDone.countDown();
}
}
}
public void reset(boolean flushPending) {
mFlushPending = flushPending;
mBeginFrame = false;
mEndFrame = false;
mSensorPlacement = false;
mDone = new CountDownLatch(1);
}
public boolean verify() {
boolean ret;
try {
ret = mDone.await(ALLOWED_ADDITIONAL_INFO_DELIVER_SEC, TimeUnit.SECONDS);
} catch (InterruptedException e) {
ret = false;
}
return ret;
}
public String getState() {
return "fp=" + mFlushPending +", b=" + mBeginFrame + ", e=" + mEndFrame;
}
// Checks sensor placement data length and determinant of rotation matrix is 1.
private void verifySensorPlacementData(float[] m) {
if(m.length < 12) {
mIsSensorPlacementSizeValid = false;
return;
}
mIsSensorPlacementSizeValid = true;
double determinant = m[0] * (m[5] * m[10] - m[6] * m[9] ) -
m[1] * (m[4] * m[10] - m[6] * m[8] ) +
m[2] * (m[4] * m[9] - m[5] * m[8] );
mIsSensorPlacementRotationValid = (Math.abs(determinant - 1) < EPSILON);
}
public boolean beginFrameDuplicate() {
return mBeginFrameDuplicate;
}
public boolean internalTemperature() {
return mInternalTemperature;
}
public boolean internalTemperatureDuplicate() {
return mInternalTemperatureDuplicate;
}
public boolean sampling() {
return mSampling;
}
public boolean samplingDuplicate() {
return mSamplingDuplicate;
}
public boolean sensorPlacement() {
return mSensorPlacement;
}
public boolean sensorPlacementDuplicate() {
return mSensorPlacementDuplicate;
}
public boolean sensorPlacementSizeValid() {
return mIsSensorPlacementSizeValid;
}
public boolean sensorPlacementRotationValid() {
return mIsSensorPlacementRotationValid;
}
public boolean untrackedDelay() {
return mUntrackedDelay;
}
public boolean untrackedDelayDuplicate() {
return mUntrackedDelayDuplicate;
}
public boolean vec3Calibration() {
return mVec3Calibration;
}
public boolean vec3CalibrationDuplicate() {
return mVec3CalibrationDuplicate;
}
}
}