diff options
4 files changed, 258 insertions, 303 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 43679364b443..e58e785850fa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -16,14 +16,12 @@ package com.android.wm.shell; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS; @@ -48,7 +46,6 @@ import android.window.StartingWindowInfo; import android.window.StartingWindowRemovalInfo; import android.window.TaskAppearedInfo; import android.window.TaskOrganizer; -import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; @@ -567,6 +564,22 @@ public class ShellTaskOrganizer extends TaskOrganizer implements } } + /** + * Return list of {@link RunningTaskInfo}s for the given display. + * + * @return filtered list of tasks or empty list + */ + public ArrayList<RunningTaskInfo> getRunningTasks(int displayId) { + ArrayList<RunningTaskInfo> result = new ArrayList<>(); + for (int i = 0; i < mTasks.size(); i++) { + RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo(); + if (taskInfo.displayId == displayId) { + result.add(taskInfo); + } + } + return result; + } + /** Gets running task by taskId. Returns {@code null} if no such task observed. */ @Nullable public RunningTaskInfo getRunningTaskInfo(int taskId) { @@ -693,57 +706,6 @@ public class ShellTaskOrganizer extends TaskOrganizer implements taskListener.reparentChildSurfaceToTask(taskId, sc, t); } - /** - * Create a {@link WindowContainerTransaction} to clear task bounds. - * - * Only affects tasks that have {@link RunningTaskInfo#getActivityType()} set to - * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}. - * - * @param displayId display id for tasks that will have bounds cleared - * @return {@link WindowContainerTransaction} with pending operations to clear bounds - */ - public WindowContainerTransaction prepareClearBoundsForStandardTasks(int displayId) { - ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks: displayId=%d", displayId); - WindowContainerTransaction wct = new WindowContainerTransaction(); - for (int i = 0; i < mTasks.size(); i++) { - RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo(); - if ((taskInfo.displayId == displayId) && (taskInfo.getActivityType() - == WindowConfiguration.ACTIVITY_TYPE_STANDARD)) { - ProtoLog.d(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s", - taskInfo.token, taskInfo); - wct.setBounds(taskInfo.token, null); - } - } - return wct; - } - - /** - * Create a {@link WindowContainerTransaction} to clear task level freeform setting. - * - * Only affects tasks that have {@link RunningTaskInfo#getActivityType()} set to - * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}. - * - * @param displayId display id for tasks that will have windowing mode reset to {@link - * WindowConfiguration#WINDOWING_MODE_UNDEFINED} - * @return {@link WindowContainerTransaction} with pending operations to clear windowing mode - */ - public WindowContainerTransaction prepareClearFreeformForStandardTasks(int displayId) { - ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks: displayId=%d", displayId); - WindowContainerTransaction wct = new WindowContainerTransaction(); - for (int i = 0; i < mTasks.size(); i++) { - RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo(); - if (taskInfo.displayId == displayId - && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM - && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) { - ProtoLog.d(WM_SHELL_DESKTOP_MODE, - "clearing windowing mode for token=%s taskInfo=%s", taskInfo.token, - taskInfo); - wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED); - } - } - return wct; - } - private void logSizeCompatRestartButtonEventReported(@NonNull TaskAppearedInfo info, int event) { ActivityInfo topActivityInfo = info.getTaskInfo().topActivityInfo; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java index 34ff6d814c8d..abc4024bc290 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java @@ -16,8 +16,11 @@ package com.android.wm.shell.desktopmode; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -151,21 +154,18 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll int displayId = mContext.getDisplayId(); + ArrayList<RunningTaskInfo> runningTasks = mShellTaskOrganizer.getRunningTasks(displayId); + WindowContainerTransaction wct = new WindowContainerTransaction(); - // Reset freeform windowing mode that is set per task level (tasks should inherit - // container value) - wct.merge(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(displayId), - true /* transfer */); - int targetWindowingMode; + // Reset freeform windowing mode that is set per task level so tasks inherit it + clearFreeformForStandardTasks(runningTasks, wct); if (active) { - targetWindowingMode = WINDOWING_MODE_FREEFORM; + moveHomeBehindVisibleTasks(runningTasks, wct); + setDisplayAreaWindowingMode(displayId, WINDOWING_MODE_FREEFORM, wct); } else { - targetWindowingMode = WINDOWING_MODE_FULLSCREEN; - // Clear any resized bounds - wct.merge(mShellTaskOrganizer.prepareClearBoundsForStandardTasks(displayId), - true /* transfer */); + clearBoundsForStandardTasks(runningTasks, wct); + setDisplayAreaWindowingMode(displayId, WINDOWING_MODE_FULLSCREEN, wct); } - prepareWindowingModeChange(wct, displayId, targetWindowingMode); if (Transitions.ENABLE_SHELL_TRANSITIONS) { mTransitions.startTransition(TRANSIT_CHANGE, wct, null); } else { @@ -173,17 +173,69 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll } } - private void prepareWindowingModeChange(WindowContainerTransaction wct, - int displayId, @WindowConfiguration.WindowingMode int windowingMode) { - DisplayAreaInfo displayAreaInfo = mRootTaskDisplayAreaOrganizer - .getDisplayAreaInfo(displayId); + private WindowContainerTransaction clearBoundsForStandardTasks( + ArrayList<RunningTaskInfo> runningTasks, WindowContainerTransaction wct) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks"); + for (RunningTaskInfo taskInfo : runningTasks) { + if (taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s", + taskInfo.token, taskInfo); + wct.setBounds(taskInfo.token, null); + } + } + return wct; + } + + private void clearFreeformForStandardTasks(ArrayList<RunningTaskInfo> runningTasks, + WindowContainerTransaction wct) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks"); + for (RunningTaskInfo taskInfo : runningTasks) { + if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM + && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, + "clearing windowing mode for token=%s taskInfo=%s", taskInfo.token, + taskInfo); + wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED); + } + } + } + + private void moveHomeBehindVisibleTasks(ArrayList<RunningTaskInfo> runningTasks, + WindowContainerTransaction wct) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveHomeBehindVisibleTasks"); + RunningTaskInfo homeTask = null; + ArrayList<RunningTaskInfo> visibleTasks = new ArrayList<>(); + for (RunningTaskInfo taskInfo : runningTasks) { + if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) { + homeTask = taskInfo; + } else if (taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD + && taskInfo.isVisible()) { + visibleTasks.add(taskInfo); + } + } + if (homeTask == null) { + ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveHomeBehindVisibleTasks: home task not found"); + } else { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveHomeBehindVisibleTasks: visible tasks %d", + visibleTasks.size()); + wct.reorder(homeTask.getToken(), true /* onTop */); + for (RunningTaskInfo task : visibleTasks) { + wct.reorder(task.getToken(), true /* onTop */); + } + } + } + + private void setDisplayAreaWindowingMode(int displayId, + @WindowConfiguration.WindowingMode int windowingMode, WindowContainerTransaction wct) { + DisplayAreaInfo displayAreaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo( + displayId); if (displayAreaInfo == null) { ProtoLog.e(WM_SHELL_DESKTOP_MODE, "unable to update windowing mode for display %d display not found", displayId); return; } - ProtoLog.d(WM_SHELL_DESKTOP_MODE, + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "setWindowingMode: displayId=%d current wmMode=%d new wmMode=%d", displayId, displayAreaInfo.configuration.windowConfiguration.getWindowingMode(), windowingMode); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index 7cbace5af48f..081c8ae91bdb 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -16,13 +16,9 @@ package com.android.wm.shell; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -34,8 +30,6 @@ import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIO import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; @@ -44,11 +38,9 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; -import android.app.WindowConfiguration; import android.content.LocusId; import android.content.pm.ParceledListSlice; import android.os.Binder; @@ -61,8 +53,6 @@ import android.window.ITaskOrganizer; import android.window.ITaskOrganizerController; import android.window.TaskAppearedInfo; import android.window.WindowContainerToken; -import android.window.WindowContainerTransaction; -import android.window.WindowContainerTransaction.Change; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -638,130 +628,10 @@ public class ShellTaskOrganizerTests extends ShellTestCase { verify(mTaskOrganizerController).restartTaskTopActivityProcessIfVisible(task1.token); } - @Test - public void testPrepareClearBoundsForStandardTasks() { - MockToken token1 = new MockToken(); - RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED, token1); - mOrganizer.onTaskAppeared(task1, null); - - MockToken token2 = new MockToken(); - RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED, token2); - mOrganizer.onTaskAppeared(task2, null); - - MockToken otherDisplayToken = new MockToken(); - RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_UNDEFINED, - otherDisplayToken); - otherDisplayTask.displayId = 2; - mOrganizer.onTaskAppeared(otherDisplayTask, null); - - WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForStandardTasks(1); - - assertEquals(wct.getChanges().size(), 2); - Change boundsChange1 = wct.getChanges().get(token1.binder()); - assertNotNull(boundsChange1); - assertNotEquals( - (boundsChange1.getWindowSetMask() & WindowConfiguration.WINDOW_CONFIG_BOUNDS), 0); - assertTrue(boundsChange1.getConfiguration().windowConfiguration.getBounds().isEmpty()); - - Change boundsChange2 = wct.getChanges().get(token2.binder()); - assertNotNull(boundsChange2); - assertNotEquals( - (boundsChange2.getWindowSetMask() & WindowConfiguration.WINDOW_CONFIG_BOUNDS), 0); - assertTrue(boundsChange2.getConfiguration().windowConfiguration.getBounds().isEmpty()); - } - - @Test - public void testPrepareClearBoundsForStandardTasks_onlyClearActivityTypeStandard() { - MockToken token1 = new MockToken(); - RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED, token1); - mOrganizer.onTaskAppeared(task1, null); - - MockToken token2 = new MockToken(); - RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED, token2); - task2.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME); - mOrganizer.onTaskAppeared(task2, null); - - WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForStandardTasks(1); - - // Only clear bounds for task1 - assertEquals(1, wct.getChanges().size()); - assertNotNull(wct.getChanges().get(token1.binder())); - } - - @Test - public void testPrepareClearFreeformForStandardTasks() { - MockToken token1 = new MockToken(); - RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM, token1); - mOrganizer.onTaskAppeared(task1, null); - - MockToken token2 = new MockToken(); - RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW, token2); - mOrganizer.onTaskAppeared(task2, null); - - MockToken otherDisplayToken = new MockToken(); - RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_FREEFORM, - otherDisplayToken); - otherDisplayTask.displayId = 2; - mOrganizer.onTaskAppeared(otherDisplayTask, null); - - WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForStandardTasks(1); - - // Only task with freeform windowing mode and the right display should be updated - assertEquals(wct.getChanges().size(), 1); - Change wmModeChange1 = wct.getChanges().get(token1.binder()); - assertNotNull(wmModeChange1); - assertEquals(wmModeChange1.getWindowingMode(), WINDOWING_MODE_UNDEFINED); - } - - @Test - public void testPrepareClearFreeformForStandardTasks_onlyClearActivityTypeStandard() { - MockToken token1 = new MockToken(); - RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM, token1); - mOrganizer.onTaskAppeared(task1, null); - - MockToken token2 = new MockToken(); - RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_FREEFORM, token2); - task2.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME); - mOrganizer.onTaskAppeared(task2, null); - - WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForStandardTasks(1); - - // Only clear freeform for task1 - assertEquals(1, wct.getChanges().size()); - assertNotNull(wct.getChanges().get(token1.binder())); - } - private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) { RunningTaskInfo taskInfo = new RunningTaskInfo(); taskInfo.taskId = taskId; taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode); return taskInfo; } - - private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode, MockToken token) { - RunningTaskInfo taskInfo = createTaskInfo(taskId, windowingMode); - taskInfo.displayId = 1; - taskInfo.token = token.token(); - taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD); - return taskInfo; - } - - private static class MockToken { - private final WindowContainerToken mToken; - private final IBinder mBinder; - - MockToken() { - mToken = mock(WindowContainerToken.class); - mBinder = mock(IBinder.class); - when(mToken.asBinder()).thenReturn(mBinder); - } - - WindowContainerToken token() { - return mToken; - } - - IBinder binder() { - return mBinder; - } - } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java index 79b520c734c8..89bafcb6b2f4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java @@ -16,10 +16,13 @@ package com.android.wm.shell.desktopmode; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS; +import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER; @@ -30,13 +33,14 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.app.ActivityManager; +import android.app.ActivityManager.RunningTaskInfo; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -68,6 +72,9 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; +import java.util.ArrayList; +import java.util.Arrays; + @SmallTest @RunWith(AndroidTestingRunner.class) public class DesktopModeControllerTest extends ShellTestCase { @@ -83,9 +90,7 @@ public class DesktopModeControllerTest extends ShellTestCase { @Mock private Handler mMockHandler; @Mock - private Transitions mMockTransitions; - private TestShellExecutor mExecutor; - + private Transitions mTransitions; private DesktopModeController mController; private DesktopModeTaskRepository mDesktopModeTaskRepository; private ShellInit mShellInit; @@ -97,20 +102,19 @@ public class DesktopModeControllerTest extends ShellTestCase { when(DesktopModeStatus.isActive(any())).thenReturn(true); mShellInit = Mockito.spy(new ShellInit(mTestExecutor)); - mExecutor = new TestShellExecutor(); mDesktopModeTaskRepository = new DesktopModeTaskRepository(); mController = new DesktopModeController(mContext, mShellInit, mShellController, - mShellTaskOrganizer, mRootTaskDisplayAreaOrganizer, mMockTransitions, - mDesktopModeTaskRepository, mMockHandler, mExecutor); + mShellTaskOrganizer, mRootTaskDisplayAreaOrganizer, mTransitions, + mDesktopModeTaskRepository, mMockHandler, new TestShellExecutor()); - when(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(anyInt())).thenReturn( - new WindowContainerTransaction()); + when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>()); mShellInit.init(); clearInvocations(mShellTaskOrganizer); clearInvocations(mRootTaskDisplayAreaOrganizer); + clearInvocations(mTransitions); } @After @@ -124,113 +128,133 @@ public class DesktopModeControllerTest extends ShellTestCase { } @Test - public void testDesktopModeEnabled_taskWmClearedDisplaySetToFreeform() { - // Create a fake WCT to simulate setting task windowing mode to undefined - WindowContainerTransaction taskWct = new WindowContainerTransaction(); - MockToken taskMockToken = new MockToken(); - taskWct.setWindowingMode(taskMockToken.token(), WINDOWING_MODE_UNDEFINED); - when(mShellTaskOrganizer.prepareClearFreeformForStandardTasks( - mContext.getDisplayId())).thenReturn(taskWct); - - // Create a fake DisplayAreaInfo to check if windowing mode change is set correctly - MockToken displayMockToken = new MockToken(); - DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(displayMockToken.mToken, - mContext.getDisplayId(), 0); - when(mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(mContext.getDisplayId())) - .thenReturn(displayAreaInfo); + public void testDesktopModeEnabled_rootTdaSetToFreeform() { + DisplayAreaInfo displayAreaInfo = createMockDisplayArea(); - // The test mController.updateDesktopModeActive(true); + WindowContainerTransaction wct = getDesktopModeSwitchTransaction(); + + // 1 change: Root TDA windowing mode + assertThat(wct.getChanges().size()).isEqualTo(1); + // Verify WCT has a change for setting windowing mode to freeform + Change change = wct.getChanges().get(displayAreaInfo.token.asBinder()); + assertThat(change).isNotNull(); + assertThat(change.getWindowingMode()).isEqualTo(WINDOWING_MODE_FREEFORM); + } - ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass( - WindowContainerTransaction.class); - verify(mRootTaskDisplayAreaOrganizer).applyTransaction(arg.capture()); + @Test + public void testDesktopModeDisabled_rootTdaSetToFullscreen() { + DisplayAreaInfo displayAreaInfo = createMockDisplayArea(); - // WCT should have 2 changes - clear task wm mode and set display wm mode - WindowContainerTransaction wct = arg.getValue(); - assertThat(wct.getChanges()).hasSize(2); + mController.updateDesktopModeActive(false); + WindowContainerTransaction wct = getDesktopModeSwitchTransaction(); + + // 1 change: Root TDA windowing mode + assertThat(wct.getChanges().size()).isEqualTo(1); + // Verify WCT has a change for setting windowing mode to fullscreen + Change change = wct.getChanges().get(displayAreaInfo.token.asBinder()); + assertThat(change).isNotNull(); + assertThat(change.getWindowingMode()).isEqualTo(WINDOWING_MODE_FULLSCREEN); + } - // Verify executed WCT has a change for setting task windowing mode to undefined - Change taskWmModeChange = wct.getChanges().get(taskMockToken.binder()); - assertThat(taskWmModeChange).isNotNull(); - assertThat(taskWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED); + @Test + public void testDesktopModeEnabled_windowingModeCleared() { + createMockDisplayArea(); + RunningTaskInfo freeformTask = createFreeformTask(); + RunningTaskInfo fullscreenTask = createFullscreenTask(); + RunningTaskInfo homeTask = createHomeTask(); + when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>( + Arrays.asList(freeformTask, fullscreenTask, homeTask))); - // Verify executed WCT has a change for setting display windowing mode to freeform - Change displayWmModeChange = wct.getChanges().get(displayAreaInfo.token.asBinder()); - assertThat(displayWmModeChange).isNotNull(); - assertThat(displayWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_FREEFORM); + mController.updateDesktopModeActive(true); + WindowContainerTransaction wct = getDesktopModeSwitchTransaction(); + + // 2 changes: Root TDA windowing mode and 1 task + assertThat(wct.getChanges().size()).isEqualTo(2); + // No changes for tasks that are not standard or freeform + assertThat(wct.getChanges().get(fullscreenTask.token.asBinder())).isNull(); + assertThat(wct.getChanges().get(homeTask.token.asBinder())).isNull(); + // Standard freeform task has windowing mode cleared + Change change = wct.getChanges().get(freeformTask.token.asBinder()); + assertThat(change).isNotNull(); + assertThat(change.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED); } @Test - public void testDesktopModeDisabled_taskWmAndBoundsClearedDisplaySetToFullscreen() { - // Create a fake WCT to simulate setting task windowing mode to undefined - WindowContainerTransaction taskWmWct = new WindowContainerTransaction(); - MockToken taskWmMockToken = new MockToken(); - taskWmWct.setWindowingMode(taskWmMockToken.token(), WINDOWING_MODE_UNDEFINED); - when(mShellTaskOrganizer.prepareClearFreeformForStandardTasks( - mContext.getDisplayId())).thenReturn(taskWmWct); - - // Create a fake WCT to simulate clearing task bounds - WindowContainerTransaction taskBoundsWct = new WindowContainerTransaction(); - MockToken taskBoundsMockToken = new MockToken(); - taskBoundsWct.setBounds(taskBoundsMockToken.token(), null); - when(mShellTaskOrganizer.prepareClearBoundsForStandardTasks( - mContext.getDisplayId())).thenReturn(taskBoundsWct); - - // Create a fake DisplayAreaInfo to check if windowing mode change is set correctly - MockToken displayMockToken = new MockToken(); - DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(displayMockToken.mToken, - mContext.getDisplayId(), 0); - when(mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(mContext.getDisplayId())) - .thenReturn(displayAreaInfo); + public void testDesktopModeDisabled_windowingModeAndBoundsCleared() { + createMockDisplayArea(); + RunningTaskInfo freeformTask = createFreeformTask(); + RunningTaskInfo fullscreenTask = createFullscreenTask(); + RunningTaskInfo homeTask = createHomeTask(); + when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>( + Arrays.asList(freeformTask, fullscreenTask, homeTask))); - // The test mController.updateDesktopModeActive(false); + WindowContainerTransaction wct = getDesktopModeSwitchTransaction(); + + // 3 changes: Root TDA windowing mode and 2 tasks + assertThat(wct.getChanges().size()).isEqualTo(3); + // No changes to home task + assertThat(wct.getChanges().get(homeTask.token.asBinder())).isNull(); + // Standard tasks have bounds cleared + assertThatBoundsCleared(wct.getChanges().get(freeformTask.token.asBinder())); + assertThatBoundsCleared(wct.getChanges().get(fullscreenTask.token.asBinder())); + // Freeform standard tasks have windowing mode cleared + assertThat(wct.getChanges().get( + freeformTask.token.asBinder()).getWindowingMode()).isEqualTo( + WINDOWING_MODE_UNDEFINED); + } - ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass( - WindowContainerTransaction.class); - verify(mRootTaskDisplayAreaOrganizer).applyTransaction(arg.capture()); - - // WCT should have 3 changes - clear task wm mode and bounds and set display wm mode - WindowContainerTransaction wct = arg.getValue(); - assertThat(wct.getChanges()).hasSize(3); - - // Verify executed WCT has a change for setting task windowing mode to undefined - Change taskWmMode = wct.getChanges().get(taskWmMockToken.binder()); - assertThat(taskWmMode).isNotNull(); - assertThat(taskWmMode.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED); - - // Verify executed WCT has a change for clearing task bounds - Change bounds = wct.getChanges().get(taskBoundsMockToken.binder()); - assertThat(bounds).isNotNull(); - assertThat(bounds.getWindowSetMask() & WINDOW_CONFIG_BOUNDS).isNotEqualTo(0); - assertThat(bounds.getConfiguration().windowConfiguration.getBounds().isEmpty()).isTrue(); - - // Verify executed WCT has a change for setting display windowing mode to fullscreen - Change displayWmModeChange = wct.getChanges().get(displayAreaInfo.token.asBinder()); - assertThat(displayWmModeChange).isNotNull(); - assertThat(displayWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_FULLSCREEN); + @Test + public void testDesktopModeEnabled_homeTaskBehindVisibleTask() { + createMockDisplayArea(); + RunningTaskInfo fullscreenTask1 = createFullscreenTask(); + fullscreenTask1.isVisible = true; + RunningTaskInfo fullscreenTask2 = createFullscreenTask(); + fullscreenTask2.isVisible = false; + RunningTaskInfo homeTask = createHomeTask(); + when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>( + Arrays.asList(fullscreenTask1, fullscreenTask2, homeTask))); + + mController.updateDesktopModeActive(true); + WindowContainerTransaction wct = getDesktopModeSwitchTransaction(); + + // Check that there are hierarchy changes for home task and visible task + assertThat(wct.getHierarchyOps()).hasSize(2); + // First show home task + WindowContainerTransaction.HierarchyOp op1 = wct.getHierarchyOps().get(0); + assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); + assertThat(op1.getContainer()).isEqualTo(homeTask.token.asBinder()); + + // Then visible task on top of it + WindowContainerTransaction.HierarchyOp op2 = wct.getHierarchyOps().get(1); + assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); + assertThat(op2.getContainer()).isEqualTo(fullscreenTask1.token.asBinder()); } @Test public void testShowDesktopApps() { // Set up two active tasks on desktop - mDesktopModeTaskRepository.addActiveTask(1); - mDesktopModeTaskRepository.addActiveTask(2); - MockToken token1 = new MockToken(); - MockToken token2 = new MockToken(); - ActivityManager.RunningTaskInfo taskInfo1 = new TestRunningTaskInfoBuilder().setToken( - token1.token()).setLastActiveTime(100).build(); - ActivityManager.RunningTaskInfo taskInfo2 = new TestRunningTaskInfoBuilder().setToken( - token2.token()).setLastActiveTime(200).build(); - when(mShellTaskOrganizer.getRunningTaskInfo(1)).thenReturn(taskInfo1); - when(mShellTaskOrganizer.getRunningTaskInfo(2)).thenReturn(taskInfo2); + RunningTaskInfo freeformTask1 = createFreeformTask(); + freeformTask1.lastActiveTime = 100; + RunningTaskInfo freeformTask2 = createFreeformTask(); + freeformTask2.lastActiveTime = 200; + mDesktopModeTaskRepository.addActiveTask(freeformTask1.taskId); + mDesktopModeTaskRepository.addActiveTask(freeformTask2.taskId); + when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask1.taskId)).thenReturn( + freeformTask1); + when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask2.taskId)).thenReturn( + freeformTask2); // Run show desktop apps logic mController.showDesktopApps(); ArgumentCaptor<WindowContainerTransaction> wctCaptor = ArgumentCaptor.forClass( WindowContainerTransaction.class); - verify(mShellTaskOrganizer).applyTransaction(wctCaptor.capture()); + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + verify(mTransitions).startTransition(eq(TRANSIT_TO_FRONT), wctCaptor.capture(), any()); + } else { + verify(mShellTaskOrganizer).applyTransaction(wctCaptor.capture()); + } WindowContainerTransaction wct = wctCaptor.getValue(); // Check wct has reorder calls @@ -239,12 +263,12 @@ public class DesktopModeControllerTest extends ShellTestCase { // Task 2 has activity later, must be first WindowContainerTransaction.HierarchyOp op1 = wct.getHierarchyOps().get(0); assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); - assertThat(op1.getContainer()).isEqualTo(token2.binder()); + assertThat(op1.getContainer()).isEqualTo(freeformTask2.token.asBinder()); // Task 1 should be second - WindowContainerTransaction.HierarchyOp op2 = wct.getHierarchyOps().get(0); + WindowContainerTransaction.HierarchyOp op2 = wct.getHierarchyOps().get(1); assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); - assertThat(op2.getContainer()).isEqualTo(token2.binder()); + assertThat(op2.getContainer()).isEqualTo(freeformTask1.token.asBinder()); } @Test @@ -266,7 +290,7 @@ public class DesktopModeControllerTest extends ShellTestCase { @Test public void testHandleTransitionRequest_notFreeform_returnsNull() { - ActivityManager.RunningTaskInfo trigger = new ActivityManager.RunningTaskInfo(); + RunningTaskInfo trigger = new RunningTaskInfo(); trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); WindowContainerTransaction wct = mController.handleRequest( new Binder(), @@ -276,7 +300,7 @@ public class DesktopModeControllerTest extends ShellTestCase { @Test public void testHandleTransitionRequest_returnsWct() { - ActivityManager.RunningTaskInfo trigger = new ActivityManager.RunningTaskInfo(); + RunningTaskInfo trigger = new RunningTaskInfo(); trigger.token = new MockToken().mToken; trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); WindowContainerTransaction wct = mController.handleRequest( @@ -285,6 +309,57 @@ public class DesktopModeControllerTest extends ShellTestCase { assertThat(wct).isNotNull(); } + private DisplayAreaInfo createMockDisplayArea() { + DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(new MockToken().mToken, + mContext.getDisplayId(), 0); + when(mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(mContext.getDisplayId())) + .thenReturn(displayAreaInfo); + return displayAreaInfo; + } + + private RunningTaskInfo createFreeformTask() { + return new TestRunningTaskInfoBuilder() + .setToken(new MockToken().token()) + .setActivityType(ACTIVITY_TYPE_STANDARD) + .setWindowingMode(WINDOWING_MODE_FREEFORM) + .setLastActiveTime(100) + .build(); + } + + private RunningTaskInfo createFullscreenTask() { + return new TestRunningTaskInfoBuilder() + .setToken(new MockToken().token()) + .setActivityType(ACTIVITY_TYPE_STANDARD) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) + .setLastActiveTime(100) + .build(); + } + + private RunningTaskInfo createHomeTask() { + return new TestRunningTaskInfoBuilder() + .setToken(new MockToken().token()) + .setActivityType(ACTIVITY_TYPE_HOME) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) + .setLastActiveTime(100) + .build(); + } + + private WindowContainerTransaction getDesktopModeSwitchTransaction() { + ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass( + WindowContainerTransaction.class); + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + verify(mTransitions).startTransition(eq(TRANSIT_CHANGE), arg.capture(), any()); + } else { + verify(mRootTaskDisplayAreaOrganizer).applyTransaction(arg.capture()); + } + return arg.getValue(); + } + + private void assertThatBoundsCleared(Change change) { + assertThat((change.getWindowSetMask() & WINDOW_CONFIG_BOUNDS) != 0).isTrue(); + assertThat(change.getConfiguration().windowConfiguration.getBounds().isEmpty()).isTrue(); + } + private static class MockToken { private final WindowContainerToken mToken; private final IBinder mBinder; @@ -298,9 +373,5 @@ public class DesktopModeControllerTest extends ShellTestCase { WindowContainerToken token() { return mToken; } - - IBinder binder() { - return mBinder; - } } } |