Loading services/core/java/com/android/server/policy/KeyCombinationManager.java +10 −6 Original line number Diff line number Diff line Loading @@ -102,9 +102,11 @@ public class KeyCombinationManager { } /** * Check if the key event could be triggered by combine key rule before dispatching to a window. * 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. */ void interceptKey(KeyEvent event, boolean interactive) { boolean interceptKey(KeyEvent event, boolean interactive) { final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final int keyCode = event.getKeyCode(); final int count = mActiveRules.size(); Loading @@ -117,9 +119,9 @@ public class KeyCombinationManager { // exceed time from first key down. forAllRules(mActiveRules, (rule)-> rule.cancel()); mActiveRules.clear(); return; return false; } else if (count == 0) { // has some key down but no active rule exist. return; return false; } } Loading @@ -127,7 +129,7 @@ public class KeyCombinationManager { mDownTimes.put(keyCode, eventTime); } else { // ignore old key, maybe a repeat key. return; return false; } if (mDownTimes.size() == 1) { Loading @@ -141,7 +143,7 @@ public class KeyCombinationManager { } else { // Ignore if rule already triggered. if (mTriggeredRule != null) { return; return true; } // check if second key can trigger rule, or remove the non-match rule. Loading @@ -156,6 +158,7 @@ public class KeyCombinationManager { mActiveRules.clear(); if (mTriggeredRule != null) { mActiveRules.add(mTriggeredRule); return true; } } } else { Loading @@ -168,6 +171,7 @@ public class KeyCombinationManager { } } } return false; } /** Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +163 −186 Original line number Diff line number Diff line Loading @@ -73,6 +73,8 @@ import static android.view.WindowManagerGlobal.ADD_OKAY; 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; Loading Loading @@ -456,7 +458,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { volatile boolean mPowerKeyHandled; volatile boolean mBackKeyHandled; volatile boolean mBeganFromNonInteractive; volatile int mPowerKeyPressCounter; volatile boolean mEndCallKeyHandled; volatile boolean mCameraGestureTriggeredDuringGoingToSleep; volatile boolean mGoingToSleep; Loading Loading @@ -497,7 +498,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mHasSoftInput = false; boolean mHapticTextHandleEnabled; boolean mUseTvRouting; int mVeryLongPressTimeout; boolean mAllowStartActivityForLongPressOnPowerDuringSetup; MetricsLogger mLogger; boolean mWakeOnDpadKeyPress; Loading Loading @@ -597,14 +597,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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; Loading @@ -615,10 +614,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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; Loading @@ -626,8 +622,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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_POWER_VERY_LONG_PRESS = 25; private static final int MSG_RINGER_TOGGLE_CHORD = 26; private static final int MSG_RINGER_TOGGLE_CHORD = 24; private class PolicyHandler extends Handler { @Override Loading Loading @@ -668,22 +663,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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; Loading Loading @@ -794,13 +776,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; private Runnable mPossibleVeryLongPressReboot = new Runnable() { @Override public void run() { mActivityManagerInternal.prepareForPossibleShutdown(); } }; private void handleRingerChordGesture() { if (mRingerToggleChord == VOLUME_HUSH_OFF) { return; Loading Loading @@ -840,28 +815,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } 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 interceptBackKeyUp(KeyEvent event) { mLogger.count("key_back_up", 1); private boolean backKeyPress() { mLogger.count("key_back_press", 1); // Cache handled state boolean handled = mBackKeyHandled; // Reset back long press state cancelPendingBackKeyAction(); if (mHasFeatureWatch) { TelecomManager telecomManager = getTelecommService(); Loading @@ -883,10 +843,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } if (mAutofillManagerInternal != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if (mAutofillManagerInternal != null) { mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_BACK_KEY_TO_AUTOFILL)); } return handled; } Loading @@ -896,11 +855,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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. Loading @@ -922,71 +876,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 = hungUp || gesturedServiceIntercepted mPowerKeyHandled = mPowerKeyHandled || hungUp || handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted(); if (!mPowerKeyHandled) { 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 { if (!interactive) { 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 { Loading @@ -994,68 +897,38 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } } 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); } // 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); } else { // handled by single key or another power key policy. mSingleKeyGestureDetector.reset(); finishPowerKeyPress(); } // Done. Reset our state. finishPowerKeyPress(); } private void finishPowerKeyPress() { mBeganFromNonInteractive = false; mPowerKeyPressCounter = 0; mPowerKeyHandled = false; 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 " Loading Loading @@ -1206,6 +1079,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void powerLongPress(long eventTime) { final int behavior = getResolvedLongPressOnPowerBehavior(); switch (behavior) { case LONG_PRESS_POWER_NOTHING: break; Loading Loading @@ -1844,8 +1718,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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); Loading Loading @@ -1939,6 +1811,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }); initKeyCombinationRules(); initSingleKeyGestureRules(); } private void initKeyCombinationRules() { Loading @@ -1951,7 +1824,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) { @Override void execute() { cancelPendingPowerKeyAction(); mPowerKeyHandled = true; interceptScreenshotChord(); } @Override Loading Loading @@ -1986,7 +1859,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override void execute() { cancelPendingPowerKeyAction(); mPowerKeyHandled = true; interceptRingerToggleChord(); } @Override Loading @@ -2000,7 +1873,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new TwoKeysCombinationRule(KEYCODE_BACK, KEYCODE_DPAD_DOWN) { @Override void execute() { cancelPendingBackKeyAction(); mBackKeyHandled = true; interceptAccessibilityGestureTv(); } Loading @@ -2014,7 +1887,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new TwoKeysCombinationRule(KEYCODE_DPAD_CENTER, KEYCODE_BACK) { @Override void execute() { cancelPendingBackKeyAction(); mBackKeyHandled = true; interceptBugreportGestureTv(); } Loading @@ -2026,6 +1899,84 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } /** * 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. Loading Loading @@ -3550,8 +3501,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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) { mKeyCombinationManager.interceptKey(event, interactive); handleKeyGesture(event, interactive); } // Enable haptics if down and virtual key without multiple repetitions. If this is a hard Loading @@ -3566,12 +3530,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { switch (keyCode) { case KeyEvent.KEYCODE_BACK: { if (down) { interceptBackKeyDown(); mBackKeyHandled = false; } else { boolean handled = interceptBackKeyUp(event); if (!hasLongPressOnBackBehavior()) { mBackKeyHandled |= backKeyPress(); } // Don't pass back press to app if we've already handled it via long press if (handled) { if (mBackKeyHandled) { result &= ~ACTION_PASS_TO_USER; } } Loading Loading @@ -3683,33 +3648,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_TV_POWER: { result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately HdmiControlManager hdmiControlManager = getHdmiControlManager(); if (hdmiControlManager != null && hdmiControlManager.shouldHandleTvPowerKey()) { if (down) { if (down && hdmiControlManager != null) { 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, mPowerKeyPressCounter); mPowerKeyHandled ? 1 : 0, mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER)); // Any activity on the power button stops the accessibility shortcut result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately Loading Loading @@ -3890,6 +3839,43 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 Loading Loading @@ -4889,15 +4875,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } 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) { Loading Loading
services/core/java/com/android/server/policy/KeyCombinationManager.java +10 −6 Original line number Diff line number Diff line Loading @@ -102,9 +102,11 @@ public class KeyCombinationManager { } /** * Check if the key event could be triggered by combine key rule before dispatching to a window. * 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. */ void interceptKey(KeyEvent event, boolean interactive) { boolean interceptKey(KeyEvent event, boolean interactive) { final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final int keyCode = event.getKeyCode(); final int count = mActiveRules.size(); Loading @@ -117,9 +119,9 @@ public class KeyCombinationManager { // exceed time from first key down. forAllRules(mActiveRules, (rule)-> rule.cancel()); mActiveRules.clear(); return; return false; } else if (count == 0) { // has some key down but no active rule exist. return; return false; } } Loading @@ -127,7 +129,7 @@ public class KeyCombinationManager { mDownTimes.put(keyCode, eventTime); } else { // ignore old key, maybe a repeat key. return; return false; } if (mDownTimes.size() == 1) { Loading @@ -141,7 +143,7 @@ public class KeyCombinationManager { } else { // Ignore if rule already triggered. if (mTriggeredRule != null) { return; return true; } // check if second key can trigger rule, or remove the non-match rule. Loading @@ -156,6 +158,7 @@ public class KeyCombinationManager { mActiveRules.clear(); if (mTriggeredRule != null) { mActiveRules.add(mTriggeredRule); return true; } } } else { Loading @@ -168,6 +171,7 @@ public class KeyCombinationManager { } } } return false; } /** Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +163 −186 Original line number Diff line number Diff line Loading @@ -73,6 +73,8 @@ import static android.view.WindowManagerGlobal.ADD_OKAY; 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; Loading Loading @@ -456,7 +458,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { volatile boolean mPowerKeyHandled; volatile boolean mBackKeyHandled; volatile boolean mBeganFromNonInteractive; volatile int mPowerKeyPressCounter; volatile boolean mEndCallKeyHandled; volatile boolean mCameraGestureTriggeredDuringGoingToSleep; volatile boolean mGoingToSleep; Loading Loading @@ -497,7 +498,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mHasSoftInput = false; boolean mHapticTextHandleEnabled; boolean mUseTvRouting; int mVeryLongPressTimeout; boolean mAllowStartActivityForLongPressOnPowerDuringSetup; MetricsLogger mLogger; boolean mWakeOnDpadKeyPress; Loading Loading @@ -597,14 +597,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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; Loading @@ -615,10 +614,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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; Loading @@ -626,8 +622,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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_POWER_VERY_LONG_PRESS = 25; private static final int MSG_RINGER_TOGGLE_CHORD = 26; private static final int MSG_RINGER_TOGGLE_CHORD = 24; private class PolicyHandler extends Handler { @Override Loading Loading @@ -668,22 +663,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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; Loading Loading @@ -794,13 +776,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; private Runnable mPossibleVeryLongPressReboot = new Runnable() { @Override public void run() { mActivityManagerInternal.prepareForPossibleShutdown(); } }; private void handleRingerChordGesture() { if (mRingerToggleChord == VOLUME_HUSH_OFF) { return; Loading Loading @@ -840,28 +815,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } 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 interceptBackKeyUp(KeyEvent event) { mLogger.count("key_back_up", 1); private boolean backKeyPress() { mLogger.count("key_back_press", 1); // Cache handled state boolean handled = mBackKeyHandled; // Reset back long press state cancelPendingBackKeyAction(); if (mHasFeatureWatch) { TelecomManager telecomManager = getTelecommService(); Loading @@ -883,10 +843,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } if (mAutofillManagerInternal != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if (mAutofillManagerInternal != null) { mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_BACK_KEY_TO_AUTOFILL)); } return handled; } Loading @@ -896,11 +855,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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. Loading @@ -922,71 +876,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 = hungUp || gesturedServiceIntercepted mPowerKeyHandled = mPowerKeyHandled || hungUp || handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted(); if (!mPowerKeyHandled) { 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 { if (!interactive) { 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 { Loading @@ -994,68 +897,38 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } } 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); } // 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); } else { // handled by single key or another power key policy. mSingleKeyGestureDetector.reset(); finishPowerKeyPress(); } // Done. Reset our state. finishPowerKeyPress(); } private void finishPowerKeyPress() { mBeganFromNonInteractive = false; mPowerKeyPressCounter = 0; mPowerKeyHandled = false; 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 " Loading Loading @@ -1206,6 +1079,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void powerLongPress(long eventTime) { final int behavior = getResolvedLongPressOnPowerBehavior(); switch (behavior) { case LONG_PRESS_POWER_NOTHING: break; Loading Loading @@ -1844,8 +1718,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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); Loading Loading @@ -1939,6 +1811,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }); initKeyCombinationRules(); initSingleKeyGestureRules(); } private void initKeyCombinationRules() { Loading @@ -1951,7 +1824,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) { @Override void execute() { cancelPendingPowerKeyAction(); mPowerKeyHandled = true; interceptScreenshotChord(); } @Override Loading Loading @@ -1986,7 +1859,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override void execute() { cancelPendingPowerKeyAction(); mPowerKeyHandled = true; interceptRingerToggleChord(); } @Override Loading @@ -2000,7 +1873,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new TwoKeysCombinationRule(KEYCODE_BACK, KEYCODE_DPAD_DOWN) { @Override void execute() { cancelPendingBackKeyAction(); mBackKeyHandled = true; interceptAccessibilityGestureTv(); } Loading @@ -2014,7 +1887,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new TwoKeysCombinationRule(KEYCODE_DPAD_CENTER, KEYCODE_BACK) { @Override void execute() { cancelPendingBackKeyAction(); mBackKeyHandled = true; interceptBugreportGestureTv(); } Loading @@ -2026,6 +1899,84 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } /** * 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. Loading Loading @@ -3550,8 +3501,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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) { mKeyCombinationManager.interceptKey(event, interactive); handleKeyGesture(event, interactive); } // Enable haptics if down and virtual key without multiple repetitions. If this is a hard Loading @@ -3566,12 +3530,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { switch (keyCode) { case KeyEvent.KEYCODE_BACK: { if (down) { interceptBackKeyDown(); mBackKeyHandled = false; } else { boolean handled = interceptBackKeyUp(event); if (!hasLongPressOnBackBehavior()) { mBackKeyHandled |= backKeyPress(); } // Don't pass back press to app if we've already handled it via long press if (handled) { if (mBackKeyHandled) { result &= ~ACTION_PASS_TO_USER; } } Loading Loading @@ -3683,33 +3648,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_TV_POWER: { result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately HdmiControlManager hdmiControlManager = getHdmiControlManager(); if (hdmiControlManager != null && hdmiControlManager.shouldHandleTvPowerKey()) { if (down) { if (down && hdmiControlManager != null) { 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, mPowerKeyPressCounter); mPowerKeyHandled ? 1 : 0, mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER)); // Any activity on the power button stops the accessibility shortcut result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately Loading Loading @@ -3890,6 +3839,43 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 Loading Loading @@ -4889,15 +4875,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } 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) { Loading