blob: 683430c465beefe2669a5f391499c56d2fbca193 [file] [log] [blame]
package com.android.cts.verifier.sensors;
import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
import junit.framework.Assert;
import android.annotation.TargetApi;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.cts.helpers.TestSensorEvent;
import android.os.Build;
import java.util.ArrayList;
import java.util.List;
/**
* Test cross-sensor timestamp alignment by detecting major change in each
* sensor and comparing timestamps of that change.
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public class SensorSynchronizationTestActivity
extends SensorCtsVerifierTestActivity
implements SensorEventListener {
public SensorSynchronizationTestActivity() {
super(SensorSynchronizationTestActivity.class);
}
private final double NANOS_PER_MILLI = 1e6;
private final int DATA_COLLECTION_TIME_IN_MS = 5000;
private final int RATE_100HZ_IN_US = 10000;
private final int MAX_CROSS_SENSOR_DELAY_MILLIS = 125;
private final double THRESH_DEGREES = 10.0;
private final double THRESH_RPS = 1.0;
private SensorManager mSensorManager = null;
private List<TestSensorEvent> mSensorEvents = new ArrayList<TestSensorEvent>();
private void startDataCollection() {
mSensorEvents.clear();
mSensorManager = (SensorManager) getApplicationContext()
.getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
RATE_100HZ_IN_US);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
RATE_100HZ_IN_US);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
RATE_100HZ_IN_US);
}
private void stopDataCollection() {
mSensorManager.unregisterListener(this);
}
private void analyzeData() {
int numberOfCollectedEvents = mSensorEvents.size();
Assert.assertTrue("No sensor events collected", numberOfCollectedEvents > 2);
boolean accMovementDetected = false;
boolean magMovementDetected = false;
boolean gyrMovementDetected = false;
long accMovementTimestamp = 0, magMovementTimestamp = 0, gyrMovementTimestamp = 0;
float[] accInitValues = null, magInitValues = null, gyrInitValues = null;
for (int i = 0; i < numberOfCollectedEvents; i++) {
TestSensorEvent event = mSensorEvents.get(i);
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
if (accInitValues == null) {
accInitValues = event.values.clone();
} else if (angleBetweenVecsDegrees(accInitValues, event.values) > THRESH_DEGREES
&& !accMovementDetected) {
accMovementDetected = true;
accMovementTimestamp = event.timestamp;
}
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
if (magInitValues == null) {
magInitValues = event.values.clone();
} else if (angleBetweenVecsDegrees(magInitValues, event.values) > THRESH_DEGREES
&& !magMovementDetected) {
magMovementDetected = true;
magMovementTimestamp = event.timestamp;
}
}
if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
if (gyrInitValues == null) {
gyrInitValues = event.values.clone();
} else if (normVec(event.values) > THRESH_RPS && !gyrMovementDetected) {
gyrMovementDetected = true;
gyrMovementTimestamp = event.timestamp;
}
}
if (accMovementDetected && magMovementDetected && gyrMovementDetected) {
double maxTimestamp = Math.max(accMovementTimestamp,
magMovementTimestamp);
maxTimestamp = Math.max(gyrMovementTimestamp, maxTimestamp);
double minTimestamp = Math.min(accMovementTimestamp,
magMovementTimestamp);
minTimestamp = Math.min(gyrMovementTimestamp, minTimestamp);
double timeDifferenceBetweenMovementMillis =
(maxTimestamp - minTimestamp) / NANOS_PER_MILLI;
appendText(String.format("\nSensor | Relative Timestamp (msec)\n"
+ "Accelerometer | %4.1f\nMagnetometer | %4.1f\nGyroscope | %4.1f\n",
(accMovementTimestamp - minTimestamp) / NANOS_PER_MILLI,
(magMovementTimestamp - minTimestamp) / NANOS_PER_MILLI,
(gyrMovementTimestamp - minTimestamp) / NANOS_PER_MILLI));
Assert.assertEquals(String.format(
"Cross sensor timestamp alignment off by more than %d msec.",
MAX_CROSS_SENSOR_DELAY_MILLIS),
0, timeDifferenceBetweenMovementMillis, MAX_CROSS_SENSOR_DELAY_MILLIS);
appendText(String.format(
"Maximum cross sensor time between movement: %4.1f msec is within "
+ "required tolerance of %4.1f msec",
timeDifferenceBetweenMovementMillis,
(float) MAX_CROSS_SENSOR_DELAY_MILLIS));
break;
}
}
Assert.assertTrue("Accelerometer did not detect any movement", accMovementDetected);
Assert.assertTrue("Magnetometer did not detect any movement", magMovementDetected);
Assert.assertTrue("Gyroscope did not detect any movement", gyrMovementDetected);
}
public String testCrossSensorSynchronization() throws Throwable {
appendText("This test provides a rough indication of cross-sensor timestamp synchronization.");
appendText("Hold device still in hand and click 'Next'");
waitForUserToBegin();
clearText();
appendText("Quickly twist device upside-down and back");
startDataCollection();
Thread.sleep(DATA_COLLECTION_TIME_IN_MS);
stopDataCollection();
analyzeData();
return null;
}
protected double angleBetweenVecsDegrees(float[] vec1, float[] vec2) {
return Math.toDegrees(Math.acos((vec1[0] * vec2[0] + vec1[1] * vec2[1] + vec1[2] * vec2[2])
/ normVec(vec1) / normVec(vec2)));
}
protected double normVec(float[] vec1) {
return Math.sqrt(vec1[0] * vec1[0] + vec1[1] * vec1[1] + vec1[2] * vec1[2]);
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
mSensorEvents.add(new TestSensorEvent(sensorEvent));
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}