Java tutorial
/* * 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 java.util.Timer; import java.util.TimerTask; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import com.android.cts.verifier.R; import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity; import com.android.cts.verifier.sensors.helpers.SensorTestScreenManipulator; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.Sensor; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; import android.hardware.cts.helpers.SensorNotSupportedException; import android.hardware.cts.helpers.TestSensorEnvironment; import android.hardware.cts.helpers.SuspendStateMonitor; import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.SystemClock; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import junit.framework.Assert; /** * Test cases for Significant Motion sensor. * They use walking motion to change the location and trigger Significant Motion. */ public class SignificantMotionTestActivity extends SensorCtsVerifierTestActivity { public SignificantMotionTestActivity() { super(SignificantMotionTestActivity.class); } // acceptable time difference between event time and system time private static final long MAX_ACCEPTABLE_EVENT_TIME_DELAY_NANOS = TimeUnit.MILLISECONDS.toNanos(500); // acceptable time difference between event time and AP wake up time. private static final long MAX_ACCEPTABLE_DELAY_EVENT_AP_WAKE_UP_NS = TimeUnit.MILLISECONDS.toNanos(2000); // time to wait for SMD after the device has gone into suspend. Even after // 45 secs if SMD does not trigger, the test will fail. private static final long ALARM_WAKE_TIME_DELAY_MS = TimeUnit.SECONDS.toMillis(45); // 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 static final int EVENT_VALUES_LENGTH = 1; private static final float EXPECTED_EVENT_VALUE = 1.0f; private static String ACTION_ALARM = "SignificantMotionTestActivity.ACTION_ALARM"; private SensorManager mSensorManager; private Sensor mSensorSignificantMotion; private TriggerVerifier mVerifier; private SensorTestScreenManipulator mScreenManipulator; /** * Test cases. */ @SuppressWarnings("unused") public String testTrigger() throws Throwable { return runTest(R.string.snsr_significant_motion_test_trigger, true /* isMotionExpected */, false /* cancelEventNotification */, false /* vibrate */); } @SuppressWarnings("unused") public String testNotTriggerAfterCancel() throws Throwable { return runTest(R.string.snsr_significant_motion_test_cancel, false /* isMotionExpected */, true /* cancelEventNotification */, false /* vibrate */); } /** * Verifies that Significant Motion is not trigger by the vibrator motion. */ @SuppressWarnings("unused") 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. */ @SuppressWarnings("unused") public String testInHandDoesNotTrigger() throws Throwable { return runTest(R.string.snsr_significant_motion_test_in_hand, false /* isMotionExpected */, false /* cancelEventNotification */, false /* vibrate */); } @SuppressWarnings("unused") public String testSittingDoesNotTrigger() throws Throwable { return runTest(R.string.snsr_significant_motion_test_sitting, false /* isMotionExpected */, false /* cancelEventNotification */, false /* vibrate */); } @SuppressWarnings("unused") public String testTriggerDeactivation() throws Throwable { SensorTestLogger logger = getTestLogger(); logger.logInstructions(R.string.snsr_significant_motion_test_deactivation); waitForUserToBegin(); TriggerVerifier verifier = new TriggerVerifier(); mSensorManager.requestTriggerSensor(verifier, mSensorSignificantMotion); logger.logWaitForSound(); // wait for the first event to trigger verifier.verifyEventTriggered(); // wait for a second event not to trigger String result = verifier.verifyEventNotTriggered(); playSound(); return result; } public static class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent alarm_intent = new Intent(context, SignificantMotionTestActivity.class); alarm_intent.setAction(SignificantMotionTestActivity.ACTION_ALARM); LocalBroadcastManager.getInstance(context).sendBroadcastSync(alarm_intent); } } public BroadcastReceiver myBroadCastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mVerifier.releaseLatch(); mScreenManipulator.turnScreenOn(); try { playSound(); } catch (InterruptedException e) { // Ignore ... } } }; @SuppressWarnings("unused") public String testAPWakeUpOnSMDTrigger() throws Throwable { SensorTestLogger logger = getTestLogger(); logger.logInstructions(R.string.snsr_significant_motion_ap_suspend); waitForUserToBegin(); mVerifier = new TriggerVerifier(); mSensorManager.requestTriggerSensor(mVerifier, mSensorSignificantMotion); long testStartTimeNs = SystemClock.elapsedRealtimeNanos(); Handler handler = new Handler(Looper.getMainLooper()); SuspendStateMonitor suspendStateMonitor = new SuspendStateMonitor(); Intent intent = new Intent(this, AlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + ALARM_WAKE_TIME_DELAY_MS, pendingIntent); try { // Wait for the first event to trigger. Device is expected to go into suspend here. mVerifier.verifyEventTriggered(); long eventTimeStampNs = mVerifier.getTimeStampForTriggerEvent(); long endTimeNs = SystemClock.elapsedRealtimeNanos(); long lastWakeupTimeNs = TimeUnit.MILLISECONDS.toNanos(suspendStateMonitor.getLastWakeUpTime()); Assert.assertTrue(getString(R.string.snsr_device_did_not_go_into_suspend), testStartTimeNs < lastWakeupTimeNs && lastWakeupTimeNs < endTimeNs); long timestampDelta = Math.abs(lastWakeupTimeNs - eventTimeStampNs); Assert.assertTrue( String.format(getString(R.string.snsr_device_did_not_wake_up_at_trigger), TimeUnit.NANOSECONDS.toMillis(lastWakeupTimeNs), TimeUnit.NANOSECONDS.toMillis(eventTimeStampNs)), timestampDelta < MAX_ACCEPTABLE_DELAY_EVENT_AP_WAKE_UP_NS); } finally { am.cancel(pendingIntent); suspendStateMonitor.cancel(); mScreenManipulator.turnScreenOn(); playSound(); } return null; } /** * @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 * requested first and request will be cancelled * @param vibrate If TRUE, vibration will be concurrent with the test * @throws Throwable */ private String runTest(int instructionsResId, boolean isMotionExpected, boolean cancelEventNotification, boolean vibrate) throws Throwable { SensorTestLogger logger = getTestLogger(); logger.logInstructions(instructionsResId); waitForUserToBegin(); if (vibrate) { vibrate(VIBRATE_DURATION_MILLIS); } TriggerVerifier verifier = new TriggerVerifier(); boolean success = mSensorManager.requestTriggerSensor(verifier, mSensorSignificantMotion); Assert.assertTrue(getString(R.string.snsr_significant_motion_registration, success), success); if (cancelEventNotification) { Assert.assertTrue(getString(R.string.snsr_significant_motion_cancelation), mSensorManager.cancelTriggerSensor(verifier, mSensorSignificantMotion)); } logger.logWaitForSound(); String result; try { if (isMotionExpected) { result = verifier.verifyEventTriggered(); } else { result = verifier.verifyEventNotTriggered(); } } finally { mSensorManager.cancelTriggerSensor(verifier, mSensorSignificantMotion); playSound(); } return result; } @Override protected void activitySetUp() { mSensorManager = (SensorManager) getApplicationContext().getSystemService(Context.SENSOR_SERVICE); mSensorSignificantMotion = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION); if (mSensorSignificantMotion == null) { throw new SensorNotSupportedException(Sensor.TYPE_SIGNIFICANT_MOTION); } mScreenManipulator = new SensorTestScreenManipulator(this); try { mScreenManipulator.initialize(this); } catch (InterruptedException e) { } PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); LocalBroadcastManager.getInstance(this).registerReceiver(myBroadCastReceiver, new IntentFilter(ACTION_ALARM)); } @Override protected void activityCleanUp() { if (mScreenManipulator != null) { mScreenManipulator.turnScreenOff(); } LocalBroadcastManager.getInstance(this).unregisterReceiver(myBroadCastReceiver); } @Override protected void onDestroy() { super.onDestroy(); if (mScreenManipulator != null) { mScreenManipulator.close(); } } /** * Helper Trigger listener for testing. * It cannot be reused. */ private class TriggerVerifier extends TriggerEventListener { private volatile CountDownLatch mCountDownLatch; private volatile TriggerEventRegistry mEventRegistry; private volatile long mTimestampForTriggeredEvent = 0; // TODO: refactor out if needed private class TriggerEventRegistry { public final TriggerEvent triggerEvent; public final long realtimeTimestampNanos; public TriggerEventRegistry(TriggerEvent event, long realtimeTimestampNanos) { this.triggerEvent = event; this.realtimeTimestampNanos = realtimeTimestampNanos; } } public void onTrigger(TriggerEvent event) { long elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos(); mEventRegistry = new TriggerEventRegistry(event, elapsedRealtimeNanos); mCountDownLatch.countDown(); } public void releaseLatch() { if (mCountDownLatch != null) { mCountDownLatch.countDown(); } } public long getTimeStampForTriggerEvent() { return mTimestampForTriggeredEvent; } 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 != null); 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); String sensorName = event.sensor.getName(); int valuesLength = event.values.length; String valuesLengthMessage = getString(R.string.snsr_event_length, EVENT_VALUES_LENGTH, valuesLength, sensorName); Assert.assertEquals(valuesLengthMessage, EVENT_VALUES_LENGTH, valuesLength); float value = event.values[0]; String valuesMessage = getString(R.string.snsr_event_value, EXPECTED_EVENT_VALUE, value, sensorName); Assert.assertEquals(valuesMessage, EXPECTED_EVENT_VALUE, value); long deltaThreshold = MAX_ACCEPTABLE_EVENT_TIME_DELAY_NANOS + TestSensorEnvironment.getSensorMaxDetectionLatencyNs(event.sensor); return assertTimestampSynchronization(event.timestamp, registry.realtimeTimestampNanos, deltaThreshold, sensorName); } public String verifyEventNotTriggered() throws Throwable { TriggerEventRegistry registry = awaitForEvent(); TriggerEvent event = registry.triggerEvent; String eventMessage = getString(R.string.snsr_significant_motion_event_unexpected, event != null); 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; // Save the last timestamp when the event triggered. if (mEventRegistry != null && mEventRegistry.triggerEvent != null) { mTimestampForTriggeredEvent = mEventRegistry.triggerEvent.timestamp; } mEventRegistry = null; playSound(); return registry != null ? registry : new TriggerEventRegistry(null, 0); } } }