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

Commit 780509fb authored by Vaibhav Devmurari's avatar Vaibhav Devmurari
Browse files

[2/n] Shift all shortcut key handling logic to KeyGestureController

Test: atest InputTests
DD: go/key_capture
Bug: 416681006
Flag: EXEMPT refactor
Change-Id: I0bfa1b52cfb3bd19bf0add09654433df91a92494
parent 9de69ec8
Loading
Loading
Loading
Loading
+7 −57
Original line number Diff line number Diff line
@@ -16,9 +16,6 @@

package com.android.server.input;

import static android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW;
import static android.content.PermissionChecker.PERMISSION_GRANTED;
import static android.content.PermissionChecker.PID_UNKNOWN;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.provider.DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT;
import static android.view.KeyEvent.KEYCODE_UNKNOWN;
@@ -26,13 +23,13 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M

import static com.android.hardware.input.Flags.enableCustomizableInputGestures;
import static com.android.hardware.input.Flags.fixKeyboardInterceptorPolicyCall;
import static com.android.hardware.input.Flags.fixSearchModifierFallbacks;
import static com.android.hardware.input.Flags.keyEventActivityDetection;
import static com.android.hardware.input.Flags.touchpadVisualizer;
import static com.android.server.policy.WindowManagerPolicy.ACTION_PASS_TO_USER;

import android.Manifest;
import android.annotation.EnforcePermission;
import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -44,7 +41,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
import android.graphics.PointF;
@@ -55,7 +51,6 @@ import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayTopologyGraph;
import android.hardware.display.DisplayViewport;
import android.hardware.input.AidlInputGestureData;
import android.hardware.input.AppLaunchData;
import android.hardware.input.HostUsiVersion;
import android.hardware.input.IInputDeviceBatteryListener;
import android.hardware.input.IInputDeviceBatteryState;
@@ -138,7 +133,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.IShortcutService;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.IProtoLogGroup;
@@ -153,7 +147,6 @@ import com.android.server.input.InputManagerInternal.LidSwitchCallback;
import com.android.server.input.debug.FocusEventDebugView;
import com.android.server.input.debug.TouchpadDebugViewController;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.WindowManagerInternal;

import libcore.io.IoUtils;

@@ -206,8 +199,6 @@ public class InputManagerService extends IInputManager.Stub
    private final InputManagerHandler mHandler;
    private DisplayManagerInternal mDisplayManagerInternal;

    private WindowManagerInternal mWindowManagerInternal;

    private final File mDoubleTouchGestureEnableFile;

    private WindowManagerCallbacks mWindowManagerCallbacks;
@@ -628,7 +619,6 @@ public class InputManagerService extends IInputManager.Stub
        }

        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);

        mSettingsObserver.registerAndUpdate();

@@ -2674,46 +2664,8 @@ public class InputManagerService extends IInputManager.Stub

    // Native callback.
    @SuppressWarnings("unused")
    @VisibleForTesting
    long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
        final long keyNotConsumedGoFallback = -2;
        final long keyConsumed = -1;
        final long keyNotConsumed = 0;
        long value = keyNotConsumed;
        // TODO(b/358569822) Remove below once we have nicer API for listening to shortcuts
        if ((event.isMetaPressed() || KeyEvent.isMetaKey(event.getKeyCode()))
                && shouldInterceptShortcuts(focus)) {
            return keyNotConsumed;
        }
        value = mKeyGestureController.interceptKeyBeforeDispatching(focus, event, policyFlags);
        if (value == keyNotConsumed) {
            value = mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event,
                    policyFlags);
        }
        if (value == keyNotConsumed && event.isMetaPressed()) {
            if (fixSearchModifierFallbacks() ) {
                // If the key has not been consumed and includes the meta key, do not send the event
                // to the app and attempt to generate a fallback.
                final KeyCharacterMap kcm = event.getKeyCharacterMap();
                final KeyCharacterMap.FallbackAction fallbackAction =
                        kcm.getFallbackAction(event.getKeyCode(), event.getMetaState());
                if (fallbackAction != null) {
                    return keyNotConsumedGoFallback;
                }
            }
            return keyConsumed;
        }
        return value;
    }

    private boolean shouldInterceptShortcuts(IBinder focusedToken) {
        KeyInterceptionInfo info =
                mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken);
        boolean hasInterceptWindowFlag = info != null && (info.layoutParamsPrivateFlags
                & WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) != 0;
        return hasInterceptWindowFlag && PermissionChecker.checkPermissionForDataDelivery(mContext,
                OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW, PID_UNKNOWN, info.windowOwnerUid,
                null, null, null) == PERMISSION_GRANTED;
        return mKeyGestureController.interceptKeyBeforeDispatching(focus, event, policyFlags);
    }

    // Native callback.
@@ -3347,13 +3299,9 @@ public class InputManagerService extends IInputManager.Stub
         * key.
         * @param token the window token that's about to receive this event
         * @param event the key event that's being dispatched
         * @param policyFlags the policy flags
         * @return -1 if the key should be skipped (not sent to the app). -2 if the key should not
         * be sent to the app, but it should still generate a fallback.
         * 0 if the key should proceed getting dispatched to the app. positive value to indicate the
         * additional time delay, in nanoseconds, to wait before sending this key to the app.
         * @return {@code true} if consumed, and {@code false} otherwise.
         */
        long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags);
        boolean interceptKeyBeforeDispatching(IBinder token, KeyEvent event);

        /**
         * Intercept unhandled key
@@ -3879,7 +3827,9 @@ public class InputManagerService extends IInputManager.Stub
                        event, /* policyFlags= */0);
            } else {
                return mWindowManagerCallbacks.interceptKeyBeforeDispatching(
                        /* focusedToken= */null, event, /* policyFlags= */0);
                        /* focusedToken= */null, event)
                        ? KeyGestureController.KEY_INTERCEPT_RESULT_CONSUMED
                        : KeyGestureController.KEY_INTERCEPT_RESULT_NOT_CONSUMED;
            }
        }
    }
+66 −2
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.server.input;

import static android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW;
import static android.content.PermissionChecker.PERMISSION_GRANTED;
import static android.content.PermissionChecker.PID_UNKNOWN;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.os.UserManager.isVisibleBackgroundUsersEnabled;
@@ -25,9 +28,11 @@ import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER;
import static android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE;

import static com.android.hardware.input.Flags.enableNew25q2Keycodes;
import static com.android.hardware.input.Flags.fixSearchModifierFallbacks;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;

import android.annotation.BinderThread;
import android.annotation.LongDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -35,6 +40,7 @@ import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.content.ContentResolver;
import android.content.Context;
import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -74,16 +80,20 @@ import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.IShortcutService;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.ScreenshotRequest;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.WindowManagerInternal;

import org.xmlpull.v1.XmlPullParserException;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.HashSet;
@@ -135,6 +145,19 @@ final class KeyGestureController {
    // Increase the chord delay when taking a screenshot from the keyguard
    private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f;

    @LongDef(prefix = {"KEY_INTERCEPT_RESULT_"}, value = {
            KEY_INTERCEPT_RESULT_NOT_CONSUMED_GO_FALLBACK,
            KEY_INTERCEPT_RESULT_CONSUMED,
            KEY_INTERCEPT_RESULT_NOT_CONSUMED
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface KeyInterceptResult {
    }

    private static final long KEY_INTERCEPT_RESULT_NOT_CONSUMED_GO_FALLBACK = -2;
    static final long KEY_INTERCEPT_RESULT_CONSUMED = -1;
    static final long KEY_INTERCEPT_RESULT_NOT_CONSUMED = 0;

    private final Context mContext;
    private InputManagerService.WindowManagerCallbacks mWindowManagerCallbacks;
    private final Handler mHandler;
@@ -193,6 +216,7 @@ final class KeyGestureController {
    private final SparseArray<Set<Integer>> mConsumedKeysForDevice = new SparseArray<>();

    private final UserManagerInternal mUserManagerInternal;
    private WindowManagerInternal mWindowManagerInternal;

    private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled();

@@ -450,6 +474,7 @@ final class KeyGestureController {
    }

    public void systemRunning() {
        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
        mSettingsObserver.observe();
        mAppLaunchShortcutManager.init();
        mInputGestureManager.init(mAppLaunchShortcutManager.getBookmarks());
@@ -504,8 +529,47 @@ final class KeyGestureController {
        return false;
    }

    public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
            int policyFlags) {
    public long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
        // TODO(b/358569822) Remove below once we have nicer API for listening to shortcuts
        if ((event.isMetaPressed() || KeyEvent.isMetaKey(event.getKeyCode()))
                && shouldInterceptShortcuts(focus)) {
            return KEY_INTERCEPT_RESULT_NOT_CONSUMED;
        }
        final long interceptResult = interceptKeyBeforeDispatchingInternal(focus, event);
        if (interceptResult != KEY_INTERCEPT_RESULT_NOT_CONSUMED) {
            // Result is either delay or consumed
            return interceptResult;
        }
        if (mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event)) {
            return KEY_INTERCEPT_RESULT_CONSUMED;
        }
        if (event.isMetaPressed()) {
            if (fixSearchModifierFallbacks() ) {
                // If the key has not been consumed and includes the meta key, do not send the event
                // to the app and attempt to generate a fallback.
                final KeyCharacterMap kcm = event.getKeyCharacterMap();
                final KeyCharacterMap.FallbackAction fallbackAction =
                        kcm.getFallbackAction(event.getKeyCode(), event.getMetaState());
                if (fallbackAction != null) {
                    return KEY_INTERCEPT_RESULT_NOT_CONSUMED_GO_FALLBACK;
                }
            }
            return KEY_INTERCEPT_RESULT_CONSUMED;
        }
        return KEY_INTERCEPT_RESULT_NOT_CONSUMED;
    }

    private boolean shouldInterceptShortcuts(IBinder focusedToken) {
        KeyInterceptionInfo info =
                mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken);
        boolean hasInterceptWindowFlag = info != null && (info.layoutParamsPrivateFlags
                & WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) != 0;
        return hasInterceptWindowFlag && PermissionChecker.checkPermissionForDataDelivery(mContext,
                OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW, PID_UNKNOWN, info.windowOwnerUid,
                null, null, null) == PERMISSION_GRANTED;
    }

    private long interceptKeyBeforeDispatchingInternal(IBinder focusedToken, KeyEvent event) {
        // TODO(b/358569822): Handle shortcuts trigger logic here and pass it to appropriate
        //  KeyGestureHandler (PWM is one of the handlers)
        final int keyCode = event.getKeyCode();
+3 −7
Original line number Diff line number Diff line
@@ -3334,12 +3334,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    // TODO (b/283241997): Add the remaining keyboard shortcut logging after refactoring
    /** {@inheritDoc} */
    @Override
    public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
            int policyFlags) {
    public boolean interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event) {
        final int keyCode = event.getKeyCode();
        final int flags = event.getFlags();
        final long keyConsumed = -1;
        final long keyNotConsumed = 0;
        final int deviceId = event.getDeviceId();

        if (DEBUG_INPUT) {
@@ -3358,7 +3354,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        if (interceptSystemKeysAndShortcuts(focusedToken, event)
                && event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
            consumedKeys.add(keyCode);
            return keyConsumed;
            return true;
        }

        boolean needToConsumeKey = consumedKeys.contains(keyCode);
@@ -3369,7 +3365,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            }
        }

        return needToConsumeKey ? keyConsumed : keyNotConsumed;
        return needToConsumeKey;
    }

    // You can only start consuming the key gesture if ACTION_DOWN and repeat count
+2 −6
Original line number Diff line number Diff line
@@ -735,13 +735,9 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
     * @param focusedToken Client window token that currently has focus. This is where the key
     *            event will normally go.
     * @param event The key event.
     * @param policyFlags The policy flags associated with the key.
     * @return 0 if the key should be dispatched immediately, -1 if the key should
     * not be dispatched ever, or a positive value indicating the number of
     * milliseconds by which the key dispatch should be delayed before trying
     * again.
     * @return {@code true} if consumed, and {@code false} otherwise.
     */
    long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event, int policyFlags);
    boolean interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event);

    /**
     * Called from the input dispatcher thread when an application did not handle
+2 −3
Original line number Diff line number Diff line
@@ -234,9 +234,8 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
     * ordinary dispatch.
     */
    @Override
    public long interceptKeyBeforeDispatching(
            IBinder focusedToken, KeyEvent event, int policyFlags) {
        return mService.mPolicy.interceptKeyBeforeDispatching(focusedToken, event, policyFlags);
    public boolean interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event) {
        return mService.mPolicy.interceptKeyBeforeDispatching(focusedToken, event);
    }

    /**
Loading