blob: 89a20d24ae72c246a76b455fc676fdd8e83daa55 [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 com.android.cts.verifier.sensors;
import com.android.cts.verifier.R;
import junit.framework.Assert;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener2;
import android.hardware.SensorManager;
import android.hardware.cts.helpers.SensorNotSupportedException;
import android.hardware.cts.helpers.TestSensorEvent;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.SystemClock;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Activity that verifies batching capabilities for sensors
* (https://source.android.com/devices/sensors/batching.html).
*
* If a sensor supports the batching mode, FifoReservedEventCount for that sensor should be greater
* than one.
*/
public class BatchingTestActivity extends BaseSensorTestActivity implements SensorEventListener2 {
public BatchingTestActivity() {
super(BatchingTestActivity.class);
}
private final long TWO_SECONDS_MILLIS = TimeUnit.SECONDS.toMillis(2);
private static final long DATA_COLLECTION_TIME_IN_MS = TimeUnit.SECONDS.toMillis(10);
private final long MIN_BATCH_TIME_NANOS = TimeUnit.SECONDS.toNanos(5);
private final long MAX_BATCH_REPORT_LATENCY_US = DATA_COLLECTION_TIME_IN_MS * 500;
private final List<TestSensorEvent> mSensorEvents = new ArrayList<TestSensorEvent>();
private SensorManager mSensorManager;
private volatile Sensor mSensorUnderTest;
private volatile long mTimeFirstBatchedEventReceivedNanos;
private CountDownLatch mSensorEventReceived;
private CountDownLatch mFlushCompleteReceived;
private PowerManager.WakeLock mWakeLock;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected void activitySetUp() throws InterruptedException {
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "BatchingTests");
mSensorFeaturesDeactivator.requestDeactivationOfFeatures();
mWakeLock.acquire();
}
@Override
protected void activityCleanUp() throws InterruptedException {
mWakeLock.release();
mSensorFeaturesDeactivator.requestToRestoreFeatures();
}
// TODO: refactor to discover all available sensors of each type and dinamically generate test
// cases for all of them
public String testStepCounter() throws Throwable {
return runTest(Sensor.TYPE_STEP_COUNTER, R.string.snsr_batching_walking_needed);
}
public String testStepDetector() throws Throwable {
return runTest(Sensor.TYPE_STEP_DETECTOR, R.string.snsr_batching_walking_needed);
}
public String testProximity() throws Throwable {
return runTest(Sensor.TYPE_PROXIMITY, R.string.snsr_interaction_needed);
}
public String testLight() throws Throwable {
return runTest(Sensor.TYPE_LIGHT, R.string.snsr_interaction_needed);
}
// TODO: move sensors that do not require interaction to CTS
public String testGameRotationVector() throws Throwable {
return runTest(Sensor.TYPE_GAME_ROTATION_VECTOR, R.string.snsr_no_interaction);
}
public String testGeomagneticRotationVector() throws Throwable {
return runTest(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, R.string.snsr_no_interaction);
}
public String testAccelerometer() throws Throwable {
return runTest(Sensor.TYPE_ACCELEROMETER, R.string.snsr_no_interaction);
}
public String testGyroscope() throws Throwable {
return runTest(Sensor.TYPE_GYROSCOPE, R.string.snsr_no_interaction);
}
public String testGyroscopeUncalibrated() throws Throwable {
return runTest(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, R.string.snsr_no_interaction);
}
public String testMagneticField() throws Throwable {
return runTest(Sensor.TYPE_MAGNETIC_FIELD, R.string.snsr_no_interaction);
}
public String testMagneticFieldUncalibrated() throws Throwable {
return runTest(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, R.string.snsr_no_interaction);
}
public String testRotationVector() throws Throwable {
return runTest(Sensor.TYPE_ROTATION_VECTOR, R.string.snsr_no_interaction);
}
// TODO: split batching and flush scenarios
private String runTest(int sensorType, int instructionsResId) throws Throwable {
mSensorUnderTest = mSensorManager.getDefaultSensor(sensorType);
// TODO: add exception for batching not supported
if (mSensorUnderTest == null || mSensorUnderTest.getFifoMaxEventCount() < 1) {
throw new SensorNotSupportedException(Sensor.TYPE_STEP_COUNTER);
}
appendText(instructionsResId);
waitForUser();
// Register to wait for first sensor event arrival, and when FIFO has been flushed
mSensorEventReceived = new CountDownLatch(1);
mFlushCompleteReceived = new CountDownLatch(1);
mSensorEvents.clear();
int fifoReservedEventCount = mSensorUnderTest.getFifoReservedEventCount();
int fifoMaxEventCount = mSensorUnderTest.getFifoMaxEventCount();
String fifoMessage = getString(
R.string.snsr_batching_fifo_count,
fifoReservedEventCount,
fifoMaxEventCount);
Assert.assertTrue(fifoMessage, fifoReservedEventCount <= fifoMaxEventCount);
// Time when start batching
mTimeFirstBatchedEventReceivedNanos = 0;
long timeBatchingStartedNanos = SystemClock.elapsedRealtimeNanos();
// Batch with the fastest rate and set report latency large enough to ensure full batching
// occurs
boolean registerResult = mSensorManager.registerListener(
this /* listener */,
mSensorUnderTest,
SensorManager.SENSOR_DELAY_FASTEST,
(int) MAX_BATCH_REPORT_LATENCY_US);
Assert.assertTrue(
getString(R.string.snsr_register_listener, registerResult),
registerResult);
// add a buffer to the duration of the test for timeout
mSensorEventReceived
.await(DATA_COLLECTION_TIME_IN_MS + TWO_SECONDS_MILLIS, TimeUnit.MILLISECONDS);
// TODO: add delayed assertion for await
// verify the minimum batching time
long firstTimeArrivalDelta = mTimeFirstBatchedEventReceivedNanos - timeBatchingStartedNanos;
String firstTimeArrivalMessage = getString(
R.string.snsr_batching_first_event_arrival,
MIN_BATCH_TIME_NANOS,
firstTimeArrivalDelta);
Assert.assertTrue(firstTimeArrivalMessage, firstTimeArrivalDelta >= MIN_BATCH_TIME_NANOS);
// batch a bit more to test the flush
long sleepTime = TimeUnit.NANOSECONDS.toMillis(MIN_BATCH_TIME_NANOS / 2);
Thread.sleep(sleepTime);
mSensorManager.flush(this);
boolean flushAwaitSuccess = mFlushCompleteReceived
.await(DATA_COLLECTION_TIME_IN_MS + TWO_SECONDS_MILLIS, TimeUnit.MILLISECONDS);
Assert.assertTrue(
getString(R.string.snsr_batching_flush_complete, flushAwaitSuccess),
flushAwaitSuccess);
playSound();
// TODO: use SensorTestVerifications to check for event ordering and event gap
return null;
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
long elapsedTime = SystemClock.elapsedRealtimeNanos();
if (sensorEvent.sensor.getType() != mSensorUnderTest.getType()) {
// TODO: add delayed assertion
return;
}
mSensorEvents.add(new TestSensorEvent(sensorEvent, elapsedTime));
if (mTimeFirstBatchedEventReceivedNanos == 0) {
mTimeFirstBatchedEventReceivedNanos = elapsedTime;
mSensorEventReceived.countDown();
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void onFlushCompleted(Sensor sensor) {
mSensorManager.unregisterListener(this);
mFlushCompleteReceived.countDown();
}
}