Merge "Revert "Introduce SingleKeyGestureDetector to PhoneWindowManager"" into sc-dev
diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java
index 7f55723..84ac124 100644
--- a/services/core/java/com/android/server/policy/KeyCombinationManager.java
+++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java
@@ -102,11 +102,9 @@
}
/**
- * Check if the key event could be intercepted by combination key rule before it is dispatched
- * to a window.
- * Return true if any active rule could be triggered by the key event, otherwise false.
+ * Check if the key event could be triggered by combine key rule before dispatching to a window.
*/
- boolean interceptKey(KeyEvent event, boolean interactive) {
+ void interceptKey(KeyEvent event, boolean interactive) {
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final int keyCode = event.getKeyCode();
final int count = mActiveRules.size();
@@ -119,9 +117,9 @@
// exceed time from first key down.
forAllRules(mActiveRules, (rule)-> rule.cancel());
mActiveRules.clear();
- return false;
+ return;
} else if (count == 0) { // has some key down but no active rule exist.
- return false;
+ return;
}
}
@@ -129,7 +127,7 @@
mDownTimes.put(keyCode, eventTime);
} else {
// ignore old key, maybe a repeat key.
- return false;
+ return;
}
if (mDownTimes.size() == 1) {
@@ -143,7 +141,7 @@
} else {
// Ignore if rule already triggered.
if (mTriggeredRule != null) {
- return true;
+ return;
}
// check if second key can trigger rule, or remove the non-match rule.
@@ -158,7 +156,6 @@
mActiveRules.clear();
if (mTriggeredRule != null) {
mActiveRules.add(mTriggeredRule);
- return true;
}
}
} else {
@@ -171,7 +168,6 @@
}
}
}
- return false;
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1b192e4..c50efc7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -73,8 +73,6 @@
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
-import static com.android.server.policy.SingleKeyGestureDetector.KEY_LONGPRESS;
-import static com.android.server.policy.SingleKeyGestureDetector.KEY_VERYLONGPRESS;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -458,6 +456,7 @@
volatile boolean mPowerKeyHandled;
volatile boolean mBackKeyHandled;
volatile boolean mBeganFromNonInteractive;
+ volatile int mPowerKeyPressCounter;
volatile boolean mEndCallKeyHandled;
volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
volatile boolean mGoingToSleep;
@@ -498,6 +497,7 @@
boolean mHasSoftInput = false;
boolean mHapticTextHandleEnabled;
boolean mUseTvRouting;
+ int mVeryLongPressTimeout;
boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
MetricsLogger mLogger;
boolean mWakeOnDpadKeyPress;
@@ -595,13 +595,14 @@
private final com.android.internal.policy.LogDecelerateInterpolator mLogDecelerateInterpolator
= new LogDecelerateInterpolator(100, 0);
+ private final MutableBoolean mTmpBoolean = new MutableBoolean(false);
+
private boolean mPerDisplayFocusEnabled = false;
private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
private int mPowerButtonSuppressionDelayMillis = POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS;
private KeyCombinationManager mKeyCombinationManager;
- private SingleKeyGestureDetector mSingleKeyGestureDetector;
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
@@ -612,7 +613,10 @@
private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
private static final int MSG_HIDE_BOOT_MESSAGE = 11;
private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
+ private static final int MSG_POWER_DELAYED_PRESS = 13;
+ private static final int MSG_POWER_LONG_PRESS = 14;
private static final int MSG_SHOW_PICTURE_IN_PICTURE_MENU = 15;
+ private static final int MSG_BACK_LONG_PRESS = 16;
private static final int MSG_ACCESSIBILITY_SHORTCUT = 17;
private static final int MSG_BUGREPORT_TV = 18;
private static final int MSG_ACCESSIBILITY_TV = 19;
@@ -620,7 +624,8 @@
private static final int MSG_SYSTEM_KEY_PRESS = 21;
private static final int MSG_HANDLE_ALL_APPS = 22;
private static final int MSG_LAUNCH_ASSIST = 23;
- private static final int MSG_RINGER_TOGGLE_CHORD = 24;
+ private static final int MSG_POWER_VERY_LONG_PRESS = 25;
+ private static final int MSG_RINGER_TOGGLE_CHORD = 26;
private class PolicyHandler extends Handler {
@Override
@@ -661,9 +666,22 @@
case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
launchVoiceAssistWithWakeLock();
break;
+ case MSG_POWER_DELAYED_PRESS:
+ powerPress((Long) msg.obj, msg.arg1 != 0, msg.arg2);
+ finishPowerKeyPress();
+ break;
+ case MSG_POWER_LONG_PRESS:
+ powerLongPress((Long) msg.obj /* eventTime */);
+ break;
+ case MSG_POWER_VERY_LONG_PRESS:
+ powerVeryLongPress();
+ break;
case MSG_SHOW_PICTURE_IN_PICTURE_MENU:
showPictureInPictureMenuInternal();
break;
+ case MSG_BACK_LONG_PRESS:
+ backLongPress();
+ break;
case MSG_ACCESSIBILITY_SHORTCUT:
accessibilityShortcutActivated();
break;
@@ -774,6 +792,13 @@
}
};
+ private Runnable mPossibleVeryLongPressReboot = new Runnable() {
+ @Override
+ public void run() {
+ mActivityManagerInternal.prepareForPossibleShutdown();
+ }
+ };
+
private void handleRingerChordGesture() {
if (mRingerToggleChord == VOLUME_HUSH_OFF) {
return;
@@ -813,13 +838,28 @@
}
}
+ private void interceptBackKeyDown() {
+ mLogger.count("key_back_down", 1);
+ // Reset back key state for long press
+ mBackKeyHandled = false;
+
+ if (hasLongPressOnBackBehavior()) {
+ Message msg = mHandler.obtainMessage(MSG_BACK_LONG_PRESS);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+ }
+ }
// returns true if the key was handled and should not be passed to the user
- private boolean backKeyPress() {
- mLogger.count("key_back_press", 1);
+ private boolean interceptBackKeyUp(KeyEvent event) {
+ mLogger.count("key_back_up", 1);
// Cache handled state
boolean handled = mBackKeyHandled;
+ // Reset back long press state
+ cancelPendingBackKeyAction();
+
if (mHasFeatureWatch) {
TelecomManager telecomManager = getTelecommService();
@@ -841,9 +881,10 @@
}
}
- if (mAutofillManagerInternal != null) {
+ if (mAutofillManagerInternal != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_BACK_KEY_TO_AUTOFILL));
}
+
return handled;
}
@@ -853,6 +894,11 @@
mPowerKeyWakeLock.acquire();
}
+ // Cancel multi-press detection timeout.
+ if (mPowerKeyPressCounter != 0) {
+ mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
+ }
+
mWindowManagerFuncs.onPowerKeyDown(interactive);
// Stop ringing or end call if configured to do so when power is pressed.
@@ -874,20 +920,71 @@
final boolean handledByPowerManager = mPowerManagerInternal.interceptPowerKeyDown(event);
+ GestureLauncherService gestureService = LocalServices.getService(
+ GestureLauncherService.class);
+ boolean gesturedServiceIntercepted = false;
+ if (gestureService != null) {
+ gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
+ mTmpBoolean);
+ if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
+ mCameraGestureTriggeredDuringGoingToSleep = true;
+ }
+ }
+
// Inform the StatusBar; but do not allow it to consume the event.
sendSystemKeyToStatusBarAsync(event.getKeyCode());
+ schedulePossibleVeryLongPressReboot();
+
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
- mPowerKeyHandled = mPowerKeyHandled || hungUp
+ mPowerKeyHandled = hungUp || gesturedServiceIntercepted
|| handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
if (!mPowerKeyHandled) {
- if (!interactive) {
+ if (interactive) {
+ // When interactive, we're already awake.
+ // Wait for a long press or for the button to be released to decide what to do.
+ if (hasLongPressOnPowerBehavior()) {
+ if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+ powerLongPress(event.getEventTime());
+ } else {
+ Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS,
+ event.getEventTime());
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+
+ if (hasVeryLongPressOnPowerBehavior()) {
+ Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
+ longMsg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ }
+ }
+ }
+ } else {
wakeUpFromPowerKey(event.getDownTime());
+
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
+ if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+ powerLongPress(event.getEventTime());
+ } else {
+ Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS,
+ event.getEventTime());
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+
+ if (hasVeryLongPressOnPowerBehavior()) {
+ Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
+ longMsg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ }
+ }
+
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();
+
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
@@ -895,38 +992,68 @@
}
}
}
- } else {
- // handled by another power key policy.
- if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
- mSingleKeyGestureDetector.reset();
- }
}
}
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
final boolean handled = canceled || mPowerKeyHandled;
+ cancelPendingPowerKeyAction();
if (!handled) {
if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == 0) {
// Abort possibly stuck animations only when power key up without long press case.
mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
}
- } else {
- // handled by single key or another power key policy.
- mSingleKeyGestureDetector.reset();
- finishPowerKeyPress();
+
+ // Figure out how to handle the key now that it has been released.
+ mPowerKeyPressCounter += 1;
+
+ final int maxCount = getMaxMultiPressPowerCount();
+ final long eventTime = event.getDownTime();
+ if (mPowerKeyPressCounter < maxCount) {
+ // This could be a multi-press. Wait a little bit longer to confirm.
+ // Continue holding the wake lock.
+ Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
+ interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
+ return;
+ }
+
+ // No other actions. Handle it immediately.
+ powerPress(eventTime, interactive, mPowerKeyPressCounter);
}
+ // Done. Reset our state.
+ finishPowerKeyPress();
}
private void finishPowerKeyPress() {
mBeganFromNonInteractive = false;
- mPowerKeyHandled = false;
+ mPowerKeyPressCounter = 0;
if (mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.release();
}
}
+ private void cancelPendingPowerKeyAction() {
+ if (!mPowerKeyHandled) {
+ mPowerKeyHandled = true;
+ mHandler.removeMessages(MSG_POWER_LONG_PRESS);
+ }
+ if (hasVeryLongPressOnPowerBehavior()) {
+ mHandler.removeMessages(MSG_POWER_VERY_LONG_PRESS);
+ }
+ cancelPossibleVeryLongPressReboot();
+ }
+
+ private void cancelPendingBackKeyAction() {
+ if (!mBackKeyHandled) {
+ mBackKeyHandled = true;
+ mHandler.removeMessages(MSG_BACK_LONG_PRESS);
+ }
+ }
+
private void powerPress(long eventTime, boolean interactive, int count) {
if (mDefaultDisplayPolicy.isScreenOnEarly() && !mDefaultDisplayPolicy.isScreenOnFully()) {
Slog.i(TAG, "Suppressed redundant power key press while "
@@ -1077,7 +1204,6 @@
private void powerLongPress(long eventTime) {
final int behavior = getResolvedLongPressOnPowerBehavior();
-
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
@@ -1716,6 +1842,8 @@
com.android.internal.R.integer.config_triplePressOnPowerBehavior);
mShortPressOnSleepBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shortPressOnSleepBehavior);
+ mVeryLongPressTimeout = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_veryLongPressTimeout);
mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
@@ -1809,7 +1937,6 @@
}
});
initKeyCombinationRules();
- initSingleKeyGestureRules();
}
private void initKeyCombinationRules() {
@@ -1822,7 +1949,7 @@
new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) {
@Override
void execute() {
- mPowerKeyHandled = true;
+ cancelPendingPowerKeyAction();
interceptScreenshotChord();
}
@Override
@@ -1857,7 +1984,7 @@
}
@Override
void execute() {
- mPowerKeyHandled = true;
+ cancelPendingPowerKeyAction();
interceptRingerToggleChord();
}
@Override
@@ -1871,7 +1998,7 @@
new TwoKeysCombinationRule(KEYCODE_BACK, KEYCODE_DPAD_DOWN) {
@Override
void execute() {
- mBackKeyHandled = true;
+ cancelPendingBackKeyAction();
interceptAccessibilityGestureTv();
}
@@ -1885,7 +2012,7 @@
new TwoKeysCombinationRule(KEYCODE_DPAD_CENTER, KEYCODE_BACK) {
@Override
void execute() {
- mBackKeyHandled = true;
+ cancelPendingBackKeyAction();
interceptBugreportGestureTv();
}
@@ -1898,84 +2025,6 @@
}
/**
- * Rule for single power key gesture.
- */
- private final class PowerKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
- PowerKeyRule(int gestures) {
- super(KEYCODE_POWER, gestures);
- }
-
- @Override
- int getMaxMultiPressCount() {
- return getMaxMultiPressPowerCount();
- }
-
- @Override
- void onPress(long downTime) {
- powerPress(downTime, true, 1 /*count*/);
- finishPowerKeyPress();
- }
-
- @Override
- void onLongPress(long downTime) {
- powerLongPress(downTime);
- }
-
- @Override
- void onVeryLongPress(long downTime) {
- mActivityManagerInternal.prepareForPossibleShutdown();
- powerVeryLongPress();
- }
-
- @Override
- void onMultiPress(long downTime, int count) {
- powerPress(downTime, true, count);
- finishPowerKeyPress();
- }
- }
-
- /**
- * Rule for single back key gesture.
- */
- private final class BackKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
- BackKeyRule(int gestures) {
- super(KEYCODE_BACK, gestures);
- }
-
- @Override
- int getMaxMultiPressCount() {
- return 1;
- }
-
- @Override
- void onPress(long downTime) {
- mBackKeyHandled |= backKeyPress();
- }
-
- @Override
- void onLongPress(long downTime) {
- backLongPress();
- }
- }
-
- private void initSingleKeyGestureRules() {
- mSingleKeyGestureDetector = new SingleKeyGestureDetector(mContext);
-
- int powerKeyGestures = 0;
- if (hasVeryLongPressOnPowerBehavior()) {
- powerKeyGestures |= KEY_VERYLONGPRESS;
- }
- if (hasLongPressOnPowerBehavior()) {
- powerKeyGestures |= KEY_LONGPRESS;
- }
- mSingleKeyGestureDetector.addRule(new PowerKeyRule(powerKeyGestures));
-
- if (hasLongPressOnBackBehavior()) {
- mSingleKeyGestureDetector.addRule(new BackKeyRule(KEY_LONGPRESS));
- }
- }
-
- /**
* Read values from config.xml that may be overridden depending on
* the configuration of the device.
* eg. Disable long press on home goes to recents on sw600dp.
@@ -3519,21 +3568,8 @@
return result;
}
- // Alternate TV power to power key for Android TV device.
- final HdmiControlManager hdmiControlManager = getHdmiControlManager();
- if (keyCode == KeyEvent.KEYCODE_TV_POWER && mHasFeatureLeanback
- && (hdmiControlManager == null || !hdmiControlManager.shouldHandleTvPowerKey())) {
- event = KeyEvent.obtain(
- event.getDownTime(), event.getEventTime(),
- event.getAction(), KeyEvent.KEYCODE_POWER,
- event.getRepeatCount(), event.getMetaState(),
- event.getDeviceId(), event.getScanCode(),
- event.getFlags(), event.getSource(), event.getDisplayId(), null);
- return interceptKeyBeforeQueueing(event, policyFlags);
- }
-
if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
- handleKeyGesture(event, interactive);
+ mKeyCombinationManager.interceptKey(event, interactive);
}
// Enable haptics if down and virtual key without multiple repetitions. If this is a hard
@@ -3548,13 +3584,12 @@
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: {
if (down) {
- mBackKeyHandled = false;
+ interceptBackKeyDown();
} else {
- if (!hasLongPressOnBackBehavior()) {
- mBackKeyHandled |= backKeyPress();
- }
+ boolean handled = interceptBackKeyUp(event);
+
// Don't pass back press to app if we've already handled it via long press
- if (mBackKeyHandled) {
+ if (handled) {
result &= ~ACTION_PASS_TO_USER;
}
}
@@ -3666,17 +3701,33 @@
case KeyEvent.KEYCODE_TV_POWER: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
- if (down && hdmiControlManager != null) {
- hdmiControlManager.toggleAndFollowTvPower();
+ HdmiControlManager hdmiControlManager = getHdmiControlManager();
+ if (hdmiControlManager != null && hdmiControlManager.shouldHandleTvPowerKey()) {
+ if (down) {
+ hdmiControlManager.toggleAndFollowTvPower();
+ }
+ } else if (mHasFeatureLeanback) {
+ KeyEvent fallbackEvent = KeyEvent.obtain(
+ event.getDownTime(), event.getEventTime(),
+ event.getAction(), KeyEvent.KEYCODE_POWER,
+ event.getRepeatCount(), event.getMetaState(),
+ event.getDeviceId(), event.getScanCode(),
+ event.getFlags(), event.getSource(), event.getDisplayId(), null);
+ if (down) {
+ interceptPowerKeyDown(fallbackEvent, interactive);
+ } else {
+ interceptPowerKeyUp(fallbackEvent, interactive, canceled);
+ }
}
+ // Ignore this key for any device that is not connected to a TV via HDMI and
+ // not an Android TV device.
break;
}
case KeyEvent.KEYCODE_POWER: {
EventLogTags.writeInterceptPower(
KeyEvent.actionToString(event.getAction()),
- mPowerKeyHandled ? 1 : 0,
- mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
+ mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);
// Any activity on the power button stops the accessibility shortcut
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
@@ -3857,43 +3908,6 @@
return result;
}
- private void handleKeyGesture(KeyEvent event, boolean interactive) {
- if (mKeyCombinationManager.interceptKey(event, interactive)) {
- // handled by combo keys manager.
- mSingleKeyGestureDetector.reset();
- return;
- }
-
- if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) {
- mPowerKeyHandled = handleCameraGesture(event, interactive);
- if (mPowerKeyHandled) {
- // handled by camera gesture.
- mSingleKeyGestureDetector.reset();
- return;
- }
- }
-
- mSingleKeyGestureDetector.interceptKey(event);
- }
-
- // The camera gesture will be detected by GestureLauncherService.
- private boolean handleCameraGesture(KeyEvent event, boolean interactive) {
- // camera gesture.
- GestureLauncherService gestureService = LocalServices.getService(
- GestureLauncherService.class);
- if (gestureService == null) {
- return false;
- }
-
- final MutableBoolean outLaunched = new MutableBoolean(false);
- final boolean gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event,
- interactive, outLaunched);
- if (outLaunched.value && mRequestedOrGoingToSleep) {
- mCameraGestureTriggeredDuringGoingToSleep = true;
- }
- return gesturedServiceIntercepted;
- }
-
/**
* Handle statusbar expansion events.
* @param event
@@ -4893,6 +4907,15 @@
}
}
+ private void schedulePossibleVeryLongPressReboot() {
+ mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+ mHandler.postDelayed(mPossibleVeryLongPressReboot, mVeryLongPressTimeout);
+ }
+
+ private void cancelPossibleVeryLongPressReboot() {
+ mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+ }
+
// TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
private void updateScreenOffSleepToken(boolean acquire) {
if (acquire) {
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
deleted file mode 100644
index 3dafb0ce..0000000
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (C) 2021 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.server.policy;
-
-import android.annotation.IntDef;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-
-/**
- * Detect single key gesture: press, long press, very long press and multi press.
- *
- * Call {@link #reset} if current {@link KeyEvent} has been handled by another policy
- */
-
-public final class SingleKeyGestureDetector {
- private static final String TAG = "SingleKeyGesture";
- private static final boolean DEBUG = false;
-
- private static final int MSG_KEY_LONG_PRESS = 0;
- private static final int MSG_KEY_VERY_LONG_PRESS = 1;
- private static final int MSG_KEY_DELAYED_PRESS = 2;
-
- private final long mLongPressTimeout;
- private final long mVeryLongPressTimeout;
-
- private volatile int mKeyPressCounter;
-
- private final ArrayList<SingleKeyRule> mRules = new ArrayList();
- private SingleKeyRule mActiveRule = null;
-
- // Key code of current key down event, reset when key up.
- private int mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- private volatile boolean mHandledByLongPress = false;
- private final Handler mHandler;
- private static final long MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout();
-
-
- /** Supported gesture flags */
- public static final int KEY_LONGPRESS = 1 << 1;
- public static final int KEY_VERYLONGPRESS = 1 << 2;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "KEY_" }, value = {
- KEY_LONGPRESS,
- KEY_VERYLONGPRESS,
- })
- public @interface KeyGestureFlag {}
-
- /**
- * Rule definition for single keys gesture.
- * E.g : define power key.
- * <pre class="prettyprint">
- * SingleKeyRule rule =
- * new SingleKeyRule(KEYCODE_POWER, KEY_LONGPRESS|KEY_VERYLONGPRESS) {
- * int getMaxMultiPressCount() { // maximum multi press count. }
- * void onPress(long downTime) { // short press behavior. }
- * void onLongPress() { // long press behavior. }
- * void onVeryLongPress() { // very long press behavior. }
- * void onMultiPress(long downTime, int count) { // multi press behavior. }
- * };
- * </pre>
- */
- abstract static class SingleKeyRule {
- private final int mKeyCode;
- private final int mSupportedGestures;
-
- SingleKeyRule(int keyCode, @KeyGestureFlag int supportedGestures) {
- mKeyCode = keyCode;
- mSupportedGestures = supportedGestures;
- }
-
- /**
- * True if the rule could intercept the key.
- */
- private boolean shouldInterceptKey(int keyCode) {
- return keyCode == mKeyCode;
- }
-
- /**
- * True if the rule support long press.
- */
- private boolean supportLongPress() {
- return (mSupportedGestures & KEY_LONGPRESS) != 0;
- }
-
- /**
- * True if the rule support very long press.
- */
- private boolean supportVeryLongPress() {
- return (mSupportedGestures & KEY_VERYLONGPRESS) != 0;
- }
-
- /**
- * Maximum count of multi presses.
- * Return 1 will trigger onPress immediately when {@link KeyEvent.ACTION_UP}.
- * Otherwise trigger onMultiPress immediately when reach max count when
- * {@link KeyEvent.ACTION_DOWN}.
- */
- int getMaxMultiPressCount() {
- return 1;
- }
-
- /**
- * Called when short press has been detected.
- */
- abstract void onPress(long downTime);
- /**
- * Callback when multi press (>= 2) has been detected.
- */
- void onMultiPress(long downTime, int count) {}
- /**
- * Callback when long press has been detected.
- */
- void onLongPress(long downTime) {}
- /**
- * Callback when very long press has been detected.
- */
- void onVeryLongPress(long downTime) {}
-
- @Override
- public String toString() {
- return "KeyCode = " + KeyEvent.keyCodeToString(mKeyCode)
- + ", long press : " + supportLongPress()
- + ", very Long press : " + supportVeryLongPress()
- + ", max multi press count : " + getMaxMultiPressCount();
- }
- }
-
- public SingleKeyGestureDetector(Context context) {
- mLongPressTimeout = ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout();
- mVeryLongPressTimeout = context.getResources().getInteger(
- com.android.internal.R.integer.config_veryLongPressTimeout);
- mHandler = new KeyHandler();
- }
-
- void addRule(SingleKeyRule rule) {
- mRules.add(rule);
- }
-
- void interceptKey(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- interceptKeyDown(event);
- } else {
- interceptKeyUp(event);
- }
- }
-
- private void interceptKeyDown(KeyEvent event) {
- final int keyCode = event.getKeyCode();
- // same key down.
- if (mDownKeyCode == keyCode) {
- if (mActiveRule != null && (event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0
- && !mHandledByLongPress) {
- if (DEBUG) {
- Log.i(TAG, "Long press Key " + KeyEvent.keyCodeToString(keyCode));
- }
- mHandledByLongPress = true;
- mHandler.removeMessages(MSG_KEY_LONG_PRESS);
- mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
- mActiveRule.onLongPress(event.getEventTime());
- }
- return;
- }
-
- // When a different key is pressed, stop processing gestures for the currently active key.
- if (mDownKeyCode != KeyEvent.KEYCODE_UNKNOWN
- || (mActiveRule != null && !mActiveRule.shouldInterceptKey(keyCode))) {
- if (DEBUG) {
- Log.i(TAG, "Press another key " + KeyEvent.keyCodeToString(keyCode));
- }
-
- reset();
- }
- mDownKeyCode = keyCode;
-
- // Picks a new rule, return if no rule picked.
- if (mActiveRule == null) {
- final int count = mRules.size();
- for (int index = 0; index < count; index++) {
- final SingleKeyRule rule = mRules.get(index);
- if (rule.shouldInterceptKey(keyCode)) {
- mActiveRule = rule;
- break;
- }
- }
- }
- if (mActiveRule == null) {
- return;
- }
-
- final long eventTime = event.getEventTime();
- if (mKeyPressCounter == 0) {
- if (mActiveRule.supportLongPress()) {
- final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, keyCode, 0,
- eventTime);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg, mLongPressTimeout);
- }
-
- if (mActiveRule.supportVeryLongPress()) {
- final Message msg = mHandler.obtainMessage(MSG_KEY_VERY_LONG_PRESS, keyCode, 0,
- eventTime);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg, mVeryLongPressTimeout);
- }
- } else {
- mHandler.removeMessages(MSG_KEY_LONG_PRESS);
- mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
- mHandler.removeMessages(MSG_KEY_DELAYED_PRESS);
-
- // Trigger multi press immediately when reach max count.( > 1)
- if (mKeyPressCounter == mActiveRule.getMaxMultiPressCount() - 1) {
- if (DEBUG) {
- Log.i(TAG, "Trigger multi press " + mActiveRule.toString() + " for it"
- + " reach the max count " + mKeyPressCounter);
- }
- mActiveRule.onMultiPress(eventTime, mKeyPressCounter + 1);
- mKeyPressCounter = 0;
- }
- }
- }
-
- private boolean interceptKeyUp(KeyEvent event) {
- mHandler.removeMessages(MSG_KEY_LONG_PRESS);
- mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
- mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- if (mActiveRule == null) {
- return false;
- }
-
- if (mHandledByLongPress) {
- mHandledByLongPress = false;
- return true;
- }
-
- final long downTime = event.getDownTime();
- if (event.getKeyCode() == mActiveRule.mKeyCode) {
- // Directly trigger short press when max count is 1.
- if (mActiveRule.getMaxMultiPressCount() == 1) {
- mActiveRule.onPress(downTime);
- return true;
- }
-
- // This could be a multi-press. Wait a little bit longer to confirm.
- mKeyPressCounter++;
- Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, mActiveRule.mKeyCode,
- mKeyPressCounter, downTime);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg, MULTI_PRESS_TIMEOUT);
- return true;
- }
- reset();
- return false;
- }
-
- int getKeyPressCounter(int keyCode) {
- if (mActiveRule != null && mActiveRule.mKeyCode == keyCode) {
- return mKeyPressCounter;
- } else {
- return 0;
- }
- }
-
- void reset() {
- if (mActiveRule != null) {
- if (mDownKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
- mHandler.removeMessages(MSG_KEY_LONG_PRESS);
- mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
- }
-
- if (mKeyPressCounter > 0) {
- mHandler.removeMessages(MSG_KEY_DELAYED_PRESS);
- mKeyPressCounter = 0;
- }
- mActiveRule = null;
- }
-
- mHandledByLongPress = false;
- mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- }
-
- boolean isKeyIntercepted(int keyCode) {
- if (mActiveRule != null && mActiveRule.shouldInterceptKey(keyCode)) {
- return mHandledByLongPress;
- }
- return false;
- }
-
- private class KeyHandler extends Handler {
- KeyHandler() {
- super(Looper.getMainLooper());
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (mActiveRule == null) {
- return;
- }
- final int keyCode = msg.arg1;
- final long eventTime = (long) msg.obj;
- switch(msg.what) {
- case MSG_KEY_LONG_PRESS:
- if (DEBUG) {
- Log.i(TAG, "Detect long press " + KeyEvent.keyCodeToString(keyCode));
- }
- mHandledByLongPress = true;
- mActiveRule.onLongPress(eventTime);
- break;
- case MSG_KEY_VERY_LONG_PRESS:
- if (DEBUG) {
- Log.i(TAG, "Detect very long press "
- + KeyEvent.keyCodeToString(keyCode));
- }
- mHandledByLongPress = true;
- mActiveRule.onVeryLongPress(eventTime);
- break;
- case MSG_KEY_DELAYED_PRESS:
- if (DEBUG) {
- Log.i(TAG, "Detect press " + KeyEvent.keyCodeToString(keyCode)
- + ", count " + mKeyPressCounter);
- }
- if (mKeyPressCounter == 1) {
- mActiveRule.onPress(eventTime);
- } else {
- mActiveRule.onMultiPress(eventTime, mKeyPressCounter);
- }
- mKeyPressCounter = 0;
- break;
- }
- }
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
deleted file mode 100644
index 3025a95..0000000
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2021 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.server.policy;
-
-import static android.view.KeyEvent.ACTION_DOWN;
-import static android.view.KeyEvent.ACTION_UP;
-import static android.view.KeyEvent.KEYCODE_POWER;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.server.policy.SingleKeyGestureDetector.KEY_LONGPRESS;
-import static com.android.server.policy.SingleKeyGestureDetector.KEY_VERYLONGPRESS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.os.SystemClock;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Test class for {@link SingleKeyGestureDetector}.
- *
- * Build/Install/Run:
- * atest WmTests:SingleKeyGestureTests
- */
-public class SingleKeyGestureTests {
- private SingleKeyGestureDetector mDetector;
-
- private int mMaxMultiPressPowerCount = 2;
-
- private CountDownLatch mShortPressed = new CountDownLatch(1);
- private CountDownLatch mLongPressed = new CountDownLatch(1);
- private CountDownLatch mVeryLongPressed = new CountDownLatch(1);
- private CountDownLatch mMultiPressed = new CountDownLatch(1);
-
- private final Instrumentation mInstrumentation = getInstrumentation();
- private final Context mContext = mInstrumentation.getTargetContext();
- private long mWaitTimeout;
- private long mLongPressTime;
- private long mVeryLongPressTime;
-
- @Before
- public void setUp() {
- mDetector = new SingleKeyGestureDetector(mContext);
- initSingleKeyGestureRules();
- mWaitTimeout = ViewConfiguration.getMultiPressTimeout() + 50;
- mLongPressTime = ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout() + 50;
- mVeryLongPressTime = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_veryLongPressTimeout) + 50;
- }
-
- private void initSingleKeyGestureRules() {
- mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(KEYCODE_POWER,
- KEY_LONGPRESS | KEY_VERYLONGPRESS) {
- @Override
- int getMaxMultiPressCount() {
- return mMaxMultiPressPowerCount;
- }
- @Override
- public void onPress(long downTime) {
- mShortPressed.countDown();
- }
-
- @Override
- void onLongPress(long downTime) {
- mLongPressed.countDown();
- }
-
- @Override
- void onVeryLongPress(long downTime) {
- mVeryLongPressed.countDown();
- }
-
- @Override
- void onMultiPress(long downTime, int count) {
- mMultiPressed.countDown();
- assertEquals(mMaxMultiPressPowerCount, count);
- }
- });
- }
-
- private void pressKey(long eventTime, int keyCode, long pressTime) {
- final KeyEvent keyDown = new KeyEvent(eventTime, eventTime, ACTION_DOWN,
- keyCode, 0 /* repeat */, 0 /* metaState */);
- mDetector.interceptKey(keyDown);
-
- // keep press down.
- try {
- Thread.sleep(pressTime);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- eventTime += pressTime;
- final KeyEvent keyUp = new KeyEvent(eventTime, eventTime, ACTION_UP,
- keyCode, 0 /* repeat */, 0 /* metaState */);
-
- mDetector.interceptKey(keyUp);
- }
-
- @Test
- public void testShortPress() throws InterruptedException {
- final long eventTime = SystemClock.uptimeMillis();
- pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
- assertTrue(mShortPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
- }
-
- @Test
- public void testLongPress() throws InterruptedException {
- final long eventTime = SystemClock.uptimeMillis();
- pressKey(eventTime, KEYCODE_POWER, mLongPressTime);
- assertTrue(mLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
- }
-
- @Test
- public void testVeryLongPress() throws InterruptedException {
- final long eventTime = SystemClock.uptimeMillis();
- pressKey(eventTime, KEYCODE_POWER, mVeryLongPressTime);
- assertTrue(mVeryLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
- }
-
- @Test
- public void testMultiPress() throws InterruptedException {
- final long eventTime = SystemClock.uptimeMillis();
- pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
- pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
- assertTrue(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
- }
-}