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

Commit eee436fd authored by Charles Wang's avatar Charles Wang
Browse files

Remove foreground power key code.

Remove code associated with foreground power key capture for system
apps, including the system API (reverts ag/30871623 and ag/30152916).

The decision was made to abandon this change for 25Q2 as Wallet does not
plan to use this feature with the system app limitation.

The flag is already rolled back in Gantry: see https://gantry.corp.google.com/changes/0a61p0a000001?build_unique_id=ComAndroidHardwareInputOverridePowerKeyBehaviorInFocusedWindowLaunch-platform&apply_default_filter=true&enable_workflow_timeline=false
Context: b/357144512#comment55

Test: atest PowerKeyGestureTests && atest GestureLauncherServicetest &&
atest WindowManagerServiceTests
Test: manually ensuring power button shortcuts remain same as before.
Bug: 357144512
Flag: com.android.hardware.input.override_power_key_behavior_in_focused_window

Change-Id: Ifd533b7e28745dd78be8ff53bd0cc465f248dda4
parent 0fa17c84
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -18977,10 +18977,8 @@ package android.view {
  public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
    method public final long getUserActivityTimeout();
    method @FlaggedApi("com.android.hardware.input.override_power_key_behavior_in_focused_window") @RequiresPermission(android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) public boolean isReceivePowerKeyDoublePressEnabled();
    method public boolean isSystemApplicationOverlay();
    method @FlaggedApi("android.companion.virtualdevice.flags.status_bar_and_insets") public void setInsetsParams(@NonNull java.util.List<android.view.WindowManager.InsetsParams>);
    method @FlaggedApi("com.android.hardware.input.override_power_key_behavior_in_focused_window") @RequiresPermission(android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) public void setReceivePowerKeyDoublePressEnabled(boolean);
    method @RequiresPermission(android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY) public void setSystemApplicationOverlay(boolean);
    method public final void setUserActivityTimeout(long);
    field @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS) public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
+1 −76
Original line number Diff line number Diff line
@@ -80,9 +80,6 @@ import static android.view.WindowLayoutParamsProto.WINDOW_ANIMATIONS;
import static android.view.WindowLayoutParamsProto.X;
import static android.view.WindowLayoutParamsProto.Y;

import static com.android.hardware.input.Flags.FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW;
import static com.android.hardware.input.Flags.overridePowerKeyBehaviorInFocusedWindow;

import android.Manifest.permission;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
@@ -4548,29 +4545,6 @@ public interface WindowManager extends ViewManager {
         */
        public static final int INPUT_FEATURE_SENSITIVE_FOR_PRIVACY = 1 << 3;

        /**
         * Input feature used to indicate that the system should send power key events to this
         * window when it's in the foreground. The window can override the double press power key
         * gesture behavior.
         *
         * A double press gesture is defined as two
         * {@link KeyEvent.Callback#onKeyDown(int, KeyEvent)} events within a time span defined by
         *  {@link ViewConfiguration#getMultiPressTimeout()}.
         *
         * Note: While the window may receive all power key {@link KeyEvent}s, it can only
         * override the double press gesture behavior. The system will perform default behavior for
         * single, long-press and other multi-press gestures, regardless of if the app handles the
         * key or not.
         *
         * To override the default behavior for double press, the app must return true for the
         * second {@link KeyEvent.Callback#onKeyDown(int, KeyEvent)}. If the app returns false, the
         * system behavior will be performed for double press.
         * @hide
         */
        @RequiresPermission(permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW)
        public static final int
                INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS = 1 << 4;

        /**
         * An internal annotation for flags that can be specified to {@link #inputFeatures}.
         *
@@ -4583,8 +4557,7 @@ public interface WindowManager extends ViewManager {
                INPUT_FEATURE_NO_INPUT_CHANNEL,
                INPUT_FEATURE_DISABLE_USER_ACTIVITY,
                INPUT_FEATURE_SPY,
                INPUT_FEATURE_SENSITIVE_FOR_PRIVACY,
                INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS
                INPUT_FEATURE_SENSITIVE_FOR_PRIVACY
        })
        public @interface InputFeatureFlags {
        }
@@ -4873,44 +4846,6 @@ public interface WindowManager extends ViewManager {
            privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
        }

        /**
         * Specifies if the system should send power key events to this window when it's in the
         * foreground, with only the double tap gesture behavior being overrideable.
         *
         * @param enabled if true, the system should send power key events to this window when it's
         *              in the foreground, with only the power key double tap gesture being
         *              overrideable.
         * @hide
         */
        @SystemApi
        @RequiresPermission(permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW)
        @FlaggedApi(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW)
        public void setReceivePowerKeyDoublePressEnabled(boolean enabled) {
            if (enabled) {
                inputFeatures
                        |= INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS;
            } else {
                inputFeatures
                        &= ~INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS;
            }
        }

        /**
         * Returns whether or not the system should send power key events to this window when it's
         * in the foreground, with only the double tap gesture being overrideable.
         *
         * @return if the system should send power key events to this window when it's in the
         * foreground, with only the double tap gesture being overrideable.
         * @hide
         */
        @SystemApi
        @RequiresPermission(permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW)
        @FlaggedApi(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW)
        public boolean isReceivePowerKeyDoublePressEnabled() {
            return (inputFeatures
                    & INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS) != 0;
        }

        /**
         * Specifies that the window should be considered a trusted system overlay. Trusted system
         * overlays are ignored when considering whether windows are obscured during input
@@ -6312,16 +6247,6 @@ public interface WindowManager extends ViewManager {
                inputFeatures &= ~INPUT_FEATURE_SPY;
                features.add("INPUT_FEATURE_SPY");
            }
            if (overridePowerKeyBehaviorInFocusedWindow()) {
                if ((inputFeatures
                        & INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS)
                        != 0) {
                    inputFeatures
                            &=
                            ~INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS;
                    features.add("INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS");
                }
            }
            if (inputFeatures != 0) {
                features.add(Integer.toHexString(inputFeatures));
            }
+1 −3
Original line number Diff line number Diff line
@@ -27,13 +27,11 @@ public class KeyInterceptionInfo {
    // Debug friendly name to help identify the window
    public final String windowTitle;
    public final int windowOwnerUid;
    public final int inputFeaturesFlags;

    public KeyInterceptionInfo(int type, int flags, String title, int uid, int inputFeaturesFlags) {
    public KeyInterceptionInfo(int type, int flags, String title, int uid) {
        layoutParamsType = type;
        layoutParamsPrivateFlags = flags;
        windowTitle = title;
        windowOwnerUid = uid;
        this.inputFeaturesFlags = inputFeaturesFlags;
    }
}
+1 −42
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.server;
import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap;
import static android.service.quickaccesswallet.Flags.launchWalletViaSysuiCallbacks;

import static com.android.hardware.input.Flags.overridePowerKeyBehaviorInFocusedWindow;
import static com.android.internal.R.integer.config_defaultMinEmergencyGestureTapDurationMillis;

import android.app.ActivityManager;
@@ -634,46 +633,6 @@ public class GestureLauncherService extends SystemService {
        return res;
    }

    /**
     * Processes a power key event in GestureLauncherService without performing an action. This
     * method is called on every KEYCODE_POWER ACTION_DOWN event and ensures that, even if
     * KEYCODE_POWER events are passed to and handled by the app, the GestureLauncherService still
     * keeps track of all running KEYCODE_POWER events for its gesture detection and relevant
     * actions.
     */
    public void processPowerKeyDown(KeyEvent event) {
        if (mEmergencyGestureEnabled && mEmergencyGesturePowerButtonCooldownPeriodMs >= 0
                && event.getEventTime() - mLastEmergencyGestureTriggered
                < mEmergencyGesturePowerButtonCooldownPeriodMs) {
            return;
        }
        if (event.isLongPress()) {
            return;
        }

        final long powerTapInterval;

        synchronized (this) {
            powerTapInterval = event.getEventTime() - mLastPowerDown;
            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 >= POWER_DOUBLE_TAP_MAX_TIME_MS) {
                // Tap too slow for shortcuts
                mFirstPowerDown = event.getEventTime();
                mPowerButtonConsecutiveTaps = 1;
                mPowerButtonSlowConsecutiveTaps++;
            } else if (!overridePowerKeyBehaviorInFocusedWindow() || powerTapInterval > 0) {
                // Fast consecutive tap
                mPowerButtonConsecutiveTaps++;
                mPowerButtonSlowConsecutiveTaps++;
            }
        }
    }

    /**
     * Attempts to intercept power key down event by detecting certain gesture patterns
     *
@@ -721,7 +680,7 @@ public class GestureLauncherService extends SystemService {
                mFirstPowerDown  = event.getEventTime();
                mPowerButtonConsecutiveTaps = 1;
                mPowerButtonSlowConsecutiveTaps++;
            } else if (powerTapInterval > 0) {
            } else {
                // Fast consecutive tap
                mPowerButtonConsecutiveTaps++;
                mPowerButtonSlowConsecutiveTaps++;
+4 −213
Original line number Diff line number Diff line
@@ -520,32 +520,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {

    private WindowWakeUpPolicy mWindowWakeUpPolicy;

    /**
     * The three variables below are used for custom power key gesture detection in
     * PhoneWindowManager. They are used to detect when the power button has been double pressed
     * and, when it does happen, makes the behavior overrideable by the app.
     *
     * We cannot use the {@link PowerKeyRule} for this because multi-press power gesture detection
     * and behaviors are handled by {@link com.android.server.GestureLauncherService}, and the
     * {@link PowerKeyRule} only handles single and long-presses of the power button. As a result,
     * overriding the double tap behavior requires custom gesture detection here that mimics the
     * logic in {@link com.android.server.GestureLauncherService}.
     *
     * Long-term, it would be beneficial to move all power gesture detection to
     * {@link PowerKeyRule} so that this custom logic isn't required.
     */
    // Time of last power down event.
    private long mLastPowerDown;

    // Number of power button events consecutively triggered (within a specific timeout threshold).
    private int mPowerButtonConsecutiveTaps = 0;

    // Whether a double tap of the power button has been detected.
    volatile boolean mDoubleTapPowerDetected;

    // Runnable that is queued on a delay when the first power keyDown event is sent to the app.
    private Runnable mPowerKeyDelayedRunnable = null;

    boolean mSafeMode;

    // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
@@ -1135,10 +1109,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                || handledByPowerManager || isKeyGestureTriggered
                || mKeyCombinationManager.isPowerKeyIntercepted();

        if (overridePowerKeyBehaviorInFocusedWindow()) {
            mPowerKeyHandled |= mDoubleTapPowerDetected;
        }

        if (!mPowerKeyHandled) {
            if (!interactive) {
                wakeUpFromWakeKey(event);
@@ -2785,19 +2755,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            if (mShouldEarlyShortPressOnPower) {
                return;
            }
            // TODO(b/380433365): Remove deferring single power press action when refactoring.
            if (overridePowerKeyBehaviorInFocusedWindow()) {
                mDeferredKeyActionExecutor.cancelQueuedAction(KEYCODE_POWER);
                mDeferredKeyActionExecutor.queueKeyAction(
                        KEYCODE_POWER,
                        downTime,
                        () -> {
                            powerPress(downTime, 1 /*count*/, displayId);
                        });
            } else {
            powerPress(downTime, 1 /*count*/, displayId);
        }
        }

        @Override
        long getLongPressTimeoutMs() {
@@ -2827,17 +2786,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {

        @Override
        void onMultiPress(long downTime, int count, int displayId) {
            if (overridePowerKeyBehaviorInFocusedWindow()) {
                mDeferredKeyActionExecutor.cancelQueuedAction(KEYCODE_POWER);
                mDeferredKeyActionExecutor.queueKeyAction(
                        KEYCODE_POWER,
                        downTime,
                        () -> {
            powerPress(downTime, count, displayId);
                        });
            } else {
                powerPress(downTime, count, displayId);
            }
        }

        @Override
@@ -3614,12 +3563,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            }
        }

        if (overridePowerKeyBehaviorInFocusedWindow() && event.getKeyCode() == KEYCODE_POWER
                && event.getAction() == KeyEvent.ACTION_UP
                && mDoubleTapPowerDetected) {
            mDoubleTapPowerDetected = false;
        }

        return needToConsumeKey ? keyConsumed : keyNotConsumed;
    }

@@ -4117,8 +4060,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    sendSystemKeyToStatusBarAsync(event);
                    return true;
                }
            case KeyEvent.KEYCODE_POWER:
                return interceptPowerKeyBeforeDispatching(focusedToken, event);
            case KeyEvent.KEYCODE_SCREENSHOT:
                if (firstDown) {
                    interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
@@ -4174,8 +4115,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    sendSystemKeyToStatusBarAsync(event);
                    return true;
                }
            case KeyEvent.KEYCODE_POWER:
                return interceptPowerKeyBeforeDispatching(focusedToken, event);
        }
        if (isValidGlobalKey(keyCode)
                && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
@@ -4193,90 +4132,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        return (metaState & KeyEvent.META_META_ON) != 0;
    }

    /**
     * Called by interceptKeyBeforeDispatching to handle interception logic for KEYCODE_POWER
     * KeyEvents.
     *
     * @return true if intercepting the key, false if sending to app.
     */
    private boolean interceptPowerKeyBeforeDispatching(IBinder focusedToken, KeyEvent event) {
        if (!overridePowerKeyBehaviorInFocusedWindow()) {
            //Flag disabled: intercept the power key and do not send to app.
            return true;
        }
        if (event.getKeyCode() != KEYCODE_POWER) {
            Log.wtf(TAG, "interceptPowerKeyBeforeDispatching received a non-power KeyEvent "
                    + "with key code: " + event.getKeyCode());
            return false;
        }

        // Intercept keys (don't send to app) for 3x, 4x, 5x gestures)
        if (mPowerButtonConsecutiveTaps > DOUBLE_POWER_TAP_COUNT_THRESHOLD) {
            setDeferredKeyActionsExecutableAsync(KEYCODE_POWER, event.getDownTime());
            return true;
        }

        // UP key; just reuse the original decision.
        if (event.getAction() == KeyEvent.ACTION_UP) {
            final Set<Integer> consumedKeys = mConsumedKeysForDevice.get(event.getDeviceId());
            return consumedKeys != null
                    && consumedKeys.contains(event.getKeyCode());
        }

        KeyInterceptionInfo info =
                mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken);

        if (info == null || !mButtonOverridePermissionChecker.canWindowOverridePowerKey(mContext,
                info.windowOwnerUid, info.inputFeaturesFlags)) {
            // The focused window does not have the permission to override power key behavior.
            if (DEBUG_INPUT) {
                String interceptReason = "";
                if (info == null) {
                    interceptReason = "Window is null";
                } else if (!mButtonOverridePermissionChecker.canAppOverrideSystemKey(mContext,
                        info.windowOwnerUid)) {
                    interceptReason = "Application does not have "
                            + "OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW permission";
                } else {
                    interceptReason = "Window does not have inputFeatureFlag set";
                }

                Log.d(TAG, TextUtils.formatSimple("Intercepting KEYCODE_POWER event. action=%d, "
                                + "eventTime=%d to window=%s. interceptReason=%s. "
                                + "mDoubleTapPowerDetected=%b",
                        event.getAction(), event.getEventTime(), (info != null)
                                ? info.windowTitle : "null", interceptReason,
                        mDoubleTapPowerDetected));
            }
            // Intercept the key (i.e. do not send to app)
            setDeferredKeyActionsExecutableAsync(KEYCODE_POWER, event.getDownTime());
            return true;
        }

        if (DEBUG_INPUT) {
            Log.d(TAG, TextUtils.formatSimple("Sending KEYCODE_POWER to app. action=%d, "
                            + "eventTime=%d to window=%s. mDoubleTapPowerDetected=%b",
                    event.getAction(), event.getEventTime(), info.windowTitle,
                    mDoubleTapPowerDetected));
        }

        if (!mDoubleTapPowerDetected) {
            //Single press: post a delayed runnable for the single press power action that will be
            // called if it's not cancelled by a double press.
            final var downTime = event.getDownTime();
            mPowerKeyDelayedRunnable = () ->
                    setDeferredKeyActionsExecutableAsync(KEYCODE_POWER, downTime);
            mHandler.postDelayed(mPowerKeyDelayedRunnable, POWER_MULTI_PRESS_TIMEOUT_MILLIS);
        } else if (mPowerKeyDelayedRunnable != null) {
            //Double press detected: cancel the single press runnable.
            mHandler.removeCallbacks(mPowerKeyDelayedRunnable);
            mPowerKeyDelayedRunnable = null;
        }

        // Focused window has permission. Send to app.
        return false;
    }

    @SuppressLint("MissingPermission")
    private void initKeyGestures() {
        if (!useKeyGestureEventHandler()) {
@@ -4764,11 +4619,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            return true;
        }

        if (overridePowerKeyBehaviorInFocusedWindow() && keyCode == KEYCODE_POWER) {
            handleUnhandledSystemKey(event);
            return true;
        }

        if (useKeyGestureEventHandler()) {
            return false;
        }
@@ -5595,12 +5445,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                        KeyEvent.actionToString(event.getAction()),
                        mPowerKeyHandled ? 1 : 0,
                        mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
                if (overridePowerKeyBehaviorInFocusedWindow()) {
                    result |= ACTION_PASS_TO_USER;
                } else {
                // Any activity on the power button stops the accessibility shortcut
                result &= ~ACTION_PASS_TO_USER;
                }
                isWakeKey = false; // wake-up will be handled separately
                if (down) {
                    interceptPowerKeyDown(event, interactiveAndAwake, isKeyGestureTriggered);
@@ -5862,35 +5708,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }

        if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) {
            if (overridePowerKeyBehaviorInFocusedWindow()) {
                if (event.getRepeatCount() > 0 && !mHasFeatureWatch) {
                    return;
                }
                if (mGestureLauncherService != null) {
                    mGestureLauncherService.processPowerKeyDown(event);
                }

                if (detectDoubleTapPower(event)) {
                    mDoubleTapPowerDetected = true;

                    // Copy of the event for handler in case the original event gets recycled.
                    KeyEvent eventCopy = KeyEvent.obtain(event);
                    mDeferredKeyActionExecutor.queueKeyAction(
                            KeyEvent.KEYCODE_POWER,
                            eventCopy.getEventTime(),
                            () -> {
                                if (!handleCameraGesture(eventCopy, interactive)) {
                                    mSingleKeyGestureDetector.interceptKey(
                                            eventCopy, interactive, defaultDisplayOn);
                                } else {
                                    mSingleKeyGestureDetector.reset();
                                }
                                eventCopy.recycle();
                            });
                    return;
                }
            }

            mPowerKeyHandled = handleCameraGesture(event, interactive);
            if (mPowerKeyHandled) {
                // handled by camera gesture.
@@ -5902,26 +5719,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        mSingleKeyGestureDetector.interceptKey(event, interactive, defaultDisplayOn);
    }

    private boolean detectDoubleTapPower(KeyEvent event) {
        //Watches use the SingleKeyGestureDetector for detecting multi-press gestures.
        if (mHasFeatureWatch || event.getKeyCode() != KEYCODE_POWER
                || event.getAction() != KeyEvent.ACTION_DOWN  || event.getRepeatCount() != 0) {
            return false;
        }

        final long powerTapInterval = event.getEventTime() - mLastPowerDown;
        mLastPowerDown = event.getEventTime();
        if (powerTapInterval >= POWER_MULTI_PRESS_TIMEOUT_MILLIS) {
            // Tap too slow for double press
            mPowerButtonConsecutiveTaps = 1;
        } else {
            mPowerButtonConsecutiveTaps++;
        }

        return powerTapInterval < POWER_MULTI_PRESS_TIMEOUT_MILLIS
                && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD;
    }

    // The camera gesture will be detected by GestureLauncherService.
    private boolean handleCameraGesture(KeyEvent event, boolean interactive) {
        // camera gesture.
@@ -7779,12 +7576,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    null)
                    == PERMISSION_GRANTED;
        }

        boolean canWindowOverridePowerKey(Context context, int uid, int inputFeaturesFlags) {
            return canAppOverrideSystemKey(context, uid)
                    && (inputFeaturesFlags & WindowManager.LayoutParams
                    .INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS) != 0;
        }
    }

    private int getTargetDisplayIdForKeyEvent(KeyEvent event) {
Loading