Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a527467e authored by Fan Zhang's avatar Fan Zhang Committed by Android (Google) Code Review
Browse files

Merge "Block emergency gestures if the button speed is too fast" into tm-dev

parents e0d9846e bd672716
Loading
Loading
Loading
Loading
+30 −1
Original line number Diff line number Diff line
@@ -74,6 +74,13 @@ public class GestureLauncherService extends SystemService {
     */
    @VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300;

    /**
     * Min time in milliseconds to complete the emergency gesture for it count. If the gesture is
     * completed faster than this, we assume it's not performed by human and the
     * event gets ignored.
     */
    @VisibleForTesting static final int EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS = 160;

    /**
     * Interval in milliseconds in which the power button must be depressed in succession to be
     * considered part of an extended sequence of taps. Note that this is a looser threshold than
@@ -184,6 +191,7 @@ public class GestureLauncherService extends SystemService {
    private int mEmergencyGesturePowerButtonCooldownPeriodMs;

    private long mLastPowerDown;
    private long mFirstPowerDown;
    private long mLastEmergencyGestureTriggered;
    private int mPowerButtonConsecutiveTaps;
    private int mPowerButtonSlowConsecutiveTaps;
@@ -553,10 +561,12 @@ public class GestureLauncherService extends SystemService {
            mLastPowerDown = event.getEventTime();
            if (powerTapInterval >= POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) {
                // Tap too slow, reset consecutive tap counts.
                mFirstPowerDown  = event.getEventTime();
                mPowerButtonConsecutiveTaps = 1;
                mPowerButtonSlowConsecutiveTaps = 1;
            } else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) {
                // Tap too slow for shortcuts
                mFirstPowerDown  = event.getEventTime();
                mPowerButtonConsecutiveTaps = 1;
                mPowerButtonSlowConsecutiveTaps++;
            } else {
@@ -575,7 +585,26 @@ public class GestureLauncherService extends SystemService {
                    intercept = interactive;
                }
                if (mPowerButtonConsecutiveTaps == EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD) {
                    long emergencyGestureSpentTime = event.getEventTime() - mFirstPowerDown;
                    long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
                            mContext.getContentResolver(),
                            Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
                            EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS);
                    if (emergencyGestureSpentTime <= emergencyGestureTapDetectionMinTimeMs) {
                        Slog.i(TAG, "Emergency gesture detected but it's too fast. Gesture time: "
                                + emergencyGestureSpentTime + " ms");
                        // Reset consecutive tap counts.
                        mFirstPowerDown = event.getEventTime();
                        mPowerButtonConsecutiveTaps = 1;
                        mPowerButtonSlowConsecutiveTaps = 1;
                    } else {
                        Slog.i(TAG, "Emergency gesture detected. Gesture time: "
                                + emergencyGestureSpentTime + " ms");
                        launchEmergencyGesture = true;
                        mMetricsLogger.histogram("emergency_gesture_spent_time",
                                (int) emergencyGestureSpentTime);

                    }
                }
            }
            if (mCameraDoubleTapPowerEnabled
+68 −24
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.server;

import static com.android.server.GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
import static com.android.server.GestureLauncherService.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -248,7 +251,7 @@ public class GestureLauncherServiceTest {
        mGestureLauncherService.updateCameraDoubleTapPowerEnabled();

        long eventTime = INITIAL_EVENT_TIME_MILLIS +
                GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
                CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
        boolean interactive = true;
@@ -296,7 +299,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -341,7 +344,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -435,7 +438,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -489,7 +492,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;

        // 2nd button triggers camera
        eventTime += interval;
@@ -578,7 +581,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        // 3 more button presses which should not trigger any gesture (camera gesture disabled)
        for (int i = 0; i < 3; i++) {
            eventTime += interval;
@@ -632,7 +635,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        // 3 more button presses which should not trigger any gesture, but intercepts action.
        for (int i = 0; i < 3; i++) {
            eventTime += interval;
@@ -735,7 +738,7 @@ public class GestureLauncherServiceTest {
                    interactive, outLaunched);
            assertTrue(intercepted);
            assertFalse(outLaunched.value);
            interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
            interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
            eventTime += interval;
        }
    }
@@ -763,11 +766,32 @@ public class GestureLauncherServiceTest {
                    interactive, outLaunched);
            assertTrue(intercepted);
            assertFalse(outLaunched.value);
            interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
            interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
            eventTime += interval;
        }
    }

    @Test
    public void testInterceptPowerKeyDown_triggerEmergency_fiveFastTaps_gestureIgnored() {
        // Trigger emergency by tapping button 5 times
        long eventTime = triggerEmergencyGesture(/* tapIntervalMs= */ 1);

        // Add 1 more millisecond and send the event again.
        eventTime += 1;

        // Subsequent long press is intercepted, but should not trigger any gesture
        KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
                KeyEvent.FLAG_LONG_PRESS);
        MutableBoolean outLaunched = new MutableBoolean(true);
        boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(
                keyEvent,
                /* interactive= */ true,
                outLaunched);
        assertFalse(intercepted);
        assertFalse(outLaunched.value);
    }

    @Test
    public void testInterceptPowerKeyDown_triggerEmergency_longPress_cooldownTriggered() {
        // Enable power button cooldown
@@ -890,7 +914,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
@@ -936,7 +960,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -983,7 +1007,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -1075,7 +1099,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -1120,7 +1144,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -1212,7 +1236,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -1261,7 +1285,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -1306,7 +1330,7 @@ public class GestureLauncherServiceTest {
        assertFalse(intercepted);
        assertFalse(outLaunched.value);

        final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
        final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
        eventTime += interval;
        keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                IGNORED_REPEAT);
@@ -1384,9 +1408,20 @@ public class GestureLauncherServiceTest {

    /**
     * Helper method to trigger emergency gesture by pressing button for 5 times.
     *
     * @return last event time.
     */
    private long triggerEmergencyGesture() {
        return triggerEmergencyGesture(CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1);
    }

    /**
     * Helper method to trigger emergency gesture by pressing button for 5 times with
     * specified interval between each tap
     *
     * @return last event time.
     */
    private long triggerEmergencyGesture(long tapIntervalMs) {
        // Enable emergency power gesture
        withEmergencyGestureEnabledConfigValue(true);
        withEmergencyGestureEnabledSettingValue(true);
@@ -1402,8 +1437,7 @@ public class GestureLauncherServiceTest {
            keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
                    IGNORED_REPEAT);
            mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive, outLaunched);
            final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
            eventTime += interval;
            eventTime += tapIntervalMs;
        }

        // 5th button press should trigger the emergency flow
@@ -1412,12 +1446,22 @@ public class GestureLauncherServiceTest {
        outLaunched.value = false;
        boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
                outLaunched);
        assertTrue(outLaunched.value);
        long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
                mContext.getContentResolver(),
                Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
                EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS);
        assertTrue(intercepted);
        if (tapIntervalMs * 4 > emergencyGestureTapDetectionMinTimeMs) {
            assertTrue(outLaunched.value);
            verify(mUiEventLogger, times(1))
                    .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
            verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();

        } else {
            assertFalse(outLaunched.value);
            verify(mUiEventLogger, never())
                    .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
            verify(mStatusBarManagerInternal, never()).onEmergencyActionLaunchGestureDetected();
        }
        return eventTime;
    }