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

Commit e5c25297 authored by Charles Wang's avatar Charles Wang Committed by Android (Google) Code Review
Browse files

Merge "Add WindowManager flag for capturing the power key event in the foreground." into main

parents c5f1f9aa 2d5b6806
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19150,8 +19150,10 @@ 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
+75 −0
Original line number Diff line number Diff line
@@ -80,6 +80,9 @@ 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;
@@ -4464,6 +4467,29 @@ 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}.
         *
@@ -4477,6 +4503,7 @@ public interface WindowManager extends ViewManager {
                INPUT_FEATURE_DISABLE_USER_ACTIVITY,
                INPUT_FEATURE_SPY,
                INPUT_FEATURE_SENSITIVE_FOR_PRIVACY,
                INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS
        })
        public @interface InputFeatureFlags {
        }
@@ -4765,6 +4792,44 @@ 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
@@ -6157,6 +6222,16 @@ 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));
            }
+22 −1
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SENSITIVE_FOR_PRIVACY;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
@@ -101,6 +102,7 @@ import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ER
import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.window.WindowProviderService.isWindowProviderService;

import static com.android.hardware.input.Flags.overridePowerKeyBehaviorInFocusedWindow;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM;
import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_BOOT;
@@ -157,9 +159,9 @@ import static com.android.server.wm.WindowManagerServiceDumpProto.INPUT_METHOD_W
import static com.android.server.wm.WindowManagerServiceDumpProto.POLICY;
import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID;
import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions;
import static com.android.window.flags.Flags.multiCrop;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions;

import android.Manifest;
import android.Manifest.permission;
@@ -9221,6 +9223,25 @@ public class WindowManagerService extends IWindowManager.Stub
                    + "' because it isn't a trusted overlay");
            return inputFeatures & ~INPUT_FEATURE_SENSITIVE_FOR_PRIVACY;
        }

        // You need OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW permission to be able
        // to set INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS.
        if (overridePowerKeyBehaviorInFocusedWindow()
                && (inputFeatures
                & INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS)
                != 0) {
            final int powerPermissionResult =
                    mContext.checkPermission(
                            permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW,
                            callingPid,
                            callingUid);
            if (powerPermissionResult != PackageManager.PERMISSION_GRANTED) {
                throw new IllegalArgumentException(
                        "Cannot use INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS from" + windowName
                                + " because it doesn't have the"
                                + " OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW permission");
            }
        }
        return inputFeatures;
    }

+50 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.view.Display.FLAG_OWN_FOCUS;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SENSITIVE_FOR_PRIVACY;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
@@ -46,6 +47,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.hardware.input.Flags.FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW;
import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR;
@@ -75,6 +77,7 @@ import static org.mockito.Mockito.when;
import android.app.ActivityThread;
import android.app.IApplicationThread;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
@@ -1135,6 +1138,53 @@ public class WindowManagerServiceTests extends WindowTestsBase {
                        null /* region */));
    }

    @Test
    @RequiresFlagsEnabled(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW)
    public void testUpdateInputChannel_sanitizeWithoutPermission_ThrowsError() {
        final Session session = mock(Session.class);
        final int callingUid = Process.FIRST_APPLICATION_UID;
        final int callingPid = 1234;
        final SurfaceControl surfaceControl = mock(SurfaceControl.class);
        final IBinder window = new Binder();
        final InputTransferToken inputTransferToken = mock(InputTransferToken.class);


        final InputChannel inputChannel = new InputChannel();

        assertThrows(IllegalArgumentException.class, () ->
                mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY,
                        surfaceControl, window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE,
                        0 /* privateFlags */,
                        INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS,
                        TYPE_APPLICATION, null /* windowToken */, inputTransferToken,
                        "TestInputChannel", inputChannel));
    }


    @Test
    @RequiresFlagsEnabled(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW)
    public void testUpdateInputChannel_sanitizeWithPermission_doesNotThrowError() {
        final Session session = mock(Session.class);
        final int callingUid = Process.FIRST_APPLICATION_UID;
        final int callingPid = 1234;
        final SurfaceControl surfaceControl = mock(SurfaceControl.class);
        final IBinder window = new Binder();
        final InputTransferToken inputTransferToken = mock(InputTransferToken.class);

        doReturn(PackageManager.PERMISSION_GRANTED).when(mWm.mContext).checkPermission(
                android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW,
                callingPid,
                callingUid);

        final InputChannel inputChannel = new InputChannel();

        mWm.grantInputChannel(session, callingUid, callingPid, DEFAULT_DISPLAY, surfaceControl,
                window, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, 0 /* privateFlags */,
                INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS,
                TYPE_APPLICATION, null /* windowToken */, inputTransferToken, "TestInputChannel",
                inputChannel);
    }

    @Test
    public void testUpdateInputChannel_allowSpyWindowForInputMonitorPermission() {
        final Session session = mock(Session.class);