Move desktop mode logic out of ShellTaskOrganizer
Expose list of running tasks per display from ShellTaskOrganizer. This allows us to move desktop mode related logic out from ShellTaskOrganizer and to DesktopModeController. Bug: 258282673 Test: atest DesktopModeControllerTest ShellTaskOrganizerTests Change-Id: I179c69c185153a07de3602627ed18734420abda2
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package com.android.wm.shell.desktopmode;
|
||||
|
||||
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 +153,20 @@ 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 */);
|
||||
// Reset freeform windowing mode that is set per task level so tasks inherit it
|
||||
clearFreeformForStandardTasks(runningTasks, wct);
|
||||
int targetWindowingMode;
|
||||
if (active) {
|
||||
targetWindowingMode = WINDOWING_MODE_FREEFORM;
|
||||
} else {
|
||||
targetWindowingMode = WINDOWING_MODE_FULLSCREEN;
|
||||
// Clear any resized bounds
|
||||
wct.merge(mShellTaskOrganizer.prepareClearBoundsForStandardTasks(displayId),
|
||||
true /* transfer */);
|
||||
clearBoundsForStandardTasks(runningTasks, wct);
|
||||
}
|
||||
prepareWindowingModeChange(wct, displayId, targetWindowingMode);
|
||||
setDisplayAreaWindowingMode(displayId, targetWindowingMode, wct);
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
mTransitions.startTransition(TRANSIT_CHANGE, wct, null);
|
||||
} else {
|
||||
@@ -173,17 +174,44 @@ 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 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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,106 @@ 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);
|
||||
public void testDesktopModeEnabled_rootTdaSetToFreeform() {
|
||||
DisplayAreaInfo displayAreaInfo = createMockDisplayArea();
|
||||
|
||||
// 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);
|
||||
|
||||
// The test
|
||||
mController.updateDesktopModeActive(true);
|
||||
WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
|
||||
|
||||
ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
|
||||
WindowContainerTransaction.class);
|
||||
verify(mRootTaskDisplayAreaOrganizer).applyTransaction(arg.capture());
|
||||
|
||||
// WCT should have 2 changes - clear task wm mode and set display wm mode
|
||||
WindowContainerTransaction wct = arg.getValue();
|
||||
assertThat(wct.getChanges()).hasSize(2);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
}
|
||||
|
||||
@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);
|
||||
public void testDesktopModeDisabled_rootTdaSetToFullscreen() {
|
||||
DisplayAreaInfo displayAreaInfo = createMockDisplayArea();
|
||||
|
||||
// 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);
|
||||
|
||||
// The test
|
||||
mController.updateDesktopModeActive(false);
|
||||
WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
|
||||
|
||||
ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
|
||||
WindowContainerTransaction.class);
|
||||
verify(mRootTaskDisplayAreaOrganizer).applyTransaction(arg.capture());
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
@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 task windowing mode to undefined
|
||||
Change taskWmMode = wct.getChanges().get(taskWmMockToken.binder());
|
||||
assertThat(taskWmMode).isNotNull();
|
||||
assertThat(taskWmMode.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
|
||||
mController.updateDesktopModeActive(true);
|
||||
WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
|
||||
|
||||
// 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();
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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 testDesktopModeDisabled_windowingModeAndBoundsCleared() {
|
||||
createMockDisplayArea();
|
||||
RunningTaskInfo freeformTask = createFreeformTask();
|
||||
RunningTaskInfo fullscreenTask = createFullscreenTask();
|
||||
RunningTaskInfo homeTask = createHomeTask();
|
||||
when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>(
|
||||
Arrays.asList(freeformTask, fullscreenTask, homeTask)));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@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 +236,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 +263,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 +273,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 +282,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 +346,5 @@ public class DesktopModeControllerTest extends ShellTestCase {
|
||||
WindowContainerToken token() {
|
||||
return mToken;
|
||||
}
|
||||
|
||||
IBinder binder() {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user