Fix Significant Motion test crash, and use of resources, and base classes.
b/16984049
Change-Id: I21096015be11a61efd309d3cc7b68e41e48e0a41
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index da93a59..5186ce3 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -732,7 +732,8 @@
android:value="android.hardware.sensor.accelerometer" />
</activity>
- <activity android:name=".sensors.SensorSynchronizationTestActivity"
+ <!-- TODO: enable test when a more reliable way to identify time synchronization is available -->
+ <!--activity android:name=".sensors.SensorSynchronizationTestActivity"
android:label="@string/snsr_synch_test"
android:screenOrientation="nosensor">
<intent-filter>
@@ -742,7 +743,7 @@
<meta-data android:name="test_category" android:value="@string/test_category_sensors" />
<meta-data android:name="test_required_features"
android:value="android.hardware.sensor.gyroscope" />
- </activity>
+ </activity-->
<activity android:name=".location.LocationModeOffTestActivity"
android:label="@string/location_mode_off_test">
diff --git a/apps/CtsVerifier/res/layout/snsr_semi_auto_test.xml b/apps/CtsVerifier/res/layout/snsr_semi_auto_test.xml
index 92039f0..c816021 100644
--- a/apps/CtsVerifier/res/layout/snsr_semi_auto_test.xml
+++ b/apps/CtsVerifier/res/layout/snsr_semi_auto_test.xml
@@ -13,15 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/log_text"
- android:gravity="bottom"
- android:layout_height="wrap_content"
+ android:layout_height="0dp"
android:layout_width="wrap_content"
- android:maxLines="27"
+ android:layout_weight="1"
+ android:layout_gravity="bottom"
android:paddingBottom="5dip"
android:paddingLeft="10dip"
android:paddingRight="10dip"
@@ -30,13 +31,11 @@
/>
<Button android:id="@+id/next_button"
- android:layout_alignParentBottom="true"
- android:layout_centerInParent="true"
+ android:layout_gravity="center_horizontal"
android:layout_height="wrap_content"
- android:layout_marginBottom="20dip"
- android:layout_width="120dip"
+ android:layout_width="wrap_content"
+ android:paddingBottom="5dip"
android:text="@string/next_button_text"
- android:textSize="24dip"
/>
-</RelativeLayout>
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 321673f..2d5e203 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -503,6 +503,21 @@
<!-- Significant Motion -->
<string name="snsr_significant_motion_test">Significant Motion Tests</string>
+ <string name="snsr_significant_motion_event_arrival">Event expected to trigger. Current: %1$s</string>
+ <string name="snsr_significant_motion_event_type">Event expected to be of type=%1$d. Found=%2$d</string>
+ <string name="snsr_significant_motion_event_length">Event values expected to have size=%1$d. Found=%2$d</string>
+ <string name="snsr_significant_motion_event_value">Event value[0] expected to be of value=%1$f. Found=%2$f</string>
+ <string name="snsr_significant_motion_event_time">Event timestamp expected to be at=%1$d. Found=%2$d. Delta=%3$d. Threshold=%4$d.</string>
+ <string name="snsr_significant_motion_event_unexpected">Event not expected to trigger. Current: %1$s.</string>
+ <string name="snsr_significant_motion_disable_info">Significant Motion is expected to disable itself after it triggers once.</string>
+ <string name="snsr_significant_motion_test_trigger">Once you begin the test, you will need to walk for Significant Motion to be detected.</string>
+ <string name="snsr_significant_motion_test_cancel">Once you begin the test, you will need to walk to ensure Significant Motion is not reported after trigger canceled.</string>
+ <string name="snsr_significant_motion_test_vibration">Leave the device in a level surface. Once you begin the test, the device will vibrate to ensure that Significant Motion is not triggered.</string>
+ <string name="snsr_significant_motion_test_in_hand">Once you begin the test, hold the device in your hand while you perform natural hand movements.</string>
+ <string name="snsr_significant_motion_test_sitting">Once you begin the test, keep the device in your pocket and move naturally while sitting in a chair.</string>
+ <string name="snsr_significant_motion_test_deactivation">Once you begin the test, you will need to walk to ensure Significant Motion triggers only once.</string>
+ <string name="snsr_significant_motion_registration">Expected to be able to register for TriggerSensor. Found=%b.</string>
+ <string name="snsr_significant_motion_cancelation">Expected to be able to cancel TriggerSensor. Found=%b.</string>
<!-- Strings for Sample Test Activities -->
<string name="share_button_text">Share</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BaseSensorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BaseSensorTestActivity.java
index 418e52f..b4859ce 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BaseSensorTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BaseSensorTestActivity.java
@@ -21,12 +21,14 @@
import android.app.Activity;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.hardware.cts.helpers.SensorNotSupportedException;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
+import android.os.Vibrator;
import android.provider.Settings;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
@@ -284,6 +286,11 @@
}
}
+ protected void vibrate(int timeInMs) {
+ Vibrator vibrator = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE);
+ vibrator.vibrate(timeInMs);
+ }
+
private List<Method> findTestMethods() {
ArrayList<Method> testMethods = new ArrayList<Method>();
for (Method method : mTestClass.getDeclaredMethods()) {
@@ -299,7 +306,7 @@
private SensorTestDetails executeTest(Method testMethod) {
SensorTestDetails testDetails = new SensorTestDetails();
- testDetails.name = String.format("%s.%s", getTestClassName(), testMethod.getName());
+ testDetails.name = String.format("%s#%s", getTestClassName(), testMethod.getName());
try {
appendText(getString(R.string.snsr_executing_test, testDetails.name));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
index 9258ba6..15eeba6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
@@ -16,120 +16,112 @@
package com.android.cts.verifier.sensors;
+import com.android.cts.verifier.R;
+
import junit.framework.Assert;
-import android.annotation.TargetApi;
-import android.app.Activity;
+
import android.content.Context;
-import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
-import android.media.AudioManager;
-import android.media.ToneGenerator;
-import android.os.Build;
import android.os.Bundle;
-import android.os.Vibrator;
+import android.os.SystemClock;
-@TargetApi(Build.VERSION_CODES.KITKAT)
-class TriggerListener extends TriggerEventListener {
- // how much difference between system time and event time considered to be
- // acceptable [msec]
- private final long MAX_ACCEPTABLE_EVENT_TIME_DELAY_MILLIS = 500;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
- // state used for internal recording of the event detection
- private boolean mEventDetected = false;
-
- public void onTrigger(TriggerEvent event) {
- final long NANOS_PER_MS = 1000000L;
-
- Assert.assertEquals("values should be of length 1 for significant motion event", 1,
- event.values.length);
- Assert.assertEquals("values[0] should be 1.0 for significant motion event", 1.0f,
- event.values[0]);
-
- // Check that timestamp is within MAX_ACCEPTABLE_EVENT_TIME_DELAY_MILLIS
- // It might take time to determine Significant Motion, but then that
- // event should be reported to the host in a timely fashion.
- long timeReportedMillis = event.timestamp / NANOS_PER_MS;
- long timeActualMillis = System.currentTimeMillis();
- Assert.assertEquals("Incorrect time reported in the event",
- timeReportedMillis, timeActualMillis, MAX_ACCEPTABLE_EVENT_TIME_DELAY_MILLIS);
-
- // Verify event type is truly Significant Motion
- Assert.assertEquals("Triggered event type is not Significant Motion",
- event.sensor.getType(), Sensor.TYPE_SIGNIFICANT_MOTION);
-
- // Event detected flag should be false if indeed only one event per
- // request
- Assert.assertFalse("Significant Motion sensor did not automatically "
- + "disable itself from subsequent detection", mEventDetected);
-
- // audible cue to indicate Significant Motion occurred
- beep();
- mEventDetected = true;
+/**
+ * Test cases for Significant Motion sensor.
+ * They use walking motion to change the location and trigger Significant Motion.
+ */
+public class SignificantMotionTestActivity extends BaseSensorTestActivity {
+ public SignificantMotionTestActivity() {
+ super(SignificantMotionTestActivity.class);
}
- public boolean wasEventTriggered() {
- return mEventDetected;
- }
+ // acceptable time difference between event time and system time
+ private static final long MAX_ACCEPTABLE_EVENT_TIME_DELAY_MILLIS = 500;
- public void reset() {
- mEventDetected = false;
- }
+ // time for the test to wait for a trigger
+ private static final int TRIGGER_MAX_DELAY_SECONDS = 30;
+ private static final int VIBRATE_DURATION_MILLIS = 10000;
- private void beep() {
- final ToneGenerator tg = new ToneGenerator(
- AudioManager.STREAM_NOTIFICATION, 100);
- tg.startTone(ToneGenerator.TONE_PROP_BEEP);
- }
-}
-
-@TargetApi(Build.VERSION_CODES.KITKAT)
-public class SignificantMotionTestActivity extends BaseSensorSemiAutomatedTestActivity {
- // minimum time for test to consider valid [msec]
- private final int MIN_TEST_TIME_MILLIS = 20000;
- private final int VIBRATE_DURATION_MILLIS = 10000;
+ private static final int EVENT_VALUES_LENGTH = 1;
+ private static final float EXPECTED_EVENT_VALUE = 1.0f;
private SensorManager mSensorManager;
private Sensor mSensorSignificantMotion;
- private final TriggerListener mTriggeredListener = new TriggerListener();
- private long mTestStartTimestamp;
- private static int sNumPassedTests = 0;
- @Override
- protected void onRun() throws Throwable {
- switch (sNumPassedTests) {
- // avoid re-running passed tests, so purposely want fallthroughs here
- case 0:
- // use walking to change location and trigger significant motion
- runTest("walk 15 steps for significant motion to be detected", true, false, false);
- case 1:
- runTest("walk another 15 steps to ensure significant motion "
- + "is not reported after trigger cancelled", false, true, false);
- case 2:
- // use vibrator to ensure significant motion is not triggered
- runTest("leave the device on a level surface", false, false, true);
- case 3:
- // use natural motion that does not change location to ensure
- // significant motion is not triggered
- runTest("hold the device in hand while performing natural "
- + "hand movements", false, false, false);
- case 4:
- runTest("keep the device in pocket and move naturally while "
- + "sitting in a chair", false, false, false);
- default:
- break;
- }
+ /**
+ * Test cases.
+ */
+ public String testTrigger() throws Throwable {
+ return runTest(
+ R.string.snsr_significant_motion_test_trigger,
+ true /* isMotionExpected */,
+ false /* cancelEventNotification */,
+ false /* vibrate */);
}
- private void vibrateDevice(int timeInMs) {
- Vibrator vibrator = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE);
- vibrator.vibrate(timeInMs);
+ public String testNotTriggerAfterCancell() throws Throwable {
+ return runTest(
+ R.string.snsr_significant_motion_test_cancel,
+ false /* isMotionExpected */,
+ true /* cancelEventNotification */,
+ false /* vibrate */);
}
/**
- * @param instructions Instruction to be shown to testers
+ * Verifies that Significant Motion is not trigger by the vibrator motion.
+ */
+ public String testVibratorDoesNotTrigger() throws Throwable {
+ return runTest(
+ R.string.snsr_significant_motion_test_vibration,
+ false /* isMotionExpected */,
+ false /* cancelEventNotification */,
+ true /* vibrate */);
+ }
+
+ /**
+ * Verifies that the natural motion of keeping the device in hand does not change the location.
+ * It ensures that Significant Motion will not trigger in that scenario.
+ */
+ public String testInHandDoesNotTrigger() throws Throwable {
+ return runTest(
+ R.string.snsr_significant_motion_test_in_hand,
+ false /* isMotionExpected */,
+ false /* cancelEventNotification */,
+ false /* vibrate */);
+ }
+
+ public String testSittingDoesNotTrigger() throws Throwable {
+ return runTest(
+ R.string.snsr_significant_motion_test_sitting,
+ false /* isMotionExpected */,
+ false /* cancelEventNotification */,
+ false /* vibrate */);
+ }
+
+ public String testTriggerDeactivation() throws Throwable {
+ appendText(R.string.snsr_significant_motion_test_deactivation);
+ waitForUser();
+
+ TriggerVerifier verifier = new TriggerVerifier();
+ mSensorManager.requestTriggerSensor(verifier, mSensorSignificantMotion);
+ appendText(R.string.snsr_test_play_sound);
+
+ // wait for the first event to trigger
+ verifier.verifyEventTriggered();
+
+ // wait for a second event not to trigger
+ String result = verifier.verifyEventNotTriggered();
+ playSound();
+ return result;
+ }
+
+ /**
+ * @param instructionsResId Instruction to be shown to testers
* @param isMotionExpected Should the device detect significant motion event
* for this test?
* @param cancelEventNotification If TRUE, motion notifications will be
@@ -137,57 +129,40 @@
* @param vibrate If TRUE, vibration will be concurrent with the test
* @throws Throwable
*/
- private void runTest(String instructions, final boolean isMotionExpected,
- final boolean cancelEventNotification, final boolean vibrate) throws Throwable {
-
- appendText("Click 'Next' and " + instructions);
+ private String runTest(
+ int instructionsResId,
+ boolean isMotionExpected,
+ boolean cancelEventNotification,
+ boolean vibrate) throws Throwable {
+ appendText(instructionsResId);
waitForUser();
if (vibrate) {
- vibrateDevice(VIBRATE_DURATION_MILLIS);
+ vibrate(VIBRATE_DURATION_MILLIS);
}
- mTestStartTimestamp = System.currentTimeMillis();
- startMeasurements(cancelEventNotification);
-
- long testTime = System.currentTimeMillis() - mTestStartTimestamp;
-
- while (!mTriggeredListener.wasEventTriggered()
- && testTime < MIN_TEST_TIME_MILLIS) {
- int timeWaitSec = Math
- .round((MIN_TEST_TIME_MILLIS - testTime) / 1000);
- clearText();
- appendText("Current test: " + instructions);
- appendText(
- String.format("%d seconds for the test to complete", timeWaitSec),
- Color.GRAY);
-
- Thread.sleep(1000);
- testTime = System.currentTimeMillis() - mTestStartTimestamp;
+ TriggerVerifier verifier = new TriggerVerifier();
+ Assert.assertTrue(
+ getString(R.string.snsr_significant_motion_registration),
+ mSensorManager.requestTriggerSensor(verifier, mSensorSignificantMotion));
+ if (cancelEventNotification) {
+ Assert.assertTrue(
+ getString(R.string.snsr_significant_motion_cancelation),
+ mSensorManager.cancelTriggerSensor(verifier, mSensorSignificantMotion));
}
- clearText();
- appendText("Current test: " + instructions);
- playSound();
- verifyMeasurements(isMotionExpected);
- sNumPassedTests++;
- }
+ appendText(R.string.snsr_test_play_sound);
- private void startMeasurements(boolean isCancelTriggerRequested) throws Throwable {
- mTriggeredListener.reset();
-
- mSensorManager.requestTriggerSensor(mTriggeredListener, mSensorSignificantMotion);
-
- if (isCancelTriggerRequested) {
- mSensorManager.cancelTriggerSensor(mTriggeredListener, mSensorSignificantMotion);
+ String result;
+ try {
+ if (isMotionExpected) {
+ result = verifier.verifyEventTriggered();
+ } else {
+ result = verifier.verifyEventNotTriggered();
+ }
+ } finally {
+ mSensorManager.cancelTriggerSensor(verifier, mSensorSignificantMotion);
}
- }
-
- private void verifyMeasurements(boolean isMotionExpected) throws Throwable {
- Assert.assertEquals("Significant motion event expected/detected mismatch: "
- + isMotionExpected + " / " + mTriggeredListener.wasEventTriggered(),
- isMotionExpected, mTriggeredListener.wasEventTriggered());
- appendText("Significant motion event " + isMotionExpected + " as expected", Color.GRAY);
- logSuccess();
+ return result;
}
@Override
@@ -196,29 +171,102 @@
mSensorManager = (SensorManager) getApplicationContext()
.getSystemService(Context.SENSOR_SERVICE);
-
mSensorSignificantMotion = mSensorManager
.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
}
- @Override
- protected void onResume() {
- super.onResume();
+ /**
+ * Helper Trigger listener for testing.
+ * It cannot be reused.
+ */
+ private class TriggerVerifier extends TriggerEventListener {
+ private volatile CountDownLatch mCountDownLatch;
+ private volatile TriggerEventRegistry mEventRegistry;
- if (mSensorManager != null && mSensorSignificantMotion != null) {
- mSensorManager.requestTriggerSensor(mTriggeredListener,
- mSensorSignificantMotion);
+ private class TriggerEventRegistry {
+ public final TriggerEvent triggerEvent;
+ public final long realtimeTimestampNanos;
+
+ public TriggerEventRegistry(TriggerEvent event, long realtimeTimestampNanos) {
+ this.triggerEvent = event;
+ this.realtimeTimestampNanos = realtimeTimestampNanos;
+ }
}
- }
- @Override
- protected void onPause() {
- super.onPause();
+ public void onTrigger(TriggerEvent event) {
+ long elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
+ mEventRegistry = new TriggerEventRegistry(event, elapsedRealtimeNanos);
+ mCountDownLatch.countDown();
+ }
- if (mSensorManager != null && mSensorSignificantMotion != null) {
- mSensorManager.cancelTriggerSensor(mTriggeredListener,
- mSensorSignificantMotion);
+ public String verifyEventTriggered() throws Throwable {
+ TriggerEventRegistry registry = awaitForEvent();
+
+ // verify an event arrived, and it is indeed a Significant Motion event
+ TriggerEvent event = registry.triggerEvent;
+ String eventArrivalMessage =
+ getString(R.string.snsr_significant_motion_event_arrival, event);
+ Assert.assertNotNull(eventArrivalMessage, event);
+
+ int eventType = event.sensor.getType();
+ String eventTypeMessage = getString(
+ R.string.snsr_significant_motion_event_type,
+ Sensor.TYPE_SIGNIFICANT_MOTION,
+ eventType);
+ Assert.assertEquals(eventTypeMessage, Sensor.TYPE_SIGNIFICANT_MOTION, eventType);
+
+ int valuesLength = event.values.length;
+ String valuesLengthMessage = getString(
+ R.string.snsr_significant_motion_event_length,
+ EVENT_VALUES_LENGTH,
+ valuesLength);
+ Assert.assertEquals(valuesLengthMessage, EVENT_VALUES_LENGTH, valuesLength);
+
+ float value = event.values[0];
+ String valuesMessage = getString(
+ R.string.snsr_significant_motion_event_value,
+ EXPECTED_EVENT_VALUE,
+ value);
+ Assert.assertEquals(valuesMessage, EXPECTED_EVENT_VALUE, value);
+
+ // Check that timestamp is within MAX_ACCEPTABLE_EVENT_TIME_DELAY_MILLIS: it might take
+ // time to determine Significant Motion, but then that event should be reported to the
+ // host in a timely fashion.
+ long eventTimestamp = event.timestamp;
+ long elapsedRealtimeNanos = registry.realtimeTimestampNanos;
+ long timestampDelta = Math.abs(eventTimestamp - elapsedRealtimeNanos);
+ String timestampMessage = getString(
+ R.string.snsr_significant_motion_event_time,
+ elapsedRealtimeNanos,
+ eventTimestamp,
+ timestampDelta,
+ MAX_ACCEPTABLE_EVENT_TIME_DELAY_MILLIS);
+ Assert.assertTrue(
+ timestampMessage,
+ timestampDelta < MAX_ACCEPTABLE_EVENT_TIME_DELAY_MILLIS);
+ return timestampMessage;
+ }
+
+ public String verifyEventNotTriggered() throws Throwable {
+ TriggerEventRegistry registry = awaitForEvent();
+
+ TriggerEvent event = registry.triggerEvent;
+ String eventMessage =
+ getString(R.string.snsr_significant_motion_event_unexpected, event);
+ Assert.assertNull(eventMessage, event);
+ return eventMessage;
+ }
+
+ private TriggerEventRegistry awaitForEvent() throws InterruptedException {
+ mCountDownLatch = new CountDownLatch(1);
+ mCountDownLatch.await(TRIGGER_MAX_DELAY_SECONDS, TimeUnit.SECONDS);
+
+ TriggerEventRegistry registry = mEventRegistry;
+ mEventRegistry = null;
+
+ playSound();
+ return registry != null ? registry : new TriggerEventRegistry(null, 0);
}
}
}