Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt +16 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ class DesktopModeKeyGestureHandler( KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW, KeyGestureEvent.KEY_GESTURE_TYPE_SWITCH_TO_PREVIOUS_DESK, KeyGestureEvent.KEY_GESTURE_TYPE_SWITCH_TO_NEXT_DESK, KeyGestureEvent.KEY_GESTURE_TYPE_QUIT_FOCUSED_DESKTOP_TASK, ) inputManager.registerKeyGestureEventHandler(supportedGestures, this) } Loading Loading @@ -166,6 +167,21 @@ class DesktopModeKeyGestureHandler( } } } KeyGestureEvent.KEY_GESTURE_TYPE_QUIT_FOCUSED_DESKTOP_TASK -> { logV("Key gesture KEY_GESTURE_TYPE_QUIT_FOCUSED_DESKTOP_TASK is handled") val focusedTask = getGloballyFocusedDesktopTask() if (focusedTask == null) { logV( "Globally focused desktop task is not found to close. focusedDisplay=%d", focusTransitionObserver.globallyFocusedDisplayId, ) return } logV("Found focused desktop task %d to close", focusedTask.taskId) mainExecutor.execute { desktopModeWindowDecorViewModel.get().closeTask(focusedTask) } } } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +62 −42 Original line number Diff line number Diff line Loading @@ -1133,6 +1133,58 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mCaptionTouchStatusListener = l; } /** * Closes a task. * This method closes a task as if the close button on the window decor is clicked. * It does nothing if the task does not have a window decor, thus cannot be closed through the * UI. * Must call the method on the shell main executor. * @param task Task to be closed. */ public void closeTask(RunningTaskInfo task) { final WindowDecorationWrapper decoration = mWindowDecorationFinder.apply(task.taskId); if (decoration == null) { ProtoLog.e(WM_SHELL_DESKTOP_MODE, "%s: handled close key gesture but decoration is null, ignoring", TAG); return; } if (mTaskOperations == null) { ProtoLog.e(WM_SHELL_DESKTOP_MODE, "%s: handled close key gesture but mTaskOperations is null, ignoring", TAG); return; } ProtoLog.e(WM_SHELL_DESKTOP_MODE, "%s: close task %d vis key gesture", TAG, task.taskId); onCloseTask(task.taskId, decoration, task.token); } private void onCloseTask(int taskId, @NotNull WindowDecorationWrapper decoration, @NotNull WindowContainerToken token) { if (isTaskInSplitScreen(taskId)) { mSplitScreenController.moveTaskToFullscreen(getOtherSplitTask(taskId).taskId, SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { if (DesktopExperienceFlags .ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS.isTrue()) { final int nextFocusedTaskId = mDesktopTasksController.getNextFocusedTask( decoration.getTaskInfo()); final WindowDecorationWrapper nextFocusedWindow = mWindowDecorationFinder.apply(nextFocusedTaskId); if (nextFocusedWindow != null) { nextFocusedWindow.a11yAnnounceNewFocusedWindow(); } } final WindowContainerTransaction wct = new WindowContainerTransaction(); final Function1<IBinder, Unit> runOnTransitionStart = mDesktopTasksController.onDesktopWindowClose(wct, decoration.getTaskInfo().displayId, decoration.getTaskInfo()); final IBinder transition = mTaskOperations.closeTask(token, wct); if (transition != null) { runOnTransitionStart.invoke(transition); } } } /** Listener for caption touch events. */ public interface CaptionTouchStatusListener { /** Called when the caption is pressed. */ Loading Loading @@ -1171,7 +1223,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, private final WindowContainerToken mTaskToken; private final @NonNull DragPositioningCallback mDragPositioningCallback; private final @NonNull Function<Integer, WindowDecorationWrapper> mWindowDecorationFinder; private final @Nullable SplitScreenController mSplitScreenController; private final @NonNull DesktopTasksController mDesktopTasksController; private final @NonNull TaskOperations mTaskOperations; private final @NonNull DesktopModeUiEventLogger mDesktopModeUiEventLogger; Loading Loading @@ -1215,7 +1266,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, @NonNull RunningTaskInfo taskInfo, @NonNull DragPositioningCallback dragPositioningCallback, @NonNull Function<Integer, WindowDecorationWrapper> windowDecorationFinder, @Nullable SplitScreenController splitScreenController, @NonNull DesktopTasksController desktopTasksController, @NonNull TaskOperations taskOperations, @NonNull DesktopModeUiEventLogger desktopModeUiEventLogger, Loading @@ -1233,7 +1283,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mContext = context; mDragPositioningCallback = dragPositioningCallback; mWindowDecorationFinder = windowDecorationFinder; mSplitScreenController = splitScreenController; mDesktopTasksController = desktopTasksController; mTaskOperations = taskOperations; mDesktopModeUiEventLogger = desktopModeUiEventLogger; Loading Loading @@ -1291,29 +1340,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, } final int id = v.getId(); if (id == R.id.close_window) { if (isTaskInSplitScreen(mTaskId)) { mSplitScreenController.moveTaskToFullscreen(getOtherSplitTask(mTaskId).taskId, SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { if (DesktopExperienceFlags .ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS.isTrue()) { final int nextFocusedTaskId = mDesktopTasksController.getNextFocusedTask( decoration.getTaskInfo()); WindowDecorationWrapper nextFocusedWindow = mWindowDecorationFinder.apply(nextFocusedTaskId); if (nextFocusedWindow != null) { nextFocusedWindow.a11yAnnounceNewFocusedWindow(); } } WindowContainerTransaction wct = new WindowContainerTransaction(); final Function1<IBinder, Unit> runOnTransitionStart = mDesktopTasksController.onDesktopWindowClose(wct, decoration.getTaskInfo().displayId, decoration.getTaskInfo()); final IBinder transition = mTaskOperations.closeTask(mTaskToken, wct); if (transition != null) { runOnTransitionStart.invoke(transition); } } mWindowDecorationActions.onClose(mTaskId, decoration, mTaskToken); } else if (id == R.id.back_button) { mTaskOperations.injectBackKey(decoration.getTaskInfo().displayId); } else if (id == R.id.caption_handle || id == R.id.open_menu_button) { Loading Loading @@ -1352,7 +1379,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, .ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS.isTrue()) { final int nextFocusedTaskId = mDesktopTasksController .getNextFocusedTask(decoration.getTaskInfo()); WindowDecorationWrapper nextFocusedWindow = final WindowDecorationWrapper nextFocusedWindow = mWindowDecorationFinder.apply(nextFocusedTaskId); if (nextFocusedWindow != null) { nextFocusedWindow.a11yAnnounceNewFocusedWindow(); Loading Loading @@ -1887,19 +1914,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, return true; } private boolean isTaskInSplitScreen(int taskId) { return mSplitScreenController != null && mSplitScreenController.isTaskInSplitScreen(taskId); } @Nullable private RunningTaskInfo getOtherSplitTask(int taskId) { @SplitPosition int remainingTaskPosition = mSplitScreenController .getSplitPosition(taskId) == SPLIT_POSITION_BOTTOM_OR_RIGHT ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT; return mSplitScreenController.getTaskInfo(remainingTaskPosition); } private InputMethod getInputMethod(MotionEvent ev) { return DesktopModeEventLogger.getInputMethodFromMotionEvent(ev); } Loading Loading @@ -2390,8 +2404,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, final DesktopModeTouchEventListener touchEventListener = new DesktopModeTouchEventListener(mContext, taskInfo, taskPositioner, mWindowDecorationFinder, mSplitScreenController, mDesktopTasksController, mTaskOperations, mDesktopModeUiEventLogger, mWindowDecorationActions, mWindowDecorationFinder, mDesktopTasksController, mTaskOperations, mDesktopModeUiEventLogger, mWindowDecorationActions, mDesktopUserRepositories, mGestureExclusionTracker, mInputManager, mFocusTransitionObserver, mShellDesktopState, mMultiDisplayDragMoveIndicatorController, mTransactionFactory, Loading Loading @@ -2645,6 +2659,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mDesktopTasksController.minimizeTask(taskInfo, MinimizeReason.MINIMIZE_BUTTON); } @Override public void onClose(int taskId, @NotNull WindowDecorationWrapper decoration, @NotNull WindowContainerToken token) { mViewModel.onCloseTask(taskId, decoration, token); } @Override public void onImmersiveOrRestore(@NonNull ActivityManager.RunningTaskInfo taskInfo) { mViewModel.onEnterOrExitImmersive(taskInfo); Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorationActions.kt +4 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.windowdecor import android.app.ActivityManager.RunningTaskInfo import android.content.Intent import android.window.WindowContainerToken import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction.AmbiguousSource import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource Loading @@ -33,6 +34,9 @@ interface WindowDecorationActions { /** Minimizes the task. */ fun onMinimize(taskInfo: RunningTaskInfo) /** Close the task */ fun onClose(taskId: Int, decoration: WindowDecorationWrapper, token: WindowContainerToken) /** * Moves task to immersive mode or exits immersive and restores task to previous size if task is * already in immersive. Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt +19 −0 Original line number Diff line number Diff line Loading @@ -366,6 +366,25 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() { verify(desktopTasksController).minimizeTask(task, MinimizeReason.KEY_GESTURE) } @Test fun keyGestureQuitFocusedDesktopTask_shouldQuitTask() { val task = setUpDesktopTask() 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_QUIT_FOCUSED_DESKTOP_TASK) .setKeycodes(intArrayOf(KeyEvent.KEYCODE_Q)) .setModifierState(KeyEvent.META_META_ON) .build() keyGestureEventHandler.handleKeyGestureEvent(event, null) testExecutor.flushAll() verify(desktopModeWindowDecorViewModel).closeTask(task) } @Test fun keyGestureSwitchToPreviousDesk_activatesDesk() { val displayId = 2 Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +30 −0 Original line number Diff line number Diff line Loading @@ -319,6 +319,36 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest assertThat(hierarchyOp.container).isEqualTo(decor.taskInfo.token.asBinder()) } @Test fun testCloseTask_notInSplitScreen_closesTask() { desktopModeWindowDecorViewModel.setFreeformTaskTransitionStarter( mockFreeformTaskTransitionStarter ) val decor = createOpenTaskDecoration(windowingMode = WINDOWING_MODE_FREEFORM) val taskInfo = decor.taskInfo whenever(mockSplitScreenController.isTaskInSplitScreen(eq(taskInfo.taskId))) .thenReturn(false) whenever(mockDesktopTasksController.getNextFocusedTask(eq(taskInfo))).thenReturn(-1) whenever(mockDesktopTasksController.onDesktopWindowClose(any(), any(), any())).thenReturn { binder: IBinder -> } desktopModeWindowDecorViewModel.closeTask(decor.taskInfo) verify(mockFreeformTaskTransitionStarter).startRemoveTransition(any()) } @Test fun testCloseTask_noDecoration_doesNothing() { val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM) // No decoration is created for this task. desktopModeWindowDecorViewModel.closeTask(task) verify(mockSplitScreenController, never()).isTaskInSplitScreen(any()) verify(mockFreeformTaskTransitionStarter, never()).startRemoveTransition(any()) } @Test @EnableFlags(Flags.FLAG_ENABLE_MINIMIZE_BUTTON) @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS) Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt +16 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ class DesktopModeKeyGestureHandler( KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW, KeyGestureEvent.KEY_GESTURE_TYPE_SWITCH_TO_PREVIOUS_DESK, KeyGestureEvent.KEY_GESTURE_TYPE_SWITCH_TO_NEXT_DESK, KeyGestureEvent.KEY_GESTURE_TYPE_QUIT_FOCUSED_DESKTOP_TASK, ) inputManager.registerKeyGestureEventHandler(supportedGestures, this) } Loading Loading @@ -166,6 +167,21 @@ class DesktopModeKeyGestureHandler( } } } KeyGestureEvent.KEY_GESTURE_TYPE_QUIT_FOCUSED_DESKTOP_TASK -> { logV("Key gesture KEY_GESTURE_TYPE_QUIT_FOCUSED_DESKTOP_TASK is handled") val focusedTask = getGloballyFocusedDesktopTask() if (focusedTask == null) { logV( "Globally focused desktop task is not found to close. focusedDisplay=%d", focusTransitionObserver.globallyFocusedDisplayId, ) return } logV("Found focused desktop task %d to close", focusedTask.taskId) mainExecutor.execute { desktopModeWindowDecorViewModel.get().closeTask(focusedTask) } } } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +62 −42 Original line number Diff line number Diff line Loading @@ -1133,6 +1133,58 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mCaptionTouchStatusListener = l; } /** * Closes a task. * This method closes a task as if the close button on the window decor is clicked. * It does nothing if the task does not have a window decor, thus cannot be closed through the * UI. * Must call the method on the shell main executor. * @param task Task to be closed. */ public void closeTask(RunningTaskInfo task) { final WindowDecorationWrapper decoration = mWindowDecorationFinder.apply(task.taskId); if (decoration == null) { ProtoLog.e(WM_SHELL_DESKTOP_MODE, "%s: handled close key gesture but decoration is null, ignoring", TAG); return; } if (mTaskOperations == null) { ProtoLog.e(WM_SHELL_DESKTOP_MODE, "%s: handled close key gesture but mTaskOperations is null, ignoring", TAG); return; } ProtoLog.e(WM_SHELL_DESKTOP_MODE, "%s: close task %d vis key gesture", TAG, task.taskId); onCloseTask(task.taskId, decoration, task.token); } private void onCloseTask(int taskId, @NotNull WindowDecorationWrapper decoration, @NotNull WindowContainerToken token) { if (isTaskInSplitScreen(taskId)) { mSplitScreenController.moveTaskToFullscreen(getOtherSplitTask(taskId).taskId, SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { if (DesktopExperienceFlags .ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS.isTrue()) { final int nextFocusedTaskId = mDesktopTasksController.getNextFocusedTask( decoration.getTaskInfo()); final WindowDecorationWrapper nextFocusedWindow = mWindowDecorationFinder.apply(nextFocusedTaskId); if (nextFocusedWindow != null) { nextFocusedWindow.a11yAnnounceNewFocusedWindow(); } } final WindowContainerTransaction wct = new WindowContainerTransaction(); final Function1<IBinder, Unit> runOnTransitionStart = mDesktopTasksController.onDesktopWindowClose(wct, decoration.getTaskInfo().displayId, decoration.getTaskInfo()); final IBinder transition = mTaskOperations.closeTask(token, wct); if (transition != null) { runOnTransitionStart.invoke(transition); } } } /** Listener for caption touch events. */ public interface CaptionTouchStatusListener { /** Called when the caption is pressed. */ Loading Loading @@ -1171,7 +1223,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, private final WindowContainerToken mTaskToken; private final @NonNull DragPositioningCallback mDragPositioningCallback; private final @NonNull Function<Integer, WindowDecorationWrapper> mWindowDecorationFinder; private final @Nullable SplitScreenController mSplitScreenController; private final @NonNull DesktopTasksController mDesktopTasksController; private final @NonNull TaskOperations mTaskOperations; private final @NonNull DesktopModeUiEventLogger mDesktopModeUiEventLogger; Loading Loading @@ -1215,7 +1266,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, @NonNull RunningTaskInfo taskInfo, @NonNull DragPositioningCallback dragPositioningCallback, @NonNull Function<Integer, WindowDecorationWrapper> windowDecorationFinder, @Nullable SplitScreenController splitScreenController, @NonNull DesktopTasksController desktopTasksController, @NonNull TaskOperations taskOperations, @NonNull DesktopModeUiEventLogger desktopModeUiEventLogger, Loading @@ -1233,7 +1283,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mContext = context; mDragPositioningCallback = dragPositioningCallback; mWindowDecorationFinder = windowDecorationFinder; mSplitScreenController = splitScreenController; mDesktopTasksController = desktopTasksController; mTaskOperations = taskOperations; mDesktopModeUiEventLogger = desktopModeUiEventLogger; Loading Loading @@ -1291,29 +1340,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, } final int id = v.getId(); if (id == R.id.close_window) { if (isTaskInSplitScreen(mTaskId)) { mSplitScreenController.moveTaskToFullscreen(getOtherSplitTask(mTaskId).taskId, SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { if (DesktopExperienceFlags .ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS.isTrue()) { final int nextFocusedTaskId = mDesktopTasksController.getNextFocusedTask( decoration.getTaskInfo()); WindowDecorationWrapper nextFocusedWindow = mWindowDecorationFinder.apply(nextFocusedTaskId); if (nextFocusedWindow != null) { nextFocusedWindow.a11yAnnounceNewFocusedWindow(); } } WindowContainerTransaction wct = new WindowContainerTransaction(); final Function1<IBinder, Unit> runOnTransitionStart = mDesktopTasksController.onDesktopWindowClose(wct, decoration.getTaskInfo().displayId, decoration.getTaskInfo()); final IBinder transition = mTaskOperations.closeTask(mTaskToken, wct); if (transition != null) { runOnTransitionStart.invoke(transition); } } mWindowDecorationActions.onClose(mTaskId, decoration, mTaskToken); } else if (id == R.id.back_button) { mTaskOperations.injectBackKey(decoration.getTaskInfo().displayId); } else if (id == R.id.caption_handle || id == R.id.open_menu_button) { Loading Loading @@ -1352,7 +1379,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, .ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS.isTrue()) { final int nextFocusedTaskId = mDesktopTasksController .getNextFocusedTask(decoration.getTaskInfo()); WindowDecorationWrapper nextFocusedWindow = final WindowDecorationWrapper nextFocusedWindow = mWindowDecorationFinder.apply(nextFocusedTaskId); if (nextFocusedWindow != null) { nextFocusedWindow.a11yAnnounceNewFocusedWindow(); Loading Loading @@ -1887,19 +1914,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, return true; } private boolean isTaskInSplitScreen(int taskId) { return mSplitScreenController != null && mSplitScreenController.isTaskInSplitScreen(taskId); } @Nullable private RunningTaskInfo getOtherSplitTask(int taskId) { @SplitPosition int remainingTaskPosition = mSplitScreenController .getSplitPosition(taskId) == SPLIT_POSITION_BOTTOM_OR_RIGHT ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT; return mSplitScreenController.getTaskInfo(remainingTaskPosition); } private InputMethod getInputMethod(MotionEvent ev) { return DesktopModeEventLogger.getInputMethodFromMotionEvent(ev); } Loading Loading @@ -2390,8 +2404,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, final DesktopModeTouchEventListener touchEventListener = new DesktopModeTouchEventListener(mContext, taskInfo, taskPositioner, mWindowDecorationFinder, mSplitScreenController, mDesktopTasksController, mTaskOperations, mDesktopModeUiEventLogger, mWindowDecorationActions, mWindowDecorationFinder, mDesktopTasksController, mTaskOperations, mDesktopModeUiEventLogger, mWindowDecorationActions, mDesktopUserRepositories, mGestureExclusionTracker, mInputManager, mFocusTransitionObserver, mShellDesktopState, mMultiDisplayDragMoveIndicatorController, mTransactionFactory, Loading Loading @@ -2645,6 +2659,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mDesktopTasksController.minimizeTask(taskInfo, MinimizeReason.MINIMIZE_BUTTON); } @Override public void onClose(int taskId, @NotNull WindowDecorationWrapper decoration, @NotNull WindowContainerToken token) { mViewModel.onCloseTask(taskId, decoration, token); } @Override public void onImmersiveOrRestore(@NonNull ActivityManager.RunningTaskInfo taskInfo) { mViewModel.onEnterOrExitImmersive(taskInfo); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorationActions.kt +4 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.windowdecor import android.app.ActivityManager.RunningTaskInfo import android.content.Intent import android.window.WindowContainerToken import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction.AmbiguousSource import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource Loading @@ -33,6 +34,9 @@ interface WindowDecorationActions { /** Minimizes the task. */ fun onMinimize(taskInfo: RunningTaskInfo) /** Close the task */ fun onClose(taskId: Int, decoration: WindowDecorationWrapper, token: WindowContainerToken) /** * Moves task to immersive mode or exits immersive and restores task to previous size if task is * already in immersive. Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt +19 −0 Original line number Diff line number Diff line Loading @@ -366,6 +366,25 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() { verify(desktopTasksController).minimizeTask(task, MinimizeReason.KEY_GESTURE) } @Test fun keyGestureQuitFocusedDesktopTask_shouldQuitTask() { val task = setUpDesktopTask() 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_QUIT_FOCUSED_DESKTOP_TASK) .setKeycodes(intArrayOf(KeyEvent.KEYCODE_Q)) .setModifierState(KeyEvent.META_META_ON) .build() keyGestureEventHandler.handleKeyGestureEvent(event, null) testExecutor.flushAll() verify(desktopModeWindowDecorViewModel).closeTask(task) } @Test fun keyGestureSwitchToPreviousDesk_activatesDesk() { val displayId = 2 Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +30 −0 Original line number Diff line number Diff line Loading @@ -319,6 +319,36 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest assertThat(hierarchyOp.container).isEqualTo(decor.taskInfo.token.asBinder()) } @Test fun testCloseTask_notInSplitScreen_closesTask() { desktopModeWindowDecorViewModel.setFreeformTaskTransitionStarter( mockFreeformTaskTransitionStarter ) val decor = createOpenTaskDecoration(windowingMode = WINDOWING_MODE_FREEFORM) val taskInfo = decor.taskInfo whenever(mockSplitScreenController.isTaskInSplitScreen(eq(taskInfo.taskId))) .thenReturn(false) whenever(mockDesktopTasksController.getNextFocusedTask(eq(taskInfo))).thenReturn(-1) whenever(mockDesktopTasksController.onDesktopWindowClose(any(), any(), any())).thenReturn { binder: IBinder -> } desktopModeWindowDecorViewModel.closeTask(decor.taskInfo) verify(mockFreeformTaskTransitionStarter).startRemoveTransition(any()) } @Test fun testCloseTask_noDecoration_doesNothing() { val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM) // No decoration is created for this task. desktopModeWindowDecorViewModel.closeTask(task) verify(mockSplitScreenController, never()).isTaskInSplitScreen(any()) verify(mockFreeformTaskTransitionStarter, never()).startRemoveTransition(any()) } @Test @EnableFlags(Flags.FLAG_ENABLE_MINIMIZE_BUTTON) @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_HEADER_STATE_CHANGE_ANNOUNCEMENTS) Loading