Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +28 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; Loading Loading @@ -175,6 +176,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private boolean mInImmersiveMode; private final String mSysUIPackageName; private final DisplayChangeController.OnDisplayChangingListener mOnDisplayChangingListener; private final ISystemGestureExclusionListener mGestureExclusionListener = new ISystemGestureExclusionListener.Stub() { @Override Loading Loading @@ -287,6 +289,31 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mSysUIPackageName = mContext.getResources().getString( com.android.internal.R.string.config_systemUi); mInteractionJankMonitor = interactionJankMonitor; mOnDisplayChangingListener = (displayId, fromRotation, toRotation, displayAreaInfo, t) -> { DesktopModeWindowDecoration decoration; RunningTaskInfo taskInfo; for (int i = 0; i < mWindowDecorByTaskId.size(); i++) { decoration = mWindowDecorByTaskId.valueAt(i); if (decoration == null) { continue; } else { taskInfo = decoration.mTaskInfo; } // Check if display has been rotated between portrait & landscape if (displayId == taskInfo.displayId && taskInfo.isFreeform() && (fromRotation % 2 != toRotation % 2)) { // Check if the task bounds on the rotated display will be out of bounds. // If so, then update task bounds to be within reachable area. final Rect taskBounds = new Rect( taskInfo.configuration.windowConfiguration.getBounds()); if (DragPositioningCallbackUtility.snapTaskBoundsIfNecessary( taskBounds, decoration.calculateValidDragArea())) { t.setBounds(taskInfo.token, taskBounds); } } } }; shellInit.addInitCallback(this::onInit, this); } Loading @@ -298,6 +325,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { new DesktopModeOnInsetsChangedListener()); mDesktopTasksController.setOnTaskResizeAnimationListener( new DesktopModeOnTaskResizeAnimationListener()); mDisplayController.addDisplayChangingController(mOnDisplayChangingListener); try { mWindowManager.registerSystemGestureExclusionListener(mGestureExclusionListener, mContext.getDisplayId()); Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +3 −6 Original line number Diff line number Diff line Loading @@ -312,8 +312,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // transaction (that applies task crop) is synced with the buffer transaction (that draws // the View). Both will be shown on screen at the same, whereas applying them independently // causes flickering. See b/270202228. final boolean applyTransactionOnDraw = taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; final boolean applyTransactionOnDraw = taskInfo.isFreeform(); relayout(taskInfo, t, t, applyTransactionOnDraw, shouldSetTaskPositionAndCrop); if (!applyTransactionOnDraw) { t.apply(); Loading @@ -324,7 +323,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) { Trace.beginSection("DesktopModeWindowDecoration#relayout"); if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { if (taskInfo.isFreeform()) { // The Task is in Freeform mode -> show its header in sync since it's an integral part // of the window itself - a delayed header might cause bad UX. relayoutInSync(taskInfo, startT, finishT, applyStartTransactionOnDraw, Loading Loading @@ -524,9 +523,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo) { final boolean isFreeform = taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; return isFreeform && taskInfo.isResizeable; return taskInfo.isFreeform() && taskInfo.isResizeable; } private void updateMaximizeMenu(SurfaceControl.Transaction startT) { Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +148 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_PINNED import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.app.WindowConfiguration.WindowingMode import android.content.ComponentName Loading Loading @@ -51,11 +52,13 @@ import android.view.InputMonitor import android.view.InsetsSource import android.view.InsetsState import android.view.KeyEvent import android.view.Surface import android.view.SurfaceControl import android.view.SurfaceView import android.view.View import android.view.WindowInsets.Type.navigationBars import android.view.WindowInsets.Type.statusBars import android.window.WindowContainerTransaction import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession Loading @@ -69,6 +72,7 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestRunningTaskInfoBuilder import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser import com.android.wm.shell.common.DisplayChangeController import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayInsetsController import com.android.wm.shell.common.DisplayLayout Loading Loading @@ -110,6 +114,7 @@ import org.mockito.kotlin.argThat import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doNothing import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.whenever import org.mockito.quality.Strictness Loading Loading @@ -166,6 +171,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { private lateinit var mockitoSession: StaticMockitoSession private lateinit var shellInit: ShellInit private lateinit var desktopModeOnInsetsChangedListener: DesktopModeOnInsetsChangedListener private lateinit var displayChangingListener: DisplayChangeController.OnDisplayChangingListener private lateinit var desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel @Before Loading @@ -174,6 +180,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { mockitoSession() .strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java) .spyStatic(DragPositioningCallbackUtility::class.java) .startMocking() doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(Mockito.any()) } Loading Loading @@ -218,10 +225,17 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { shellInit.init() val listenerCaptor = val insetListenerCaptor = argumentCaptor<DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener>() verify(displayInsetsController).addInsetsChangedListener(anyInt(), listenerCaptor.capture()) desktopModeOnInsetsChangedListener = listenerCaptor.firstValue verify(displayInsetsController) .addInsetsChangedListener(anyInt(), insetListenerCaptor.capture()) desktopModeOnInsetsChangedListener = insetListenerCaptor.firstValue val displayChangingListenerCaptor = argumentCaptor<DisplayChangeController.OnDisplayChangingListener>() verify(mockDisplayController) .addDisplayChangingController(displayChangingListenerCaptor.capture()) displayChangingListener = displayChangingListenerCaptor.firstValue } @After Loading Loading @@ -786,6 +800,135 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { }) } @Test fun testOnDisplayRotation_tasksOutOfValidArea_taskBoundsUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) val thirdTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) doReturn(true).`when` { DragPositioningCallbackUtility.snapTaskBoundsIfNecessary(any(), any()) } setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_90, null, wct ) verify(wct).setBounds(eq(task.token), any()) verify(wct).setBounds(eq(secondTask.token), any()) verify(wct).setBounds(eq(thirdTask.token), any()) } @Test fun testOnDisplayRotation_taskInValidArea_taskBoundsNotUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) val thirdTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) doReturn(false).`when` { DragPositioningCallbackUtility.snapTaskBoundsIfNecessary(any(), any()) } setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_90, null, wct ) verify(wct, never()).setBounds(eq(task.token), any()) verify(wct, never()).setBounds(eq(secondTask.token), any()) verify(wct, never()).setBounds(eq(thirdTask.token), any()) } @Test fun testOnDisplayRotation_sameOrientationRotation_taskBoundsNotUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) val thirdTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_180, null, wct ) verify(wct, never()).setBounds(eq(task.token), any()) verify(wct, never()).setBounds(eq(secondTask.token), any()) verify(wct, never()).setBounds(eq(thirdTask.token), any()) } @Test fun testOnDisplayRotation_differentDisplayId_taskBoundsNotUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = -2, windowingMode = WINDOWING_MODE_FREEFORM) val thirdTask = createTask(displayId = -3, windowingMode = WINDOWING_MODE_FREEFORM) doReturn(true).`when` { DragPositioningCallbackUtility.snapTaskBoundsIfNecessary(any(), any()) } setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_90, null, wct ) verify(wct).setBounds(eq(task.token), any()) verify(wct, never()).setBounds(eq(secondTask.token), any()) verify(wct, never()).setBounds(eq(thirdTask.token), any()) } @Test fun testOnDisplayRotation_nonFreeformTask_taskBoundsNotUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = -2, windowingMode = WINDOWING_MODE_FULLSCREEN) val thirdTask = createTask(displayId = -3, windowingMode = WINDOWING_MODE_PINNED) doReturn(true).`when` { DragPositioningCallbackUtility.snapTaskBoundsIfNecessary(any(), any()) } setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_90, null, wct ) verify(wct).setBounds(eq(task.token), any()) verify(wct, never()).setBounds(eq(secondTask.token), any()) verify(wct, never()).setBounds(eq(thirdTask.token), any()) } private fun createOpenTaskDecoration( @WindowingMode windowingMode: Int, onMaxOrRestoreListenerCaptor: ArgumentCaptor<Function0<Unit>> = Loading Loading @@ -864,6 +1007,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { whenever(mockSplitScreenController.isTaskInSplitScreen(task.taskId)) .thenReturn(true) } whenever(decoration.calculateValidDragArea()).thenReturn(Rect(0, 60, 2560, 1600)) return decoration } Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +28 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; Loading Loading @@ -175,6 +176,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private boolean mInImmersiveMode; private final String mSysUIPackageName; private final DisplayChangeController.OnDisplayChangingListener mOnDisplayChangingListener; private final ISystemGestureExclusionListener mGestureExclusionListener = new ISystemGestureExclusionListener.Stub() { @Override Loading Loading @@ -287,6 +289,31 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mSysUIPackageName = mContext.getResources().getString( com.android.internal.R.string.config_systemUi); mInteractionJankMonitor = interactionJankMonitor; mOnDisplayChangingListener = (displayId, fromRotation, toRotation, displayAreaInfo, t) -> { DesktopModeWindowDecoration decoration; RunningTaskInfo taskInfo; for (int i = 0; i < mWindowDecorByTaskId.size(); i++) { decoration = mWindowDecorByTaskId.valueAt(i); if (decoration == null) { continue; } else { taskInfo = decoration.mTaskInfo; } // Check if display has been rotated between portrait & landscape if (displayId == taskInfo.displayId && taskInfo.isFreeform() && (fromRotation % 2 != toRotation % 2)) { // Check if the task bounds on the rotated display will be out of bounds. // If so, then update task bounds to be within reachable area. final Rect taskBounds = new Rect( taskInfo.configuration.windowConfiguration.getBounds()); if (DragPositioningCallbackUtility.snapTaskBoundsIfNecessary( taskBounds, decoration.calculateValidDragArea())) { t.setBounds(taskInfo.token, taskBounds); } } } }; shellInit.addInitCallback(this::onInit, this); } Loading @@ -298,6 +325,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { new DesktopModeOnInsetsChangedListener()); mDesktopTasksController.setOnTaskResizeAnimationListener( new DesktopModeOnTaskResizeAnimationListener()); mDisplayController.addDisplayChangingController(mOnDisplayChangingListener); try { mWindowManager.registerSystemGestureExclusionListener(mGestureExclusionListener, mContext.getDisplayId()); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +3 −6 Original line number Diff line number Diff line Loading @@ -312,8 +312,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // transaction (that applies task crop) is synced with the buffer transaction (that draws // the View). Both will be shown on screen at the same, whereas applying them independently // causes flickering. See b/270202228. final boolean applyTransactionOnDraw = taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; final boolean applyTransactionOnDraw = taskInfo.isFreeform(); relayout(taskInfo, t, t, applyTransactionOnDraw, shouldSetTaskPositionAndCrop); if (!applyTransactionOnDraw) { t.apply(); Loading @@ -324,7 +323,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) { Trace.beginSection("DesktopModeWindowDecoration#relayout"); if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { if (taskInfo.isFreeform()) { // The Task is in Freeform mode -> show its header in sync since it's an integral part // of the window itself - a delayed header might cause bad UX. relayoutInSync(taskInfo, startT, finishT, applyStartTransactionOnDraw, Loading Loading @@ -524,9 +523,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo) { final boolean isFreeform = taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; return isFreeform && taskInfo.isResizeable; return taskInfo.isFreeform() && taskInfo.isResizeable; } private void updateMaximizeMenu(SurfaceControl.Transaction startT) { Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +148 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_PINNED import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.app.WindowConfiguration.WindowingMode import android.content.ComponentName Loading Loading @@ -51,11 +52,13 @@ import android.view.InputMonitor import android.view.InsetsSource import android.view.InsetsState import android.view.KeyEvent import android.view.Surface import android.view.SurfaceControl import android.view.SurfaceView import android.view.View import android.view.WindowInsets.Type.navigationBars import android.view.WindowInsets.Type.statusBars import android.window.WindowContainerTransaction import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession Loading @@ -69,6 +72,7 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestRunningTaskInfoBuilder import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser import com.android.wm.shell.common.DisplayChangeController import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayInsetsController import com.android.wm.shell.common.DisplayLayout Loading Loading @@ -110,6 +114,7 @@ import org.mockito.kotlin.argThat import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doNothing import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.whenever import org.mockito.quality.Strictness Loading Loading @@ -166,6 +171,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { private lateinit var mockitoSession: StaticMockitoSession private lateinit var shellInit: ShellInit private lateinit var desktopModeOnInsetsChangedListener: DesktopModeOnInsetsChangedListener private lateinit var displayChangingListener: DisplayChangeController.OnDisplayChangingListener private lateinit var desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel @Before Loading @@ -174,6 +180,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { mockitoSession() .strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java) .spyStatic(DragPositioningCallbackUtility::class.java) .startMocking() doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(Mockito.any()) } Loading Loading @@ -218,10 +225,17 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { shellInit.init() val listenerCaptor = val insetListenerCaptor = argumentCaptor<DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener>() verify(displayInsetsController).addInsetsChangedListener(anyInt(), listenerCaptor.capture()) desktopModeOnInsetsChangedListener = listenerCaptor.firstValue verify(displayInsetsController) .addInsetsChangedListener(anyInt(), insetListenerCaptor.capture()) desktopModeOnInsetsChangedListener = insetListenerCaptor.firstValue val displayChangingListenerCaptor = argumentCaptor<DisplayChangeController.OnDisplayChangingListener>() verify(mockDisplayController) .addDisplayChangingController(displayChangingListenerCaptor.capture()) displayChangingListener = displayChangingListenerCaptor.firstValue } @After Loading Loading @@ -786,6 +800,135 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { }) } @Test fun testOnDisplayRotation_tasksOutOfValidArea_taskBoundsUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) val thirdTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) doReturn(true).`when` { DragPositioningCallbackUtility.snapTaskBoundsIfNecessary(any(), any()) } setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_90, null, wct ) verify(wct).setBounds(eq(task.token), any()) verify(wct).setBounds(eq(secondTask.token), any()) verify(wct).setBounds(eq(thirdTask.token), any()) } @Test fun testOnDisplayRotation_taskInValidArea_taskBoundsNotUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) val thirdTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) doReturn(false).`when` { DragPositioningCallbackUtility.snapTaskBoundsIfNecessary(any(), any()) } setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_90, null, wct ) verify(wct, never()).setBounds(eq(task.token), any()) verify(wct, never()).setBounds(eq(secondTask.token), any()) verify(wct, never()).setBounds(eq(thirdTask.token), any()) } @Test fun testOnDisplayRotation_sameOrientationRotation_taskBoundsNotUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) val thirdTask = createTask(displayId = task.displayId, windowingMode = WINDOWING_MODE_FREEFORM) setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_180, null, wct ) verify(wct, never()).setBounds(eq(task.token), any()) verify(wct, never()).setBounds(eq(secondTask.token), any()) verify(wct, never()).setBounds(eq(thirdTask.token), any()) } @Test fun testOnDisplayRotation_differentDisplayId_taskBoundsNotUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = -2, windowingMode = WINDOWING_MODE_FREEFORM) val thirdTask = createTask(displayId = -3, windowingMode = WINDOWING_MODE_FREEFORM) doReturn(true).`when` { DragPositioningCallbackUtility.snapTaskBoundsIfNecessary(any(), any()) } setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_90, null, wct ) verify(wct).setBounds(eq(task.token), any()) verify(wct, never()).setBounds(eq(secondTask.token), any()) verify(wct, never()).setBounds(eq(thirdTask.token), any()) } @Test fun testOnDisplayRotation_nonFreeformTask_taskBoundsNotUpdated() { val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM) val secondTask = createTask(displayId = -2, windowingMode = WINDOWING_MODE_FULLSCREEN) val thirdTask = createTask(displayId = -3, windowingMode = WINDOWING_MODE_PINNED) doReturn(true).`when` { DragPositioningCallbackUtility.snapTaskBoundsIfNecessary(any(), any()) } setUpMockDecorationsForTasks(task, secondTask, thirdTask) onTaskOpening(task) onTaskOpening(secondTask) onTaskOpening(thirdTask) val wct = mock<WindowContainerTransaction>() displayChangingListener.onDisplayChange( task.displayId, Surface.ROTATION_0, Surface.ROTATION_90, null, wct ) verify(wct).setBounds(eq(task.token), any()) verify(wct, never()).setBounds(eq(secondTask.token), any()) verify(wct, never()).setBounds(eq(thirdTask.token), any()) } private fun createOpenTaskDecoration( @WindowingMode windowingMode: Int, onMaxOrRestoreListenerCaptor: ArgumentCaptor<Function0<Unit>> = Loading Loading @@ -864,6 +1007,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { whenever(mockSplitScreenController.isTaskInSplitScreen(task.taskId)) .thenReturn(true) } whenever(decoration.calculateValidDragArea()).thenReturn(Rect(0, 60, 2560, 1600)) return decoration } Loading