Merge "Block visible background user unallowed key event gestures" into main
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index cb1e016..290f526 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -232,6 +232,26 @@
     public @interface KeyGestureType {
     }
 
+    /**
+     * Returns whether the key gesture type passed as argument is allowed for visible background
+     * users.
+     *
+     * @hide
+     */
+    public static boolean isVisibleBackgrounduserAllowedGesture(int keyGestureType) {
+        switch (keyGestureType) {
+            case KEY_GESTURE_TYPE_SLEEP:
+            case KEY_GESTURE_TYPE_WAKEUP:
+            case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
+            case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
+            case KEY_GESTURE_TYPE_VOLUME_MUTE:
+            case KEY_GESTURE_TYPE_RECENT_APPS:
+            case KEY_GESTURE_TYPE_APP_SWITCH:
+                return false;
+        }
+        return true;
+    }
+
     public KeyGestureEvent(@NonNull AidlKeyGestureEvent keyGestureEvent) {
         this.mKeyGestureEvent = keyGestureEvent;
     }
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index 5f7ad27..db6d772 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -18,6 +18,8 @@
 
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.os.UserManager.isVisibleBackgroundUsersEnabled;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE;
 
 import static com.android.hardware.input.Flags.enableNew25q2Keycodes;
@@ -55,7 +57,6 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.view.Display;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -64,6 +65,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.IShortcutService;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
 import com.android.server.policy.KeyCombinationManager;
 
 import java.util.ArrayDeque;
@@ -159,6 +162,10 @@
     /** Currently fully consumed key codes per device */
     private final SparseArray<Set<Integer>> mConsumedKeysForDevice = new SparseArray<>();
 
+    private final UserManagerInternal mUserManagerInternal;
+
+    private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled();
+
     KeyGestureController(Context context, Looper looper, InputDataStore inputDataStore) {
         mContext = context;
         mHandler = new Handler(looper, this::handleMessage);
@@ -180,6 +187,7 @@
         mAppLaunchShortcutManager = new AppLaunchShortcutManager(mContext);
         mInputGestureManager = new InputGestureManager(mContext);
         mInputDataStore = inputDataStore;
+        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         initBehaviors();
         initKeyCombinationRules();
     }
@@ -449,6 +457,9 @@
     }
 
     public boolean interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+        if (mVisibleBackgroundUsersEnabled && shouldIgnoreKeyEventForVisibleBackgroundUser(event)) {
+            return false;
+        }
         final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
         if (InputSettings.doesKeyGestureEventHandlerSupportMultiKeyGestures()
                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
@@ -457,6 +468,24 @@
         return false;
     }
 
+    private boolean shouldIgnoreKeyEventForVisibleBackgroundUser(KeyEvent event) {
+        final int displayAssignedUserId = mUserManagerInternal.getUserAssignedToDisplay(
+                event.getDisplayId());
+        final int currentUserId;
+        synchronized (mUserLock) {
+            currentUserId = mCurrentUserId;
+        }
+        if (currentUserId != displayAssignedUserId
+                && !KeyEvent.isVisibleBackgroundUserAllowedKey(event.getKeyCode())) {
+            if (DEBUG) {
+                Slog.w(TAG, "Ignored key event [" + event + "] for visible background user ["
+                        + displayAssignedUserId + "]");
+            }
+            return true;
+        }
+        return false;
+    }
+
     public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
             int policyFlags) {
         // TODO(b/358569822): Handle shortcuts trigger logic here and pass it to appropriate
@@ -895,7 +924,7 @@
     private void handleMultiKeyGesture(int[] keycodes,
             @KeyGestureEvent.KeyGestureType int gestureType, int action, int flags) {
         handleKeyGesture(KeyCharacterMap.VIRTUAL_KEYBOARD, keycodes, /* modifierState= */0,
-                gestureType, action, Display.DEFAULT_DISPLAY, /* focusedToken = */null, flags,
+                gestureType, action, DEFAULT_DISPLAY, /* focusedToken = */null, flags,
                 /* appLaunchData = */null);
     }
 
@@ -903,7 +932,7 @@
             @Nullable AppLaunchData appLaunchData) {
         handleKeyGesture(KeyCharacterMap.VIRTUAL_KEYBOARD, new int[0], /* modifierState= */0,
                 keyGestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE,
-                Display.DEFAULT_DISPLAY, /* focusedToken = */null, /* flags = */0, appLaunchData);
+                DEFAULT_DISPLAY, /* focusedToken = */null, /* flags = */0, appLaunchData);
     }
 
     @VisibleForTesting
@@ -915,6 +944,11 @@
     }
 
     private boolean handleKeyGesture(AidlKeyGestureEvent event, @Nullable IBinder focusedToken) {
+        if (mVisibleBackgroundUsersEnabled && event.displayId != DEFAULT_DISPLAY
+                && shouldIgnoreGestureEventForVisibleBackgroundUser(event.gestureType,
+                event.displayId)) {
+            return false;
+        }
         synchronized (mKeyGestureHandlerRecords) {
             for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) {
                 if (handler.handleKeyGesture(event, focusedToken)) {
@@ -927,6 +961,24 @@
         return false;
     }
 
+    private boolean shouldIgnoreGestureEventForVisibleBackgroundUser(
+            @KeyGestureEvent.KeyGestureType int gestureType, int displayId) {
+        final int displayAssignedUserId = mUserManagerInternal.getUserAssignedToDisplay(displayId);
+        final int currentUserId;
+        synchronized (mUserLock) {
+            currentUserId = mCurrentUserId;
+        }
+        if (currentUserId != displayAssignedUserId
+                && !KeyGestureEvent.isVisibleBackgrounduserAllowedGesture(gestureType)) {
+            if (DEBUG) {
+                Slog.w(TAG, "Ignored gesture event [" + gestureType
+                        + "] for visible background user [" + displayAssignedUserId + "]");
+            }
+            return true;
+        }
+        return false;
+    }
+
     private boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
         synchronized (mKeyGestureHandlerRecords) {
             for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) {
@@ -943,7 +995,7 @@
         // TODO(b/358569822): Once we move the gesture detection logic to IMS, we ideally
         //  should not rely on PWM to tell us about the gesture start and end.
         AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState,
-                gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY,
+                gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, DEFAULT_DISPLAY,
                 /* flags = */0, /* appLaunchData = */null);
         mHandler.obtainMessage(MSG_NOTIFY_KEY_GESTURE_EVENT, event).sendToTarget();
     }
@@ -951,7 +1003,7 @@
     public void handleKeyGesture(int deviceId, int[] keycodes, int modifierState,
             @KeyGestureEvent.KeyGestureType int gestureType) {
         AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState,
-                gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY,
+                gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, DEFAULT_DISPLAY,
                 /* flags = */0, /* appLaunchData = */null);
         handleKeyGesture(event, null /*focusedToken*/);
     }