Add keyboard shortcuts implementation for Desktop Windowing task
resizing keyboard shortcuts (snap left/right, toggle window size and
minimize task)

Flag: com.android.window.flags.enable_task_resizing_keyboard_shortcuts
Test: atest DesktopModeKeyGestureHandlerTest
Bug: 335819608
Change-Id: I4c5318ccfda0043e13b377196cb35c78a7815da8
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index 24951c4..711dc3a 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -115,12 +115,14 @@
     public static final int KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS = 67;
     public static final int KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW = 68;
     public static final int KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW = 69;
-    public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 70;
-    public static final int KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE = 71;
+    public static final int KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW = 70;
+    public static final int KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW = 71;
     public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN = 72;
     public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT = 73;
     public static final int KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION = 74;
     public static final int KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK = 75;
+    public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 76;
+
 
     public static final int FLAG_CANCELLED = 1;
 
@@ -205,12 +207,13 @@
             KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
             KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
             KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
-            KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
-            KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
+            KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW,
+            KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
             KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN,
             KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT,
             KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION,
             KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK,
+            KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface KeyGestureType {
@@ -557,14 +560,6 @@
                 return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE;
             case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
                 return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION;
-            case KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW:
-                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_LEFT_FREEFORM_WINDOW;
-            case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW:
-                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_RIGHT_FREEFORM_WINDOW;
-            case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
-                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MAXIMIZE_FREEFORM_WINDOW;
-            case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE:
-                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RESTORE_FREEFORM_WINDOW_SIZE;
             default:
                 return LOG_EVENT_UNSPECIFIED;
         }
@@ -777,10 +772,10 @@
                 return "KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW";
             case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW:
                 return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW";
-            case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
-                return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW";
-            case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE:
-                return "KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE";
+            case KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW:
+                return "KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW";
+            case KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW:
+                return "KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW";
             case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN:
                 return "KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN";
             case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT:
@@ -789,6 +784,8 @@
                 return "KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION";
             case KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK:
                 return "KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK";
+            case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
+                return "KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW";
             default:
                 return Integer.toHexString(value);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 00c1578..e5abd72 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -20,6 +20,7 @@
 import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
 import static android.window.DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS;
 
+import static com.android.hardware.input.Flags.manageKeyGestures;
 import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
 
 import android.annotation.NonNull;
@@ -884,13 +885,15 @@
     @Provides
     static Optional<DesktopModeKeyGestureHandler> provideDesktopModeKeyGestureHandler(
             Context context,
-            DesktopModeWindowDecorViewModel desktopModeWindowDecorViewModel,
+            Optional<DesktopModeWindowDecorViewModel> desktopModeWindowDecorViewModel,
             Optional<DesktopTasksController> desktopTasksController,
             InputManager inputManager,
             ShellTaskOrganizer shellTaskOrganizer,
             FocusTransitionObserver focusTransitionObserver) {
         if (DesktopModeStatus.canEnterDesktopMode(context) && useKeyGestureEventHandler()
-                && Flags.enableMoveToNextDisplayShortcut()) {
+                && manageKeyGestures()
+                && (Flags.enableMoveToNextDisplayShortcut()
+                || Flags.enableTaskResizingKeyboardShortcuts())) {
             return Optional.of(new DesktopModeKeyGestureHandler(context,
                     desktopModeWindowDecorViewModel, desktopTasksController,
                     inputManager, shellTaskOrganizer, focusTransitionObserver));
@@ -900,7 +903,7 @@
 
     @WMSingleton
     @Provides
-    static DesktopModeWindowDecorViewModel provideDesktopModeWindowDecorViewModel(
+    static Optional<DesktopModeWindowDecorViewModel> provideDesktopModeWindowDecorViewModel(
             Context context,
             @ShellMainThread ShellExecutor shellExecutor,
             @ShellMainThread Handler mainHandler,
@@ -930,7 +933,10 @@
             FocusTransitionObserver focusTransitionObserver,
             DesktopModeEventLogger desktopModeEventLogger
     ) {
-        return new DesktopModeWindowDecorViewModel(context, shellExecutor, mainHandler,
+        if (!DesktopModeStatus.canEnterDesktopMode(context)) {
+            return Optional.empty();
+        }
+        return Optional.of(new DesktopModeWindowDecorViewModel(context, shellExecutor, mainHandler,
                 mainChoreographer, bgExecutor, shellInit, shellCommandHandler, windowManager,
                 taskOrganizer, desktopRepository, displayController, shellController,
                 displayInsetsController, syncQueue, transitions, desktopTasksController,
@@ -938,7 +944,7 @@
                 assistContentRequester, multiInstanceHelper, desktopTasksLimiter,
                 appHandleEducationController, appToWebEducationController,
                 windowDecorCaptionHandleRepository, activityOrientationChangeHandler,
-                focusTransitionObserver, desktopModeEventLogger);
+                focusTransitionObserver, desktopModeEventLogger));
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
index db46f3c..ac07eaa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.desktopmode
 
 import android.hardware.input.KeyGestureEvent
-import android.view.KeyEvent
 
 import android.hardware.input.InputManager
 import android.hardware.input.InputManager.KeyGestureEventHandler
@@ -29,6 +28,9 @@
 import com.android.internal.protolog.ProtoLog
 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
 import android.content.Context
+import com.android.hardware.input.Flags.manageKeyGestures
+import com.android.window.flags.Flags.enableTaskResizingKeyboardShortcuts
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.transition.FocusTransitionObserver
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import java.util.Optional
@@ -38,7 +40,7 @@
  */
 class DesktopModeKeyGestureHandler(
     private val context: Context,
-    private val desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel,
+    private val desktopModeWindowDecorViewModel: Optional<DesktopModeWindowDecorViewModel>,
     private val desktopTasksController: Optional<DesktopTasksController>,
     inputManager: InputManager,
     private val shellTaskOrganizer: ShellTaskOrganizer,
@@ -50,23 +52,63 @@
     }
 
     override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?): Boolean {
-        if (!isKeyGestureSupported(event.keyGestureType) || !desktopTasksController.isPresent) {
+        if (!isKeyGestureSupported(event.keyGestureType) || !desktopTasksController.isPresent
+            || !desktopModeWindowDecorViewModel.isPresent) {
             return false
         }
         when (event.keyGestureType) {
             KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> {
-                if (event.keycodes.contains(KeyEvent.KEYCODE_D) &&
-                    event.hasModifiers(KeyEvent.META_CTRL_ON or KeyEvent.META_META_ON)
-                ) {
-                    logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled")
-                    getGloballyFocusedFreeformTask()?.let {
-                        desktopTasksController.get().moveToNextDisplay(
-                            it.taskId
-                        )
-                    }
-                    return true
+                logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopTasksController.get().moveToNextDisplay(
+                        it.taskId
+                    )
                 }
-                return false
+                return true
+            }
+            // TODO(b/375356876): Modify function to pass in keyboard shortcut as the input
+            // method for logging task resize
+            KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW -> {
+                logV("Key gesture SNAP_LEFT_FREEFORM_WINDOW is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopModeWindowDecorViewModel.get().onSnapResize(
+                        it.taskId,
+                        true,
+                        null
+                    )
+                }
+                return true
+            }
+            KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW -> {
+                logV("Key gesture SNAP_RIGHT_FREEFORM_WINDOW is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopModeWindowDecorViewModel.get().onSnapResize(
+                        it.taskId,
+                        false,
+                        null
+                    )
+                }
+                return true
+            }
+            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW -> {
+                logV("Key gesture TOGGLE_MAXIMIZE_FREEFORM_WINDOW is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopTasksController.get().toggleDesktopTaskSize(
+                        it,
+                        ResizeTrigger.MAXIMIZE_MENU,
+                        null,
+                    )
+                }
+                return true
+            }
+            KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW -> {
+                logV("Key gesture MINIMIZE_FREEFORM_WINDOW is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopTasksController.get().minimizeTask(
+                        it,
+                    )
+                }
+                return true
             }
             else -> return false
         }
@@ -75,6 +117,11 @@
     override fun isKeyGestureSupported(gestureType: Int): Boolean = when (gestureType) {
         KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY
             -> enableMoveToNextDisplayShortcut()
+        KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
+        KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
+        KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
+        KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW
+            -> enableTaskResizingKeyboardShortcuts() && manageKeyGestures()
         else -> false
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index cef5a30..8bad874 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -70,6 +70,7 @@
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.internal.protolog.ProtoLog
 import com.android.window.flags.Flags
+import com.android.wm.shell.R
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.common.DisplayController
@@ -777,6 +778,10 @@
         resizeTrigger: ResizeTrigger,
         motionEvent: MotionEvent?,
     ) {
+        desktopModeEventLogger.logTaskResizingStarted(
+            resizeTrigger, motionEvent, taskInfo, displayController
+        )
+
         val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
 
         val stableBounds = Rect().apply { displayLayout.getStableBounds(this) }
@@ -855,9 +860,6 @@
             return
         }
 
-        desktopModeEventLogger.logTaskResizingStarted(
-            ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent, taskInfo, displayController
-        )
         toggleDesktopTaskSize(taskInfo, ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent)
     }
 
@@ -945,13 +947,17 @@
      */
     fun snapToHalfScreen(
         taskInfo: RunningTaskInfo,
-        taskSurface: SurfaceControl,
+        taskSurface: SurfaceControl?,
         currentDragBounds: Rect,
         position: SnapPosition,
         resizeTrigger: ResizeTrigger,
         motionEvent: MotionEvent?,
         desktopWindowDecoration: DesktopModeWindowDecoration,
     ) {
+        desktopModeEventLogger.logTaskResizingStarted(
+            resizeTrigger, motionEvent, taskInfo, displayController
+        )
+
         if (DesktopModeFlags.ENABLE_TILE_RESIZING.isTrue()) {
             val isTiled = desktopTilingDecorViewModel.snapToHalfScreen(
                 taskInfo,
@@ -977,7 +983,7 @@
             // Handle the case where we attempt to snap resize when already snap resized: the task
             // position won't need to change but we want to animate the surface going back to the
             // snapped position from the "dragged-to-the-edge" position.
-            if (destinationBounds != currentDragBounds) {
+            if (destinationBounds != currentDragBounds && taskSurface != null) {
                 returnToDragStartAnimator.start(
                     taskInfo.taskId,
                     taskSurface,
@@ -994,8 +1000,40 @@
         toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentDragBounds)
     }
 
+    /**
+     * Handles snap resizing a [taskInfo] to [position] instantaneously, for example when the
+     * [resizeTrigger] is the snap resize menu using any [motionEvent] or a keyboard shortcut.
+     */
+    fun handleInstantSnapResizingTask(
+        taskInfo: RunningTaskInfo,
+        position: SnapPosition,
+        resizeTrigger: ResizeTrigger,
+        motionEvent: MotionEvent? = null,
+        desktopModeWindowDecoration: DesktopModeWindowDecoration,
+    ) {
+        if (!isSnapResizingAllowed(taskInfo)) {
+            Toast.makeText(
+                getContext(),
+                R.string.desktop_mode_non_resizable_snap_text,
+                Toast.LENGTH_SHORT
+            ).show()
+            return
+        }
+
+        snapToHalfScreen(
+            taskInfo,
+            null,
+            taskInfo.configuration.windowConfiguration.bounds,
+            position,
+            resizeTrigger,
+            motionEvent,
+            desktopModeWindowDecoration
+        )
+    }
+
+
     @VisibleForTesting
-    fun handleSnapResizingTask(
+    fun handleSnapResizingTaskOnDrag(
         taskInfo: RunningTaskInfo,
         position: SnapPosition,
         taskSurface: SurfaceControl,
@@ -1005,7 +1043,7 @@
         desktopModeWindowDecoration: DesktopModeWindowDecoration,
     ) {
         releaseVisualIndicator()
-        if (!taskInfo.isResizeable && DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) {
+        if (!isSnapResizingAllowed(taskInfo)) {
             interactionJankMonitor.begin(
                 taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_non_resizable"
             )
@@ -1030,9 +1068,6 @@
             } else {
                 ResizeTrigger.DRAG_RIGHT
             }
-            desktopModeEventLogger.logTaskResizingStarted(
-                resizeTrigger, motionEvent, taskInfo, displayController
-            )
             interactionJankMonitor.begin(
                 taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_resizable"
             )
@@ -1048,6 +1083,9 @@
         }
     }
 
+    private fun isSnapResizingAllowed(taskInfo: RunningTaskInfo) =
+        taskInfo.isResizeable || !DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()
+
     private fun getSnapBounds(taskInfo: RunningTaskInfo, position: SnapPosition): Rect {
         val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return Rect()
 
@@ -1966,7 +2004,7 @@
                 }
             }
             IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
-                handleSnapResizingTask(
+                handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.LEFT,
                     taskSurface,
@@ -1977,7 +2015,7 @@
                 )
             }
             IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
-                handleSnapResizingTask(
+                handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.RIGHT,
                     taskSurface,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index d71e61a..f89b0d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -78,7 +78,6 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.widget.Toast;
 import android.window.DesktopModeFlags;
 import android.window.TaskSnapshot;
 import android.window.WindowContainerToken;
@@ -572,9 +571,6 @@
         if (decoration == null) {
             return;
         }
-        mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent,
-                decoration.mTaskInfo,
-                mDisplayController, /* displayLayoutSize= */ null);
         mInteractionJankMonitor.begin(
                 decoration.mTaskSurface, mContext, mMainHandler,
                 Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source);
@@ -593,33 +589,20 @@
         decoration.closeMaximizeMenu();
     }
 
-    private void onSnapResize(int taskId, boolean left, MotionEvent motionEvent) {
+    public void onSnapResize(int taskId, boolean left, @Nullable MotionEvent motionEvent) {
         final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
         if (decoration == null) {
             return;
         }
 
-        if (!decoration.mTaskInfo.isResizeable
-                && DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) {
-            Toast.makeText(mContext,
-                    R.string.desktop_mode_non_resizable_snap_text, Toast.LENGTH_SHORT).show();
-        } else {
-            ResizeTrigger resizeTrigger =
-                    left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU;
-            mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent,
-                    decoration.mTaskInfo,
-                    mDisplayController, /* displayLayoutSize= */ null);
-            mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
-                    Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable");
-            mDesktopTasksController.snapToHalfScreen(
-                    decoration.mTaskInfo,
-                    decoration.mTaskSurface,
-                    decoration.mTaskInfo.configuration.windowConfiguration.getBounds(),
-                    left ? SnapPosition.LEFT : SnapPosition.RIGHT,
-                    resizeTrigger,
-                    motionEvent,
-                    mWindowDecorByTaskId.get(taskId));
-        }
+        mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
+                Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable");
+        mDesktopTasksController.handleInstantSnapResizingTask(
+                decoration.mTaskInfo,
+                left ? SnapPosition.LEFT : SnapPosition.RIGHT,
+                left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU,
+                motionEvent,
+                decoration);
 
         decoration.closeHandleMenu();
         decoration.closeMaximizeMenu();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 9cb9d25..723bbd3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -206,7 +206,7 @@
     private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository;
     private final DesktopRepository mDesktopRepository;
 
-    DesktopModeWindowDecoration(
+    public DesktopModeWindowDecoration(
             Context context,
             @NonNull Context userContext,
             DisplayController displayController,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
index d18bf1f..9e63a6d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
@@ -52,9 +52,11 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
 import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel
@@ -151,7 +153,7 @@
     fun keyGestureMoveToNextDisplay_shouldMoveToNextDisplay() {
         desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
             context,
-            desktopModeWindowDecorViewModel, Optional.of(desktopTasksController),
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
             inputManager, shellTaskOrganizer, focusTransitionObserver
         )
         // Set up two display ids
@@ -179,6 +181,118 @@
         verify(desktopTasksController).moveToNextDisplay(task.taskId)
     }
 
+    @Test
+    @EnableFlags(
+        FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+        FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+    )
+    fun keyGestureSnapLeft_shouldSnapResizeTaskToLeft() {
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+            inputManager, shellTaskOrganizer, focusTransitionObserver
+        )
+        val task = setUpFreeformTask()
+        task.isFocused = true
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+        whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+        val event = KeyGestureEvent.Builder()
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET))
+            .setModifierState(KeyEvent.META_META_ON)
+            .build()
+        val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+        assertThat(result).isTrue()
+        verify(desktopModeWindowDecorViewModel).onSnapResize(task.taskId, true, null)
+    }
+
+    @Test
+    @EnableFlags(
+        FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+        FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+    )
+    fun keyGestureSnapRight_shouldSnapResizeTaskToRight() {
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+            inputManager, shellTaskOrganizer, focusTransitionObserver
+        )
+        val task = setUpFreeformTask()
+        task.isFocused = true
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+        whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+        val event = KeyGestureEvent.Builder()
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET))
+            .setModifierState(KeyEvent.META_META_ON)
+            .build()
+        val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+        assertThat(result).isTrue()
+        verify(desktopModeWindowDecorViewModel).onSnapResize(task.taskId, false, null)
+    }
+
+    @Test
+    @EnableFlags(
+        FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+        FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+    )
+    fun keyGestureToggleFreeformWindowSize_shouldToggleTaskSize() {
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+            inputManager, shellTaskOrganizer, focusTransitionObserver
+        )
+        val task = setUpFreeformTask()
+        task.isFocused = true
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+        whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+        val event = KeyGestureEvent.Builder()
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_EQUALS))
+            .setModifierState(KeyEvent.META_META_ON)
+            .build()
+        val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+        assertThat(result).isTrue()
+        verify(desktopTasksController).toggleDesktopTaskSize(
+            task,
+            ResizeTrigger.MAXIMIZE_MENU,
+            null
+        )
+    }
+
+    @Test
+    @EnableFlags(
+        FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+        FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+    )
+    fun keyGestureMinimizeFreeformWindow_shouldMinimizeTask() {
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+            inputManager, shellTaskOrganizer, focusTransitionObserver
+        )
+        val task = setUpFreeformTask()
+        task.isFocused = true
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+        whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+        val event = KeyGestureEvent.Builder()
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_MINUS))
+            .setModifierState(KeyEvent.META_META_ON)
+            .build()
+        val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+        assertThat(result).isTrue()
+        verify(desktopTasksController).minimizeTask(task)
+    }
+
     private fun setUpFreeformTask(
         displayId: Int = DEFAULT_DISPLAY,
         bounds: Rect? = null,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 1d7136b..93999476 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -36,6 +36,7 @@
 import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
 import android.content.res.Configuration.ORIENTATION_LANDSCAPE
 import android.content.res.Configuration.ORIENTATION_PORTRAIT
+import android.content.res.Resources
 import android.graphics.Point
 import android.graphics.PointF
 import android.graphics.Rect
@@ -59,6 +60,7 @@
 import android.view.WindowManager.TRANSIT_OPEN
 import android.view.WindowManager.TRANSIT_TO_BACK
 import android.view.WindowManager.TRANSIT_TO_FRONT
+import android.widget.Toast
 import android.window.DisplayAreaInfo
 import android.window.IWindowContainerToken
 import android.window.RemoteTransition
@@ -214,12 +216,13 @@
   @Mock lateinit var persistentRepository: DesktopPersistentRepository
   @Mock lateinit var motionEvent: MotionEvent
   @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
-
+  @Mock private lateinit var mockToast: Toast
   private lateinit var mockitoSession: StaticMockitoSession
   @Mock
   private lateinit var desktopTilingDecorViewModel: DesktopTilingDecorViewModel
   @Mock
   private lateinit var desktopWindowDecoration: DesktopModeWindowDecoration
+  @Mock private lateinit var resources: Resources
   private lateinit var controller: DesktopTasksController
   private lateinit var shellInit: ShellInit
   private lateinit var taskRepository: DesktopRepository
@@ -248,6 +251,7 @@
         mockitoSession()
             .strictness(Strictness.LENIENT)
             .spyStatic(DesktopModeStatus::class.java)
+            .spyStatic(Toast::class.java)
             .startMocking()
     doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
 
@@ -275,6 +279,7 @@
     whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn(
       Desktop.getDefaultInstance()
     )
+    doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) }
 
     val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
     tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
@@ -3403,7 +3408,7 @@
 
   @Test
   @DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING, Flags.FLAG_ENABLE_TILE_RESIZING)
-  fun handleSnapResizingTask_nonResizable_snapsToHalfScreen() {
+  fun handleSnapResizingTaskOnDrag_nonResizable_snapsToHalfScreen() {
     val task = setUpFreeformTask(DEFAULT_DISPLAY, Rect(0, 0, 200, 100)).apply {
       isResizeable = false
     }
@@ -3412,7 +3417,7 @@
     val expectedBounds =
       Rect(STABLE_BOUNDS.left, STABLE_BOUNDS.top, STABLE_BOUNDS.right / 2, STABLE_BOUNDS.bottom)
 
-    controller.handleSnapResizingTask(
+    controller.handleSnapResizingTaskOnDrag(
 
       task, SnapPosition.LEFT, mockSurface, currentDragBounds, preDragBounds, motionEvent,
       desktopWindowDecoration
@@ -3431,14 +3436,14 @@
 
   @Test
   @EnableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
-  fun handleSnapResizingTask_nonResizable_startsRepositionAnimation() {
+  fun handleSnapResizingTaskOnDrag_nonResizable_startsRepositionAnimation() {
     val task = setUpFreeformTask(DEFAULT_DISPLAY, Rect(0, 0, 200, 100)).apply {
       isResizeable = false
     }
     val preDragBounds = Rect(100, 100, 400, 500)
     val currentDragBounds = Rect(0, 100, 300, 500)
 
-    controller.handleSnapResizingTask(
+    controller.handleSnapResizingTaskOnDrag(
       task, SnapPosition.LEFT, mockSurface, currentDragBounds, preDragBounds, motionEvent,
       desktopWindowDecoration)
     verify(mReturnToDragStartAnimator).start(
@@ -3458,6 +3463,59 @@
   }
 
   @Test
+  @EnableFlags(
+    Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING
+  )
+  fun handleInstantSnapResizingTask_nonResizable_animatorNotStartedAndShowsToast() {
+    val taskBounds = Rect(0, 0, 200, 100)
+    val task = setUpFreeformTask(DEFAULT_DISPLAY, taskBounds).apply {
+      isResizeable = false
+    }
+
+    controller.handleInstantSnapResizingTask(
+      task, SnapPosition.LEFT, ResizeTrigger.SNAP_LEFT_MENU, motionEvent, desktopWindowDecoration)
+
+    // Assert that task is NOT updated via WCT
+    verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any())
+    verify(mockToast).show()
+  }
+
+  @Test
+  @EnableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
+  @DisableFlags(Flags.FLAG_ENABLE_TILE_RESIZING)
+  fun handleInstantSnapResizingTask_resizable_snapsToHalfScreenAndNotShowToast() {
+    val taskBounds = Rect(0, 0, 200, 100)
+    val task = setUpFreeformTask(DEFAULT_DISPLAY, taskBounds).apply {
+      isResizeable = true
+    }
+    val expectedBounds = Rect(
+      STABLE_BOUNDS.left, STABLE_BOUNDS.top, STABLE_BOUNDS.right / 2, STABLE_BOUNDS.bottom
+    )
+
+    controller.handleInstantSnapResizingTask(
+      task, SnapPosition.LEFT, ResizeTrigger.SNAP_LEFT_MENU, motionEvent, desktopWindowDecoration)
+
+    // Assert bounds set to half of the stable bounds
+    val wct = getLatestToggleResizeDesktopTaskWct(taskBounds)
+    assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
+    verify(mockToast, never()).show()
+    verify(desktopModeEventLogger, times(1)).logTaskResizingStarted(
+      ResizeTrigger.SNAP_LEFT_MENU,
+      motionEvent,
+      task,
+      displayController
+    )
+    verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
+      ResizeTrigger.SNAP_LEFT_MENU,
+      motionEvent,
+      task,
+      expectedBounds.height(),
+      expectedBounds.width(),
+      displayController
+    )
+  }
+
+  @Test
   fun toggleBounds_togglesToCalculatedBoundsForNonResizable() {
     val bounds = Rect(0, 0, 200, 100)
     val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds).apply {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index be664f8..ef9b30c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -63,7 +63,6 @@
 import android.view.View
 import android.view.ViewRootImpl
 import android.view.WindowInsets.Type.statusBars
-import android.widget.Toast
 import android.window.WindowContainerTransaction
 import android.window.WindowContainerTransaction.HierarchyOp
 import androidx.test.filters.SmallTest
@@ -186,7 +185,6 @@
     @Mock private lateinit var mockGenericLinksParser: AppToWebGenericLinksParser
     @Mock private lateinit var mockUserHandle: UserHandle
     @Mock private lateinit var mockAssistContentRequester: AssistContentRequester
-    @Mock private lateinit var mockToast: Toast
     private val bgExecutor = TestShellExecutor()
     @Mock private lateinit var mockMultiInstanceHelper: MultiInstanceHelper
     @Mock private lateinit var mockTasksLimiter: DesktopTasksLimiter
@@ -226,7 +224,6 @@
                 .strictness(Strictness.LENIENT)
                 .spyStatic(DesktopModeStatus::class.java)
                 .spyStatic(DragPositioningCallbackUtility::class.java)
-                .spyStatic(Toast::class.java)
                 .startMocking()
         doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(Mockito.any()) }
 
@@ -290,8 +287,6 @@
         )
             .thenReturn(mockTaskPositioner)
 
-        doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) }
-
         // InputChannel cannot be mocked because it passes to InputEventReceiver.
         val inputChannels = InputChannel.openInputChannelPair(TAG)
         inputChannels.first().dispose()
@@ -640,7 +635,6 @@
 
     @Test
     fun testOnDecorSnappedLeft_snapResizes() {
-        val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
         val onLeftSnapClickListenerCaptor = forClass(Function0::class.java)
                 as ArgumentCaptor<Function0<Unit>>
         val decor = createOpenTaskDecoration(
@@ -648,19 +642,15 @@
             onLeftSnapClickListenerCaptor = onLeftSnapClickListenerCaptor
         )
 
-        val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
         onLeftSnapClickListenerCaptor.value.invoke()
 
-        verify(mockDesktopTasksController).snapToHalfScreen(
+        verify(mockDesktopTasksController).handleInstantSnapResizingTask(
             eq(decor.mTaskInfo),
-            taskSurfaceCaptor.capture(),
-            eq(currentBounds),
             eq(SnapPosition.LEFT),
             eq(ResizeTrigger.SNAP_LEFT_MENU),
             eq(null),
             eq(decor)
         )
-        assertEquals(taskSurfaceCaptor.firstValue, decor.mTaskSurface)
     }
 
     @Test
@@ -681,7 +671,6 @@
     @Test
     @DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
     fun testOnSnapResizeLeft_nonResizable_decorSnappedLeft() {
-        val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
         val onLeftSnapClickListenerCaptor = forClass(Function0::class.java)
                 as ArgumentCaptor<Function0<Unit>>
         val decor = createOpenTaskDecoration(
@@ -689,19 +678,15 @@
             onLeftSnapClickListenerCaptor = onLeftSnapClickListenerCaptor
         ).also { it.mTaskInfo.isResizeable = false }
 
-        val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
         onLeftSnapClickListenerCaptor.value.invoke()
 
-        verify(mockDesktopTasksController).snapToHalfScreen(
+        verify(mockDesktopTasksController).handleInstantSnapResizingTask(
             eq(decor.mTaskInfo),
-            taskSurfaceCaptor.capture(),
-            eq(currentBounds),
             eq(SnapPosition.LEFT),
             eq(ResizeTrigger.SNAP_LEFT_MENU),
             eq(null),
             eq(decor),
         )
-        assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue)
     }
 
     @Test
@@ -723,12 +708,10 @@
                 eq(null),
                 eq(decor),
             )
-        verify(mockToast).show()
     }
 
     @Test
     fun testOnDecorSnappedRight_snapResizes() {
-        val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
         val onRightSnapClickListenerCaptor = forClass(Function0::class.java)
                 as ArgumentCaptor<Function0<Unit>>
         val decor = createOpenTaskDecoration(
@@ -736,19 +719,15 @@
             onRightSnapClickListenerCaptor = onRightSnapClickListenerCaptor
         )
 
-        val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
         onRightSnapClickListenerCaptor.value.invoke()
 
-        verify(mockDesktopTasksController).snapToHalfScreen(
+        verify(mockDesktopTasksController).handleInstantSnapResizingTask(
             eq(decor.mTaskInfo),
-            taskSurfaceCaptor.capture(),
-            eq(currentBounds),
             eq(SnapPosition.RIGHT),
             eq(ResizeTrigger.SNAP_RIGHT_MENU),
             eq(null),
             eq(decor),
         )
-        assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue)
     }
 
     @Test
@@ -769,7 +748,6 @@
     @Test
     @DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
     fun testOnSnapResizeRight_nonResizable_decorSnappedRight() {
-        val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
         val onRightSnapClickListenerCaptor = forClass(Function0::class.java)
                 as ArgumentCaptor<Function0<Unit>>
         val decor = createOpenTaskDecoration(
@@ -777,19 +755,15 @@
             onRightSnapClickListenerCaptor = onRightSnapClickListenerCaptor
         ).also { it.mTaskInfo.isResizeable = false }
 
-        val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
         onRightSnapClickListenerCaptor.value.invoke()
 
-        verify(mockDesktopTasksController).snapToHalfScreen(
+        verify(mockDesktopTasksController).handleInstantSnapResizingTask(
             eq(decor.mTaskInfo),
-            taskSurfaceCaptor.capture(),
-            eq(currentBounds),
             eq(SnapPosition.RIGHT),
             eq(ResizeTrigger.SNAP_RIGHT_MENU),
             eq(null),
             eq(decor),
         )
-        assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue)
     }
 
     @Test
@@ -811,7 +785,6 @@
                 eq(null),
                 eq(decor),
         )
-        verify(mockToast).show()
     }
 
     @Test
diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java
index 6f35402..73d5630 100644
--- a/services/core/java/com/android/server/input/InputGestureManager.java
+++ b/services/core/java/com/android/server/input/InputGestureManager.java
@@ -228,6 +228,28 @@
                     KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                     KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK));
         }
+        if (enableTaskResizingKeyboardShortcuts()) {
+            systemShortcuts.add(createKeyGesture(
+                    KeyEvent.KEYCODE_LEFT_BRACKET,
+                    KeyEvent.META_META_ON,
+                    KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW
+            ));
+            systemShortcuts.add(createKeyGesture(
+                    KeyEvent.KEYCODE_RIGHT_BRACKET,
+                    KeyEvent.META_META_ON,
+                    KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW
+            ));
+            systemShortcuts.add(createKeyGesture(
+                    KeyEvent.KEYCODE_EQUALS,
+                    KeyEvent.META_META_ON,
+                    KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW
+            ));
+            systemShortcuts.add(createKeyGesture(
+                    KeyEvent.KEYCODE_MINUS,
+                    KeyEvent.META_META_ON,
+                    KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW
+            ));
+        }
         if (keyboardA11yShortcutControl()) {
             if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()) {
                 systemShortcuts.add(createKeyGesture(
@@ -257,28 +279,6 @@
                         KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS
                 ));
             }
-            if (enableTaskResizingKeyboardShortcuts()) {
-                systemShortcuts.add(createKeyGesture(
-                        KeyEvent.KEYCODE_LEFT_BRACKET,
-                        KeyEvent.META_ALT_ON,
-                        KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW
-                ));
-                systemShortcuts.add(createKeyGesture(
-                        KeyEvent.KEYCODE_RIGHT_BRACKET,
-                        KeyEvent.META_ALT_ON,
-                        KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW
-                ));
-                systemShortcuts.add(createKeyGesture(
-                        KeyEvent.KEYCODE_EQUALS,
-                        KeyEvent.META_ALT_ON,
-                        KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW
-                ));
-                systemShortcuts.add(createKeyGesture(
-                        KeyEvent.KEYCODE_MINUS,
-                        KeyEvent.META_ALT_ON,
-                        KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE
-                ));
-            }
         }
         synchronized (mGestureLock) {
             for (InputGestureData systemShortcut : systemShortcuts) {
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index d1f8668..34350ab 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -676,47 +676,47 @@
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
-                "ALT + [ -> Resizes a task to fit the left half of the screen",
+                "META + [ -> Resizes a task to fit the left half of the screen",
                 intArrayOf(
-                    KeyEvent.KEYCODE_ALT_LEFT,
+                    KeyEvent.KEYCODE_META_LEFT,
                     KeyEvent.KEYCODE_LEFT_BRACKET
                 ),
                 KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
                 intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET),
-                KeyEvent.META_ALT_ON,
+                KeyEvent.META_META_ON,
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
-                "ALT + ] -> Resizes a task to fit the right half of the screen",
+                "META + ] -> Resizes a task to fit the right half of the screen",
                 intArrayOf(
-                    KeyEvent.KEYCODE_ALT_LEFT,
+                    KeyEvent.KEYCODE_META_LEFT,
                     KeyEvent.KEYCODE_RIGHT_BRACKET
                 ),
                 KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
                 intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET),
-                KeyEvent.META_ALT_ON,
+                KeyEvent.META_META_ON,
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
-                "ALT + '=' -> Maximizes a task to fit the screen",
+                "META + '=' -> Toggles maximization of a task to maximized and restore its bounds",
                 intArrayOf(
-                    KeyEvent.KEYCODE_ALT_LEFT,
+                    KeyEvent.KEYCODE_META_LEFT,
                     KeyEvent.KEYCODE_EQUALS
                 ),
-                KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
+                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
                 intArrayOf(KeyEvent.KEYCODE_EQUALS),
-                KeyEvent.META_ALT_ON,
+                KeyEvent.META_META_ON,
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
-                "ALT + '-' -> Restores a task size to its previous bounds",
+                "META + '-' -> Minimizes a freeform task",
                 intArrayOf(
-                    KeyEvent.KEYCODE_ALT_LEFT,
+                    KeyEvent.KEYCODE_META_LEFT,
                     KeyEvent.KEYCODE_MINUS
                 ),
-                KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
+                KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW,
                 intArrayOf(KeyEvent.KEYCODE_MINUS),
-                KeyEvent.META_ALT_ON,
+                KeyEvent.META_META_ON,
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(