summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java346
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java269
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java953
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java (renamed from services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java)894
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java912
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java423
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java1161
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java225
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java1189
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java42
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java342
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java76
20 files changed, 3391 insertions, 3617 deletions
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
deleted file mode 100644
index 1700707d9866..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
-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_PINNED;
-import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for the {@link DisplayContent} class.
- *
- * Build/Install/Run:
- * atest WmTests:ActivityDisplayTests
- */
-@SmallTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-// TODO(b/144248496): Merge to DisplayContentTests
-public class ActivityDisplayTests extends WindowTestsBase {
-
- @Test
- public void testLastFocusedStackIsUpdatedWhenMovingStack() {
- // Create a stack at bottom.
- final TaskDisplayArea taskDisplayAreas =
- mRootWindowContainer.getDefaultDisplay().getDefaultTaskDisplayArea();
- final Task stack =
- new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build();
- final Task prevFocusedStack = taskDisplayAreas.getFocusedRootTask();
-
- stack.moveToFront("moveStackToFront");
- // After moving the stack to front, the previous focused should be the last focused.
- assertTrue(stack.isFocusedRootTaskOnDisplay());
- assertEquals(prevFocusedStack, taskDisplayAreas.getLastFocusedRootTask());
-
- stack.moveToBack("moveStackToBack", null /* task */);
- // After moving the stack to back, the stack should be the last focused.
- assertEquals(stack, taskDisplayAreas.getLastFocusedRootTask());
- }
-
- /**
- * This test simulates the picture-in-picture menu activity launches an activity to fullscreen
- * stack. The fullscreen stack should be the top focused for resuming correctly.
- */
- @Test
- public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() {
- // Create a pinned stack and move to front.
- final Task pinnedStack = mRootWindowContainer.getDefaultTaskDisplayArea()
- .createRootTask(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task pinnedTask = new TaskBuilder(mAtm.mTaskSupervisor)
- .setParentTask(pinnedStack).build();
- new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
- .setTask(pinnedTask).build();
- pinnedStack.moveToFront("movePinnedStackToFront");
-
- // The focused stack should be the pinned stack.
- assertTrue(pinnedStack.isFocusedRootTaskOnDisplay());
-
- // Create a fullscreen stack and move to front.
- final Task fullscreenStack = createFullscreenStackWithSimpleActivityAt(
- mRootWindowContainer.getDefaultDisplay());
- fullscreenStack.moveToFront("moveFullscreenStackToFront");
-
- // The focused stack should be the fullscreen stack.
- assertTrue(fullscreenStack.isFocusedRootTaskOnDisplay());
- }
-
- /**
- * Test {@link TaskDisplayArea#mPreferredTopFocusableRootTask} will be cleared when
- * the stack is removed or moved to back, and the focused stack will be according to z-order.
- */
- @Test
- public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() {
- // Create a display which only contains 2 stacks.
- final DisplayContent display = addNewDisplayContentAt(POSITION_TOP);
- final Task stack1 = createFullscreenStackWithSimpleActivityAt(display);
- final Task stack2 = createFullscreenStackWithSimpleActivityAt(display);
-
- // Put stack1 and stack2 on top.
- stack1.moveToFront("moveStack1ToFront");
- stack2.moveToFront("moveStack2ToFront");
- assertTrue(stack2.isFocusedRootTaskOnDisplay());
-
- // Stack1 should be focused after moving stack2 to back.
- stack2.moveToBack("moveStack2ToBack", null /* task */);
- assertTrue(stack1.isFocusedRootTaskOnDisplay());
-
- // Stack2 should be focused after removing stack1.
- stack1.getDisplayArea().removeRootTask(stack1);
- assertTrue(stack2.isFocusedRootTaskOnDisplay());
- }
-
- /**
- * Verifies {@link DisplayContent#remove} should not resume home stack on the removing display.
- */
- @Test
- public void testNotResumeHomeStackOnRemovingDisplay() {
- // Create a display which supports system decoration and allows reparenting stacks to
- // another display when the display is removed.
- final DisplayContent display = new TestDisplayContent.Builder(
- mAtm, 1000, 1500).setSystemDecorations(true).build();
- doReturn(false).when(display).shouldDestroyContentOnRemove();
-
- // Put home stack on the display.
- final Task homeStack = new TaskBuilder(mSupervisor)
- .setDisplay(display).setActivityType(ACTIVITY_TYPE_HOME).build();
-
- // Put a finishing standard activity which will be reparented.
- final Task stack = createFullscreenStackWithSimpleActivityAt(display);
- stack.topRunningActivity().makeFinishingLocked();
-
- clearInvocations(homeStack);
- display.remove();
-
- // The removed display should have no focused stack and its home stack should never resume.
- assertNull(display.getFocusedRootTask());
- verify(homeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
- }
-
- private Task createFullscreenStackWithSimpleActivityAt(DisplayContent display) {
- final Task fullscreenStack = display.getDefaultTaskDisplayArea().createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task fullscreenTask = new TaskBuilder(mAtm.mTaskSupervisor)
- .setParentTask(fullscreenStack).build();
- new ActivityBuilder(mAtm).setTask(fullscreenTask).build();
- return fullscreenStack;
- }
-
- /**
- * Verifies the correct activity is returned when querying the top running activity.
- */
- @Test
- public void testTopRunningActivity() {
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final KeyguardController keyguard = mSupervisor.getKeyguardController();
- final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
- final ActivityRecord activity = stack.getTopNonFinishingActivity();
-
- // Create empty stack on top.
- final Task emptyStack = new TaskBuilder(mSupervisor).build();
-
- // Make sure the top running activity is not affected when keyguard is not locked.
- assertTopRunningActivity(activity, display);
-
- // Check to make sure activity not reported when it cannot show on lock and lock is on.
- doReturn(true).when(keyguard).isKeyguardLocked();
- assertEquals(activity, display.topRunningActivity());
- assertNull(display.topRunningActivity(true /* considerKeyguardState */));
-
- // Move stack with activity to top.
- stack.moveToFront("testStackToFront");
- assertEquals(stack, display.getFocusedRootTask());
- assertEquals(activity, display.topRunningActivity());
- assertNull(display.topRunningActivity(true /* considerKeyguardState */));
-
- // Add activity that should be shown on the keyguard.
- final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mAtm)
- .setTask(stack)
- .setActivityFlags(FLAG_SHOW_WHEN_LOCKED)
- .build();
-
- // Ensure the show when locked activity is returned.
- assertTopRunningActivity(showWhenLockedActivity, display);
-
- // Move empty stack to front. The running activity in focusable stack which below the
- // empty stack should be returned.
- emptyStack.moveToFront("emptyStackToFront");
- assertEquals(stack, display.getFocusedRootTask());
- assertTopRunningActivity(showWhenLockedActivity, display);
- }
-
- private static void assertTopRunningActivity(ActivityRecord top, DisplayContent display) {
- assertEquals(top, display.topRunningActivity());
- assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */));
- }
-
- /**
- * This test enforces that alwaysOnTop stack is placed at proper position.
- */
- @Test
- public void testAlwaysOnTopStackLocation() {
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task alwaysOnTopStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM,
- ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(alwaysOnTopStack).build();
- alwaysOnTopStack.setAlwaysOnTop(true);
- taskDisplayArea.positionChildAt(POSITION_TOP, alwaysOnTopStack,
- false /* includingParents */);
- assertTrue(alwaysOnTopStack.isAlwaysOnTop());
- // Ensure always on top state is synced to the children of the stack.
- assertTrue(alwaysOnTopStack.getTopNonFinishingActivity().isAlwaysOnTop());
- assertEquals(alwaysOnTopStack, taskDisplayArea.getTopRootTask());
-
- final Task pinnedStack = taskDisplayArea.createRootTask(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- assertEquals(pinnedStack, taskDisplayArea.getRootPinnedTask());
- assertEquals(pinnedStack, taskDisplayArea.getTopRootTask());
-
- final Task anotherAlwaysOnTopStack = taskDisplayArea.createRootTask(
- WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- anotherAlwaysOnTopStack.setAlwaysOnTop(true);
- taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack,
- false /* includingParents */);
- assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
- int topPosition = taskDisplayArea.getRootTaskCount() - 1;
- // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
- // existing alwaysOnTop stack.
- assertEquals(topPosition - 1, getTaskIndexOf(taskDisplayArea, anotherAlwaysOnTopStack));
-
- final Task nonAlwaysOnTopStack = taskDisplayArea.createRootTask(
- WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- assertEquals(taskDisplayArea, nonAlwaysOnTopStack.getDisplayArea());
- topPosition = taskDisplayArea.getRootTaskCount() - 1;
- // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
- // existing other non-alwaysOnTop stacks.
- assertEquals(topPosition - 3, getTaskIndexOf(taskDisplayArea, nonAlwaysOnTopStack));
-
- anotherAlwaysOnTopStack.setAlwaysOnTop(false);
- taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack,
- false /* includingParents */);
- assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
- // Ensure, when always on top is turned off for a stack, the stack is put just below all
- // other always on top stacks.
- assertEquals(topPosition - 2, getTaskIndexOf(taskDisplayArea, anotherAlwaysOnTopStack));
- anotherAlwaysOnTopStack.setAlwaysOnTop(true);
-
- // Ensure always on top state changes properly when windowing mode changes.
- anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
- assertEquals(topPosition - 2, getTaskIndexOf(taskDisplayArea, anotherAlwaysOnTopStack));
- anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
- assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
- assertEquals(topPosition - 1, getTaskIndexOf(taskDisplayArea, anotherAlwaysOnTopStack));
-
- final Task dreamStack = taskDisplayArea.createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM, true /* onTop */);
- assertEquals(taskDisplayArea, dreamStack.getDisplayArea());
- assertTrue(dreamStack.isAlwaysOnTop());
- topPosition = taskDisplayArea.getRootTaskCount() - 1;
- // Ensure dream shows above all activities, including PiP
- assertEquals(dreamStack, taskDisplayArea.getTopRootTask());
- assertEquals(topPosition - 1, getTaskIndexOf(taskDisplayArea, pinnedStack));
-
- final Task assistStack = taskDisplayArea.createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
- assertEquals(taskDisplayArea, assistStack.getDisplayArea());
- assertFalse(assistStack.isAlwaysOnTop());
- topPosition = taskDisplayArea.getRootTaskCount() - 1;
-
- // Ensure Assistant shows as a non-always-on-top activity when config_assistantOnTopOfDream
- // is false and on top of everything when true.
- final boolean isAssistantOnTop = mContext.getResources()
- .getBoolean(com.android.internal.R.bool.config_assistantOnTopOfDream);
- assertEquals(isAssistantOnTop ? topPosition : topPosition - 4,
- getTaskIndexOf(taskDisplayArea, assistStack));
- }
-
- @Test
- public void testRemoveRootTaskInWindowingModes() {
- removeStackTests(() -> mRootWindowContainer.removeRootTasksInWindowingModes(
- WINDOWING_MODE_FULLSCREEN));
- }
-
- @Test
- public void testRemoveStackWithActivityTypes() {
- removeStackTests(() -> mRootWindowContainer.removeRootTasksWithActivityTypes(
- ACTIVITY_TYPE_STANDARD));
- }
-
- private void removeStackTests(Runnable runnable) {
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task stack1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task stack2 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task stack3 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task stack4 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task task1 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(stack1).build();
- final Task task2 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(stack2).build();
- final Task task3 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(stack3).build();
- final Task task4 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(stack4).build();
-
- // Reordering stacks while removing stacks.
- doAnswer(invocation -> {
- taskDisplayArea.positionChildAt(POSITION_TOP, stack3, false /*includingParents*/);
- return true;
- }).when(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
-
- // Removing stacks from the display while removing stacks.
- doAnswer(invocation -> {
- taskDisplayArea.removeRootTask(stack2);
- return true;
- }).when(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
-
- runnable.run();
- verify(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
- verify(mSupervisor).removeTask(eq(task3), anyBoolean(), anyBoolean(), any());
- verify(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
- verify(mSupervisor).removeTask(eq(task1), anyBoolean(), anyBoolean(), any());
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index ce5fc4021eac..678defe36566 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -405,7 +405,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
public void testGetAnimationTargets_taskContainsMultipleTasks() {
// [DisplayContent] - [Task] -+- [Task1] - [ActivityRecord1] (opening, invisible)
// +- [Task2] - [ActivityRecord2] (closing, visible)
- final Task parentTask = createTaskStackOnDisplay(mDisplayContent);
+ final Task parentTask = createTask(mDisplayContent);
final ActivityRecord activity1 = createActivityRecordWithParentTask(parentTask);
activity1.setVisible(false);
activity1.mVisibleRequested = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 83aca5e2d482..c3279bf05737 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -177,13 +177,13 @@ public class AppTransitionTests extends WindowTestsBase {
}
@Test
- public void testCleanAppTransitionWhenTaskStackReparent() {
+ public void testCleanAppTransitionWhenRootTaskReparent() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
final DisplayContent dc2 = createNewDisplay(Display.STATE_ON);
- final Task stack1 = createTaskStackOnDisplay(dc1);
- final Task task1 = createTaskInStack(stack1, 0 /* userId */);
+ final Task rootTask1 = createTask(dc1);
+ final Task task1 = createTaskInRootTask(rootTask1, 0 /* userId */);
final ActivityRecord activity1 = createNonAttachedActivityRecord(dc1);
task1.addChild(activity1, 0);
@@ -198,8 +198,8 @@ public class AppTransitionTests extends WindowTestsBase {
dc1.mOpeningApps.add(activity1);
assertTrue(dc1.mOpeningApps.size() > 0);
- // Move stack to another display.
- stack1.reparent(dc2.getDefaultTaskDisplayArea(), true);
+ // Move root task to another display.
+ rootTask1.reparent(dc2.getDefaultTaskDisplayArea(), true);
// Verify if token are cleared from both pending transition list in former display.
assertFalse(dc1.mOpeningApps.contains(activity1));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 24b4f65f65ff..0afd39f1ed01 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -16,10 +16,12 @@
package com.android.server.wm;
+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_PINNED;
+import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -65,6 +67,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
@@ -350,29 +353,29 @@ public class DisplayContentTests extends WindowTestsBase {
}
/**
- * This tests stack movement between displays and proper stack's, task's and app token's display
- * container references updates.
+ * This tests root task movement between displays and proper root task's, task's and app token's
+ * display container references updates.
*/
@Test
- public void testMoveStackBetweenDisplays() {
+ public void testMoveRootTaskBetweenDisplays() {
// Create a second display.
final DisplayContent dc = createNewDisplay();
- // Add stack with activity.
- final Task stack = createTaskStackOnDisplay(dc);
- assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
- assertEquals(dc, stack.getDisplayContent());
+ // Add root task with activity.
+ final Task rootTask = createTask(dc);
+ assertEquals(dc.getDisplayId(), rootTask.getDisplayContent().getDisplayId());
+ assertEquals(dc, rootTask.getDisplayContent());
- final Task task = createTaskInStack(stack, 0 /* userId */);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
final ActivityRecord activity = createNonAttachedActivityRecord(dc);
task.addChild(activity, 0);
assertEquals(dc, task.getDisplayContent());
assertEquals(dc, activity.getDisplayContent());
- // Move stack to first display.
- stack.reparent(mDisplayContent.getDefaultTaskDisplayArea(), true /* onTop */);
- assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
- assertEquals(mDisplayContent, stack.getDisplayContent());
+ // Move root task to first display.
+ rootTask.reparent(mDisplayContent.getDefaultTaskDisplayArea(), true /* onTop */);
+ assertEquals(mDisplayContent.getDisplayId(), rootTask.getDisplayContent().getDisplayId());
+ assertEquals(mDisplayContent, rootTask.getDisplayContent());
assertEquals(mDisplayContent, task.getDisplayContent());
assertEquals(mDisplayContent, activity.getDisplayContent());
}
@@ -424,7 +427,7 @@ public class DisplayContentTests extends WindowTestsBase {
}
/**
- * Tests tapping on a stack in different display results in window gaining focus.
+ * Tests tapping on a root task in different display results in window gaining focus.
*/
@Test
public void testInputEventBringsCorrectDisplayInFocus() {
@@ -432,16 +435,16 @@ public class DisplayContentTests extends WindowTestsBase {
// Create a second display
final DisplayContent dc1 = createNewDisplay();
- // Add stack with activity.
- final Task stack0 = createTaskStackOnDisplay(dc0);
- final Task task0 = createTaskInStack(stack0, 0 /* userId */);
+ // Add root task with activity.
+ final Task rootTask0 = createTask(dc0);
+ final Task task0 = createTaskInRootTask(rootTask0, 0 /* userId */);
final ActivityRecord activity = createNonAttachedActivityRecord(dc0);
task0.addChild(activity, 0);
dc0.configureDisplayPolicy();
assertNotNull(dc0.mTapDetector);
- final Task stack1 = createTaskStackOnDisplay(dc1);
- final Task task1 = createTaskInStack(stack1, 0 /* userId */);
+ final Task rootTask1 = createTask(dc1);
+ final Task task1 = createTaskInRootTask(rootTask1, 0 /* userId */);
final ActivityRecord activity1 = createNonAttachedActivityRecord(dc0);
task1.addChild(activity1, 0);
dc1.configureDisplayPolicy();
@@ -889,13 +892,13 @@ public class DisplayContentTests extends WindowTestsBase {
final DisplayContent newDisplay = createNewDisplay();
final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
- final Task stack = mDisplayContent.getTopRootTask();
- final ActivityRecord activity = stack.topRunningActivity();
+ final Task rootTask = mDisplayContent.getTopRootTask();
+ final ActivityRecord activity = rootTask.topRunningActivity();
doReturn(true).when(activity).shouldBeVisibleUnchecked();
final WindowState appWin1 = createWindow(null, TYPE_APPLICATION, newDisplay, "appWin1");
- final Task stack1 = newDisplay.getTopRootTask();
- final ActivityRecord activity1 = stack1.topRunningActivity();
+ final Task rootTask1 = newDisplay.getTopRootTask();
+ final ActivityRecord activity1 = rootTask1.topRunningActivity();
doReturn(true).when(activity1).shouldBeVisibleUnchecked();
appWin.setHasSurface(true);
appWin1.setHasSurface(true);
@@ -934,28 +937,28 @@ public class DisplayContentTests extends WindowTestsBase {
dc.getDisplayRotation().setFixedToUserRotation(
IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
- final Task stack = new TaskBuilder(mSupervisor)
+ final Task rootTask = new TaskBuilder(mSupervisor)
.setDisplay(dc)
.setCreateActivity(true)
.build();
- doReturn(true).when(stack).isVisible();
+ doReturn(true).when(rootTask).isVisible();
- final Task freeformStack = new TaskBuilder(mSupervisor)
+ final Task freeformRootTask = new TaskBuilder(mSupervisor)
.setDisplay(dc)
.setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FREEFORM)
.build();
- doReturn(true).when(freeformStack).isVisible();
- freeformStack.getTopChild().setBounds(100, 100, 300, 400);
+ doReturn(true).when(freeformRootTask).isVisible();
+ freeformRootTask.getTopChild().setBounds(100, 100, 300, 400);
assertTrue(dc.getDefaultTaskDisplayArea().isRootTaskVisible(WINDOWING_MODE_FREEFORM));
- freeformStack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- stack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ freeformRootTask.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ rootTask.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertEquals(SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
- stack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- freeformStack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ rootTask.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ freeformRootTask.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
}
@@ -1683,66 +1686,6 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
- public void testGetOrCreateRootHomeTask_defaultDisplay() {
- TaskDisplayArea defaultTaskDisplayArea = mWm.mRoot.getDefaultTaskDisplayArea();
-
- // Remove the current home stack if it exists so a new one can be created below.
- Task homeTask = defaultTaskDisplayArea.getRootHomeTask();
- if (homeTask != null) {
- defaultTaskDisplayArea.removeChild(homeTask);
- }
- assertNull(defaultTaskDisplayArea.getRootHomeTask());
-
- assertNotNull(defaultTaskDisplayArea.getOrCreateRootHomeTask());
- }
-
- @Test
- public void testGetOrCreateRootHomeTask_supportedSecondaryDisplay() {
- DisplayContent display = createNewDisplay();
- doReturn(true).when(display).supportsSystemDecorations();
-
- // Remove the current home stack if it exists so a new one can be created below.
- TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
- Task homeTask = taskDisplayArea.getRootHomeTask();
- if (homeTask != null) {
- taskDisplayArea.removeChild(homeTask);
- }
- assertNull(taskDisplayArea.getRootHomeTask());
-
- assertNotNull(taskDisplayArea.getOrCreateRootHomeTask());
- }
-
- @Test
- public void testGetOrCreateRootHomeTask_unsupportedSystemDecorations() {
- DisplayContent display = createNewDisplay();
- TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
- doReturn(false).when(display).supportsSystemDecorations();
-
- assertNull(taskDisplayArea.getRootHomeTask());
- assertNull(taskDisplayArea.getOrCreateRootHomeTask());
- }
-
- @Test
- public void testGetOrCreateRootHomeTask_untrustedDisplay() {
- DisplayContent display = createNewDisplay();
- TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
- doReturn(false).when(display).isTrusted();
-
- assertNull(taskDisplayArea.getRootHomeTask());
- assertNull(taskDisplayArea.getOrCreateRootHomeTask());
- }
-
- @Test
- public void testGetOrCreateRootHomeTask_dontMoveToTop() {
- DisplayContent display = createNewDisplay();
- display.mDontMoveToTop = true;
- TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
-
- assertNull(taskDisplayArea.getRootHomeTask());
- assertNull(taskDisplayArea.getOrCreateRootHomeTask());
- }
-
- @Test
public void testValidWindowingLayer() {
final SurfaceControl windowingLayer = mDisplayContent.getWindowingLayer();
assertNotNull(windowingLayer);
@@ -1761,8 +1704,8 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testFindScrollCaptureTargetWindow_behindWindow() {
DisplayContent display = createNewDisplay();
- Task stack = createTaskStackOnDisplay(display);
- Task task = createTaskInStack(stack, 0 /* userId */);
+ Task rootTask = createTask(display);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
WindowState activityWindow = createAppWindow(task, TYPE_APPLICATION, "App Window");
WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot");
@@ -1774,8 +1717,8 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testFindScrollCaptureTargetWindow_cantReceiveKeys() {
DisplayContent display = createNewDisplay();
- Task stack = createTaskStackOnDisplay(display);
- Task task = createTaskInStack(stack, 0 /* userId */);
+ Task rootTask = createTask(display);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
WindowState activityWindow = createAppWindow(task, TYPE_APPLICATION, "App Window");
WindowState invisible = createWindow(null, TYPE_APPLICATION, "invisible");
invisible.mViewVisibility = View.INVISIBLE; // make canReceiveKeys return false
@@ -1788,8 +1731,8 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testFindScrollCaptureTargetWindow_taskId() {
DisplayContent display = createNewDisplay();
- Task stack = createTaskStackOnDisplay(display);
- Task task = createTaskInStack(stack, 0 /* userId */);
+ Task rootTask = createTask(display);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
WindowState window = createAppWindow(task, TYPE_APPLICATION, "App Window");
WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot");
@@ -1800,8 +1743,8 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testFindScrollCaptureTargetWindow_taskIdCantReceiveKeys() {
DisplayContent display = createNewDisplay();
- Task stack = createTaskStackOnDisplay(display);
- Task task = createTaskInStack(stack, 0 /* userId */);
+ Task rootTask = createTask(display);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
WindowState window = createAppWindow(task, TYPE_APPLICATION, "App Window");
window.mViewVisibility = View.INVISIBLE; // make canReceiveKeys return false
WindowState behindWindow = createWindow(null, TYPE_SCREENSHOT, display, "Screenshot");
@@ -1828,7 +1771,7 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testSetWindowingModeAtomicallyUpdatesWindoingModeAndDisplayWindowingMode() {
final DisplayContent dc = createNewDisplay();
- final Task stack = new TaskBuilder(mSupervisor)
+ final Task rootTask = new TaskBuilder(mSupervisor)
.setDisplay(dc)
.build();
doAnswer(invocation -> {
@@ -1837,7 +1780,7 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(config.windowConfiguration.getWindowingMode(),
config.windowConfiguration.getDisplayWindowingMode());
return null;
- }).when(stack).onConfigurationChanged(any());
+ }).when(rootTask).onConfigurationChanged(any());
dc.setWindowingMode(WINDOWING_MODE_FREEFORM);
dc.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
@@ -2072,6 +2015,130 @@ public class DisplayContentTests extends WindowTestsBase {
0 /* delta */);
}
+ /**
+ * Verifies {@link DisplayContent#remove} should not resume home root task on the removing
+ * display.
+ */
+ @Test
+ public void testNotResumeHomeRootTaskOnRemovingDisplay() {
+ // Create a display which supports system decoration and allows reparenting root tasks to
+ // another display when the display is removed.
+ final DisplayContent display = new TestDisplayContent.Builder(
+ mAtm, 1000, 1500).setSystemDecorations(true).build();
+ doReturn(false).when(display).shouldDestroyContentOnRemove();
+
+ // Put home root task on the display.
+ final Task homeRootTask = new TaskBuilder(mSupervisor)
+ .setDisplay(display).setActivityType(ACTIVITY_TYPE_HOME).build();
+
+ // Put a finishing standard activity which will be reparented.
+ final Task rootTask = createTaskWithActivity(display.getDefaultTaskDisplayArea(),
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP, true /* twoLevelTask */);
+ rootTask.topRunningActivity().makeFinishingLocked();
+
+ clearInvocations(homeRootTask);
+ display.remove();
+
+ // The removed display should have no focused root task and its home root task should never
+ // resume.
+ assertNull(display.getFocusedRootTask());
+ verify(homeRootTask, never()).resumeTopActivityUncheckedLocked(any(), any());
+ }
+
+ /**
+ * Verifies the correct activity is returned when querying the top running activity.
+ */
+ @Test
+ public void testTopRunningActivity() {
+ final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
+ final KeyguardController keyguard = mSupervisor.getKeyguardController();
+ final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
+ final ActivityRecord activity = rootTask.getTopNonFinishingActivity();
+
+ // Create empty root task on top.
+ final Task emptyRootTask = new TaskBuilder(mSupervisor).build();
+
+ // Make sure the top running activity is not affected when keyguard is not locked.
+ assertTopRunningActivity(activity, display);
+
+ // Check to make sure activity not reported when it cannot show on lock and lock is on.
+ doReturn(true).when(keyguard).isKeyguardLocked();
+ assertEquals(activity, display.topRunningActivity());
+ assertNull(display.topRunningActivity(true /* considerKeyguardState */));
+
+ // Move root task with activity to top.
+ rootTask.moveToFront("testRootTaskToFront");
+ assertEquals(rootTask, display.getFocusedRootTask());
+ assertEquals(activity, display.topRunningActivity());
+ assertNull(display.topRunningActivity(true /* considerKeyguardState */));
+
+ // Add activity that should be shown on the keyguard.
+ final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mAtm)
+ .setTask(rootTask)
+ .setActivityFlags(FLAG_SHOW_WHEN_LOCKED)
+ .build();
+
+ // Ensure the show when locked activity is returned.
+ assertTopRunningActivity(showWhenLockedActivity, display);
+
+ // Move empty root task to front. The running activity in focusable root task which below
+ // the empty root task should be returned.
+ emptyRootTask.moveToFront("emptyRootTaskToFront");
+ assertEquals(rootTask, display.getFocusedRootTask());
+ assertTopRunningActivity(showWhenLockedActivity, display);
+ }
+
+ private static void assertTopRunningActivity(ActivityRecord top, DisplayContent display) {
+ assertEquals(top, display.topRunningActivity());
+ assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */));
+ }
+
+ @Test
+ public void testRemoveRootTaskInWindowingModes() {
+ removeRootTaskTests(() -> mRootWindowContainer.removeRootTasksInWindowingModes(
+ WINDOWING_MODE_FULLSCREEN));
+ }
+
+ @Test
+ public void testRemoveRootTaskWithActivityTypes() {
+ removeRootTaskTests(() -> mRootWindowContainer.removeRootTasksWithActivityTypes(
+ ACTIVITY_TYPE_STANDARD));
+ }
+
+ private void removeRootTaskTests(Runnable runnable) {
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final Task rootTask2 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final Task rootTask3 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final Task rootTask4 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final Task task1 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask1).build();
+ final Task task2 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask2).build();
+ final Task task3 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask3).build();
+ final Task task4 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask4).build();
+
+ // Reordering root tasks while removing root tasks.
+ doAnswer(invocation -> {
+ taskDisplayArea.positionChildAt(POSITION_TOP, rootTask3, false /*includingParents*/);
+ return true;
+ }).when(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
+
+ // Removing root tasks from the display while removing root tasks.
+ doAnswer(invocation -> {
+ taskDisplayArea.removeRootTask(rootTask2);
+ return true;
+ }).when(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
+
+ runnable.run();
+ verify(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
+ verify(mSupervisor).removeTask(eq(task3), anyBoolean(), anyBoolean(), any());
+ verify(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
+ verify(mSupervisor).removeTask(eq(task1), anyBoolean(), anyBoolean(), any());
+ }
+
private boolean isOptionsPanelAtRight(int displayId) {
return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 4e2697ab64f8..1bddd7b4ef64 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -17,8 +17,6 @@
package com.android.server.wm;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
@@ -124,9 +122,8 @@ public class DragDropControllerTests extends WindowTestsBase {
*/
private WindowState createDropTargetWindow(String name, int ownerId) {
final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
- final Task stack = createTaskStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task task = createTaskInStack(stack, ownerId);
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, ownerId);
task.addChild(activity, 0);
// Use a new TestIWindow so we don't collect events for other windows
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index f97e79444d59..7d137bcb2cff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -488,9 +488,9 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
@Test
public void testIsAnimatingByRecents() {
final ActivityRecord homeActivity = createHomeActivity();
- final Task rootTask = createTaskStackOnDisplay(mDefaultDisplay);
- final Task childTask = createTaskInStack(rootTask, 0 /* userId */);
- final Task leafTask = createTaskInStack(childTask, 0 /* userId */);
+ final Task rootTask = createTask(mDefaultDisplay);
+ final Task childTask = createTaskInRootTask(rootTask, 0 /* userId */);
+ final Task leafTask = createTaskInRootTask(childTask, 0 /* userId */);
spyOn(leafTask);
doReturn(true).when(leafTask).isVisible();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
deleted file mode 100644
index 8388f2a6c6fa..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ /dev/null
@@ -1,953 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.TYPE_VIRTUAL;
-import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
-import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
-import static com.android.server.wm.Task.ActivityState.STOPPED;
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-
-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.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.contains;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.refEq;
-
-import android.app.ActivityOptions;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.platform.test.annotations.Presubmit;
-import android.util.MergedConfiguration;
-import android.util.Pair;
-
-import androidx.test.filters.MediumTest;
-
-import com.android.internal.app.ResolverActivity;
-import com.android.server.wm.Task.ActivityState;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * Tests for the {@link RootWindowContainer} class.
- *
- * Build/Install/Run:
- * atest WmTests:RootActivityContainerTests
- */
-@MediumTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class RootActivityContainerTests extends WindowTestsBase {
-
- @Before
- public void setUp() throws Exception {
- doNothing().when(mAtm).updateSleepIfNeededLocked();
- }
-
- /**
- * This test ensures that we do not try to restore a task based off an invalid task id. We
- * should expect {@code null} to be returned in this case.
- */
- @Test
- public void testRestoringInvalidTask() {
- mRootWindowContainer.getDefaultDisplay().removeAllTasks();
- Task task = mRootWindowContainer.anyTaskForId(0 /*taskId*/,
- MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
- assertNull(task);
- }
-
- /**
- * This test ensures that an existing task in the pinned stack is moved to the fullscreen
- * activity stack when a new task is added.
- */
- @Test
- public void testReplacingTaskInPinnedStack() {
- Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
- .setTask(fullscreenTask).build();
- final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
- .setTask(fullscreenTask).build();
-
- fullscreenTask.moveToFront("testReplacingTaskInPinnedStack");
-
- // Ensure full screen stack has both tasks.
- ensureStackPlacement(fullscreenTask, firstActivity, secondActivity);
-
- // Move first activity to pinned stack.
- mRootWindowContainer.moveActivityToPinnedRootTask(firstActivity, "initialMove");
-
- final TaskDisplayArea taskDisplayArea = fullscreenTask.getDisplayArea();
- Task pinnedStack = taskDisplayArea.getRootPinnedTask();
- // Ensure a task has moved over.
- ensureStackPlacement(pinnedStack, firstActivity);
- ensureStackPlacement(fullscreenTask, secondActivity);
-
- // Move second activity to pinned stack.
- mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "secondMove");
-
- // Need to get stacks again as a new instance might have been created.
- pinnedStack = taskDisplayArea.getRootPinnedTask();
- fullscreenTask = taskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD);
- // Ensure stacks have swapped tasks.
- ensureStackPlacement(pinnedStack, secondActivity);
- ensureStackPlacement(fullscreenTask, firstActivity);
- }
-
- @Test
- public void testMovingBottomMostStackActivityToPinnedStack() {
- final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
- .setTask(fullscreenTask).build();
- final Task task = firstActivity.getTask();
-
- final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
- .setTask(fullscreenTask).build();
-
- fullscreenTask.moveTaskToBack(task);
-
- // Ensure full screen stack has both tasks.
- ensureStackPlacement(fullscreenTask, firstActivity, secondActivity);
- assertEquals(task.getTopMostActivity(), secondActivity);
- firstActivity.setState(STOPPED, "testMovingBottomMostStackActivityToPinnedStack");
-
-
- // Move first activity to pinned stack.
- mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "initialMove");
-
- assertTrue(firstActivity.mRequestForceTransition);
- }
-
- private static void ensureStackPlacement(Task task, ActivityRecord... activities) {
- final ArrayList<ActivityRecord> taskActivities = new ArrayList<>();
-
- task.forAllActivities((Consumer<ActivityRecord>) taskActivities::add, false);
-
- assertEquals("Expecting " + Arrays.deepToString(activities) + " got " + taskActivities,
- taskActivities.size(), activities != null ? activities.length : 0);
-
- if (activities == null) {
- return;
- }
-
- for (ActivityRecord activity : activities) {
- assertTrue(taskActivities.contains(activity));
- }
- }
-
- @Test
- public void testApplySleepTokens() {
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final KeyguardController keyguard = mSupervisor.getKeyguardController();
- final Task stack = new TaskBuilder(mSupervisor)
- .setDisplay(display)
- .setOnTop(false)
- .build();
-
- // Make sure we wake and resume in the case the display is turning on and the keyguard is
- // not showing.
- verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
- false /* displayShouldSleep */, true /* isFocusedStack */,
- false /* keyguardShowing */, true /* expectWakeFromSleep */,
- true /* expectResumeTopActivity */);
-
- // Make sure we wake and don't resume when the display is turning on and the keyguard is
- // showing.
- verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
- false /* displayShouldSleep */, true /* isFocusedStack */,
- true /* keyguardShowing */, true /* expectWakeFromSleep */,
- false /* expectResumeTopActivity */);
-
- // Make sure we wake and don't resume when the display is turning on and the keyguard is
- // not showing as unfocused.
- verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
- false /* displayShouldSleep */, false /* isFocusedStack */,
- false /* keyguardShowing */, true /* expectWakeFromSleep */,
- false /* expectResumeTopActivity */);
-
- // Should not do anything if the display state hasn't changed.
- verifySleepTokenBehavior(display, keyguard, stack, false /*displaySleeping*/,
- false /* displayShouldSleep */, true /* isFocusedStack */,
- false /* keyguardShowing */, false /* expectWakeFromSleep */,
- false /* expectResumeTopActivity */);
- }
-
- private void verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard,
- Task stack, boolean displaySleeping, boolean displayShouldSleep,
- boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep,
- boolean expectResumeTopActivity) {
- reset(stack);
-
- doReturn(displayShouldSleep).when(display).shouldSleep();
- doReturn(displaySleeping).when(display).isSleeping();
- doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt());
-
- doReturn(isFocusedStack).when(stack).isFocusedRootTaskOnDisplay();
- doReturn(isFocusedStack ? stack : null).when(display).getFocusedRootTask();
- TaskDisplayArea defaultTaskDisplayArea = display.getDefaultTaskDisplayArea();
- doReturn(isFocusedStack ? stack : null).when(defaultTaskDisplayArea).getFocusedRootTask();
- mRootWindowContainer.applySleepTokens(true);
- verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked();
- verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
- null /* target */, null /* targetOptions */);
- }
-
- @Test
- public void testAwakeFromSleepingWithAppConfiguration() {
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
- activity.moveFocusableActivityToTop("test");
- assertTrue(activity.getRootTask().isFocusedRootTaskOnDisplay());
- ActivityRecordTests.setRotatedScreenOrientationSilently(activity);
-
- final Configuration rotatedConfig = new Configuration();
- display.computeScreenConfiguration(rotatedConfig, display.getDisplayRotation()
- .rotationForOrientation(activity.getOrientation(), display.getRotation()));
- assertNotEquals(activity.getConfiguration().orientation, rotatedConfig.orientation);
- // Assume the activity was shown in different orientation. For example, the top activity is
- // landscape and the portrait lockscreen is shown.
- activity.setLastReportedConfiguration(
- new MergedConfiguration(mAtm.getGlobalConfiguration(), rotatedConfig));
- activity.setState(ActivityState.STOPPED, "sleep");
-
- display.setIsSleeping(true);
- doReturn(false).when(display).shouldSleep();
- // Allow to resume when awaking.
- setBooted(mAtm);
- mRootWindowContainer.applySleepTokens(true);
-
- // The display orientation should be changed by the activity so there is no relaunch.
- verify(activity, never()).relaunchActivityLocked(anyBoolean());
- assertEquals(rotatedConfig.orientation, display.getConfiguration().orientation);
- }
-
- /**
- * Verifies that removal of activity with task and stack is done correctly.
- */
- @Test
- public void testRemovingStackOnAppCrash() {
- final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
- .getDefaultTaskDisplayArea();
- final int originalStackCount = defaultTaskDisplayArea.getRootTaskCount();
- final Task stack = defaultTaskDisplayArea.createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(stack).build();
-
- assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getRootTaskCount());
-
- // Let's pretend that the app has crashed.
- firstActivity.app.setThread(null);
- mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
-
- // Verify that the stack was removed.
- assertEquals(originalStackCount, defaultTaskDisplayArea.getRootTaskCount());
- }
-
- /**
- * Verifies that removal of activities with task and stack is done correctly when there are
- * several task display areas.
- */
- @Test
- public void testRemovingStackOnAppCrash_multipleDisplayAreas() {
- final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
- .getDefaultTaskDisplayArea();
- final int originalStackCount = defaultTaskDisplayArea.getRootTaskCount();
- final Task stack = defaultTaskDisplayArea.createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(stack).build();
- assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getRootTaskCount());
-
- final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent();
- final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
- dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST);
- final Task secondStack = secondTaskDisplayArea.createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- new ActivityBuilder(mAtm).setTask(secondStack).setUseProcess(firstActivity.app).build();
- assertEquals(1, secondTaskDisplayArea.getRootTaskCount());
-
- // Let's pretend that the app has crashed.
- firstActivity.app.setThread(null);
- mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
-
- // Verify that the stacks were removed.
- assertEquals(originalStackCount, defaultTaskDisplayArea.getRootTaskCount());
- assertEquals(0, secondTaskDisplayArea.getRootTaskCount());
- }
-
- @Test
- public void testFocusability() {
- final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
- .getDefaultTaskDisplayArea();
- final Task stack = defaultTaskDisplayArea.createRootTask(
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
-
- // Created stacks are focusable by default.
- assertTrue(stack.isTopActivityFocusable());
- assertTrue(activity.isFocusable());
-
- // If the stack is made unfocusable, its activities should inherit that.
- stack.setFocusable(false);
- assertFalse(stack.isTopActivityFocusable());
- assertFalse(activity.isFocusable());
-
- final Task pinnedStack = defaultTaskDisplayArea.createRootTask(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
- .setTask(pinnedStack).build();
-
- // We should not be focusable when in pinned mode
- assertFalse(pinnedStack.isTopActivityFocusable());
- assertFalse(pinnedActivity.isFocusable());
-
- // Add flag forcing focusability.
- pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE;
-
- // Task with FLAG_ALWAYS_FOCUSABLE should be focusable.
- assertTrue(pinnedStack.isTopActivityFocusable());
- assertTrue(pinnedActivity.isFocusable());
- }
-
- /**
- * Verify that split-screen primary stack will be chosen if activity is launched that targets
- * split-screen secondary, but a matching existing instance is found on top of split-screen
- * primary stack.
- */
- @Test
- public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() {
- // Create primary split-screen stack with a task and an activity.
- final Task primaryStack = mRootWindowContainer.getDefaultTaskDisplayArea()
- .createRootTask(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task task = new TaskBuilder(mSupervisor).setParentTask(primaryStack).build();
- final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build();
-
- // Find a launch stack for the top activity in split-screen primary, while requesting
- // split-screen secondary.
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- final Task result =
- mRootWindowContainer.getLaunchRootTask(r, options, task, true /* onTop */);
-
- // Assert that the primary stack is returned.
- assertEquals(primaryStack, result);
- }
-
- /**
- * Verify that home stack would be moved to front when the top activity is Recents.
- */
- @Test
- public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
- // Create stack/task on default display.
- final Task targetStack = new TaskBuilder(mSupervisor)
- .setCreateActivity(true)
- .setOnTop(false)
- .build();
- final Task targetTask = targetStack.getBottomMostTask();
-
- // Create Recents on top of the display.
- final Task stack = new TaskBuilder(mSupervisor)
- .setCreateActivity(true)
- .setActivityType(ACTIVITY_TYPE_RECENTS)
- .build();
-
- final String reason = "findTaskToMoveToFront";
- mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
- false);
-
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- verify(taskDisplayArea).moveHomeRootTaskToFront(contains(reason));
- }
-
- /**
- * Verify that home stack won't be moved to front if the top activity on other display is
- * Recents.
- */
- @Test
- public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() {
- // Create tasks on default display.
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task targetRootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final Task targetTask = new TaskBuilder(mSupervisor).setParentTask(targetRootTask).build();
-
- // Create Recents on secondary display.
- final TestDisplayContent secondDisplay = addNewDisplayContentAt(
- DisplayContent.POSITION_TOP);
- final Task rootTask = secondDisplay.getDefaultTaskDisplayArea()
- .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */);
- new ActivityBuilder(mAtm).setTask(rootTask).build();
-
- final String reason = "findTaskToMoveToFront";
- mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
- false);
-
- verify(taskDisplayArea, never()).moveHomeRootTaskToFront(contains(reason));
- }
-
- /**
- * Verify if a stack is not at the topmost position, it should be able to resume its activity if
- * the stack is the top focused.
- */
- @Test
- public void testResumeActivityWhenNonTopmostStackIsTopFocused() {
- // Create a root task at bottom.
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, false /* onTop */));
- final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build();
- taskDisplayArea.positionChildAt(POSITION_BOTTOM, rootTask, false /*includingParents*/);
-
- // Assume the task is not at the topmost position (e.g. behind always-on-top stacks) but it
- // is the current top focused task.
- assertFalse(rootTask.isTopRootTaskInDisplayArea());
- doReturn(rootTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
-
- // Use the task as target to resume.
- mRootWindowContainer.resumeFocusedTasksTopActivities(
- rootTask, activity, null /* targetOptions */);
-
- // Verify the target task should resume its activity.
- verify(rootTask, times(1)).resumeTopActivityUncheckedLocked(
- eq(activity), eq(null /* targetOptions */));
- }
-
- /**
- * Verify that home activity will be started on a display even if another display has a
- * focusable activity.
- */
- @Test
- public void testResumeFocusedStacksStartsHomeActivity_NoActivities() {
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- taskDisplayArea.getRootHomeTask().removeIfPossible();
- taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
-
- doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
-
- mAtm.setBooted(true);
-
- // Trigger resume on all displays
- mRootWindowContainer.resumeFocusedTasksTopActivities();
-
- // Verify that home activity was started on the default display
- verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea));
- }
-
- /**
- * Verify that home activity will be started on a display even if another display has a
- * focusable activity.
- */
- @Test
- public void testResumeFocusedStacksStartsHomeActivity_ActivityOnSecondaryScreen() {
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- taskDisplayArea.getRootHomeTask().removeIfPossible();
- taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
-
- // Create an activity on secondary display.
- final TestDisplayContent secondDisplay = addNewDisplayContentAt(
- DisplayContent.POSITION_TOP);
- final Task rootTask = secondDisplay.getDefaultTaskDisplayArea().createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- new ActivityBuilder(mAtm).setTask(rootTask).build();
-
- doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
-
- mAtm.setBooted(true);
-
- // Trigger resume on all displays
- mRootWindowContainer.resumeFocusedTasksTopActivities();
-
- // Verify that home activity was started on the default display
- verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea));
- }
-
- /**
- * Verify that a lingering transition is being executed in case the activity to be resumed is
- * already resumed
- */
- @Test
- public void testResumeActivityLingeringTransition() {
- // Create a root task at top.
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, false /* onTop */));
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(rootTask).setOnTop(true).build();
- activity.setState(ActivityState.RESUMED, "test");
-
- // Assume the task is at the topmost position
- assertTrue(rootTask.isTopRootTaskInDisplayArea());
-
- // Use the task as target to resume.
- mRootWindowContainer.resumeFocusedTasksTopActivities();
-
- // Verify the lingering app transition is being executed because it's already resumed
- verify(rootTask, times(1)).executeAppTransition(any());
- }
-
- @Test
- public void testResumeActivityLingeringTransition_notExecuted() {
- // Create a root task at bottom.
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, false /* onTop */));
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setTask(rootTask).setOnTop(true).build();
- activity.setState(ActivityState.RESUMED, "test");
- taskDisplayArea.positionChildAt(POSITION_BOTTOM, rootTask, false /*includingParents*/);
-
- // Assume the task is at the topmost position
- assertFalse(rootTask.isTopRootTaskInDisplayArea());
- doReturn(rootTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
-
- // Use the task as target to resume.
- mRootWindowContainer.resumeFocusedTasksTopActivities();
-
- // Verify the lingering app transition is being executed because it's already resumed
- verify(rootTask, never()).executeAppTransition(any());
- }
-
- /**
- * Tests that home activities can be started on the displays that supports system decorations.
- */
- @Test
- public void testStartHomeOnAllDisplays() {
- mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
- mockResolveSecondaryHomeActivity();
-
- // Create secondary displays.
- final TestDisplayContent secondDisplay =
- new TestDisplayContent.Builder(mAtm, 1000, 1500)
- .setSystemDecorations(true).build();
-
- doReturn(true).when(mRootWindowContainer)
- .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
- doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
- anyBoolean());
-
- mRootWindowContainer.startHomeOnAllDisplays(0, "testStartHome");
-
- assertTrue(mRootWindowContainer.getDefaultDisplay().getTopRootTask().isActivityTypeHome());
- assertNotNull(secondDisplay.getTopRootTask());
- assertTrue(secondDisplay.getTopRootTask().isActivityTypeHome());
- }
-
- /**
- * Tests that home activities won't be started before booting when display added.
- */
- @Test
- public void testNotStartHomeBeforeBoot() {
- final int displayId = 1;
- final boolean isBooting = mAtm.mAmInternal.isBooting();
- final boolean isBooted = mAtm.mAmInternal.isBooted();
- try {
- mAtm.mAmInternal.setBooting(false);
- mAtm.mAmInternal.setBooted(false);
- mRootWindowContainer.onDisplayAdded(displayId);
- verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
- } finally {
- mAtm.mAmInternal.setBooting(isBooting);
- mAtm.mAmInternal.setBooted(isBooted);
- }
- }
-
- /**
- * Tests whether home can be started if being instrumented.
- */
- @Test
- public void testCanStartHomeWhenInstrumented() {
- final ActivityInfo info = new ActivityInfo();
- info.applicationInfo = new ApplicationInfo();
- final WindowProcessController app = mock(WindowProcessController.class);
- doReturn(app).when(mAtm).getProcessController(any(), anyInt());
-
- // Can not start home if we don't want to start home while home is being instrumented.
- doReturn(true).when(app).isInstrumenting();
- final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
- .getDefaultTaskDisplayArea();
- assertFalse(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
- false /* allowInstrumenting*/));
-
- // Can start home for other cases.
- assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
- true /* allowInstrumenting*/));
-
- doReturn(false).when(app).isInstrumenting();
- assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
- false /* allowInstrumenting*/));
- assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
- true /* allowInstrumenting*/));
- }
-
- /**
- * Tests that secondary home activity should not be resolved if device is still locked.
- */
- @Test
- public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() {
- // Create secondary displays.
- final TestDisplayContent secondDisplay =
- new TestDisplayContent.Builder(mAtm, 1000, 1500)
- .setSystemDecorations(true).build();
-
- // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false.
- final int currentUser = mRootWindowContainer.mCurrentUser;
- mRootWindowContainer.mCurrentUser = -1;
-
- mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
- secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
-
- try {
- verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any());
- } finally {
- mRootWindowContainer.mCurrentUser = currentUser;
- }
- }
-
- /**
- * Tests that secondary home activity should not be resolved if display does not support system
- * decorations.
- */
- @Test
- public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() {
- // Create secondary displays.
- final TestDisplayContent secondDisplay =
- new TestDisplayContent.Builder(mAtm, 1000, 1500)
- .setSystemDecorations(false).build();
-
- mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
- secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
-
- verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any());
- }
-
- /**
- * Tests that when starting {@link #ResolverActivity} for home, it should use the standard
- * activity type (in a new stack) so the order of back stack won't be broken.
- */
- @Test
- public void testStartResolverActivityForHome() {
- final ActivityInfo info = new ActivityInfo();
- info.applicationInfo = new ApplicationInfo();
- info.applicationInfo.packageName = "android";
- info.name = ResolverActivity.class.getName();
- doReturn(info).when(mRootWindowContainer).resolveHomeActivity(anyInt(), any());
-
- mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "test", DEFAULT_DISPLAY);
- final ActivityRecord resolverActivity = mRootWindowContainer.topRunningActivity();
-
- assertEquals(info, resolverActivity.info);
- assertEquals(ACTIVITY_TYPE_STANDARD, resolverActivity.getRootTask().getActivityType());
- }
-
- /**
- * Tests that secondary home should be selected if primary home not set.
- */
- @Test
- public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet() {
- // Setup: primary home not set.
- final Intent primaryHomeIntent = mAtm.getHomeIntent();
- final ActivityInfo aInfoPrimary = new ActivityInfo();
- aInfoPrimary.name = ResolverActivity.class.getName();
- doReturn(aInfoPrimary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
- refEq(primaryHomeIntent));
- // Setup: set secondary home.
- mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
-
- // Run the test.
- final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
- .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
- final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
- assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
- assertEquals(aInfoSecondary.applicationInfo.packageName,
- resolvedInfo.first.applicationInfo.packageName);
- }
-
- /**
- * Tests that the default secondary home activity is always picked when it is in forced by
- * config_useSystemProvidedLauncherForSecondary.
- */
- @Test
- public void testResolveSecondaryHomeActivityForced() {
- // SetUp: set primary home.
- mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
- // SetUp: set secondary home and force it.
- mockResolveHomeActivity(false /* primaryHome */, true /* forceSystemProvided */);
- final Intent secondaryHomeIntent =
- mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
- final List<ResolveInfo> resolutions = new ArrayList<>();
- final ResolveInfo resolveInfo = new ResolveInfo();
- final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
- resolveInfo.activityInfo = aInfoSecondary;
- resolutions.add(resolveInfo);
- doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(),
- refEq(secondaryHomeIntent));
- doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
- anyBoolean());
-
- // Run the test.
- final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
- .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
- assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
- assertEquals(aInfoSecondary.applicationInfo.packageName,
- resolvedInfo.first.applicationInfo.packageName);
- }
-
- /**
- * Tests that secondary home should be selected if primary home not support secondary displays
- * or there is no matched activity in the same package as selected primary home.
- */
- @Test
- public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSupportMultiDisplay() {
- // Setup: there is no matched activity in the same package as selected primary home.
- mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
- final List<ResolveInfo> resolutions = new ArrayList<>();
- doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
- // Setup: set secondary home.
- mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
-
- // Run the test.
- final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
- .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
- final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
- assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
- assertEquals(aInfoSecondary.applicationInfo.packageName,
- resolvedInfo.first.applicationInfo.packageName);
- }
- /**
- * Tests that primary home activity should be selected if it already support secondary displays.
- */
- @Test
- public void testResolveSecondaryHomeActivityWhenPrimaryHomeSupportMultiDisplay() {
- // SetUp: set primary home.
- mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
- // SetUp: put primary home info on 2nd item
- final List<ResolveInfo> resolutions = new ArrayList<>();
- final ResolveInfo infoFake1 = new ResolveInfo();
- infoFake1.activityInfo = new ActivityInfo();
- infoFake1.activityInfo.name = "fakeActivity1";
- infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
- infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
- final ResolveInfo infoFake2 = new ResolveInfo();
- final ActivityInfo aInfoPrimary = getFakeHomeActivityInfo(true /* primaryHome */);
- infoFake2.activityInfo = aInfoPrimary;
- resolutions.add(infoFake1);
- resolutions.add(infoFake2);
- doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
-
- doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
- anyBoolean());
-
- // Run the test.
- final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
- .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
- assertEquals(aInfoPrimary.name, resolvedInfo.first.name);
- assertEquals(aInfoPrimary.applicationInfo.packageName,
- resolvedInfo.first.applicationInfo.packageName);
- }
-
- /**
- * Tests that the first one that matches should be selected if there are multiple activities.
- */
- @Test
- public void testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay() {
- // SetUp: set primary home.
- mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
- // Setup: prepare two eligible activity info.
- final List<ResolveInfo> resolutions = new ArrayList<>();
- final ResolveInfo infoFake1 = new ResolveInfo();
- infoFake1.activityInfo = new ActivityInfo();
- infoFake1.activityInfo.name = "fakeActivity1";
- infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
- infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
- final ResolveInfo infoFake2 = new ResolveInfo();
- infoFake2.activityInfo = new ActivityInfo();
- infoFake2.activityInfo.name = "fakeActivity2";
- infoFake2.activityInfo.applicationInfo = new ApplicationInfo();
- infoFake2.activityInfo.applicationInfo.packageName = "fakePackage2";
- resolutions.add(infoFake1);
- resolutions.add(infoFake2);
- doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
-
- doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
- anyBoolean());
-
- // Use the first one of matched activities in the same package as selected primary home.
- final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
- .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
-
- assertEquals(infoFake1.activityInfo.applicationInfo.packageName,
- resolvedInfo.first.applicationInfo.packageName);
- assertEquals(infoFake1.activityInfo.name, resolvedInfo.first.name);
- }
-
- /**
- * Test that {@link RootWindowContainer#getLaunchRootTask} with the real caller id will get the
- * expected stack when requesting the activity launch on the secondary display.
- */
- @Test
- public void testGetLaunchStackWithRealCallerId() {
- // Create a non-system owned virtual display.
- final TestDisplayContent secondaryDisplay =
- new TestDisplayContent.Builder(mAtm, 1000, 1500)
- .setType(TYPE_VIRTUAL).setOwnerUid(100).build();
-
- // Create an activity with specify the original launch pid / uid.
- final ActivityRecord r = new ActivityBuilder(mAtm).setLaunchedFromPid(200)
- .setLaunchedFromUid(200).build();
-
- // Simulate ActivityStarter to find a launch stack for requesting the activity to launch
- // on the secondary display with realCallerId.
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchDisplayId(secondaryDisplay.mDisplayId);
- options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
- doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
- 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
- final Task result = mRootWindowContainer.getLaunchRootTask(r, options,
- null /* task */, true /* onTop */, null, 300 /* test realCallerPid */,
- 300 /* test realCallerUid */);
-
- // Assert that the stack is returned as expected.
- assertNotNull(result);
- assertEquals("The display ID of the stack should same as secondary display ",
- secondaryDisplay.mDisplayId, result.getDisplayId());
- }
-
- @Test
- public void testGetValidLaunchStackOnDisplayWithCandidateRootTask() {
- // Create a root task with an activity on secondary display.
- final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mAtm, 300,
- 600).build();
- final Task task = new TaskBuilder(mSupervisor)
- .setDisplay(secondaryDisplay).build();
- final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
-
- // Make sure the root task is valid and can be reused on default display.
- final Task stack = mRootWindowContainer.getValidLaunchRootTaskInTaskDisplayArea(
- mRootWindowContainer.getDefaultTaskDisplayArea(), activity, task,
- null /* options */, null /* launchParams */);
- assertEquals(task, stack);
- }
-
- @Test
- public void testSwitchUser_missingHomeRootTask() {
- final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- doReturn(fullscreenTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
-
- final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- Task homeStack = taskDisplayArea.getRootHomeTask();
- if (homeStack != null) {
- homeStack.removeImmediately();
- }
- assertNull(taskDisplayArea.getRootHomeTask());
-
- int currentUser = mRootWindowContainer.mCurrentUser;
- int otherUser = currentUser + 1;
-
- mRootWindowContainer.switchUser(otherUser, null);
-
- assertNotNull(taskDisplayArea.getRootHomeTask());
- assertEquals(taskDisplayArea.getTopRootTask(), taskDisplayArea.getRootHomeTask());
- }
-
- /**
- * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
- * info for test cases.
- *
- * @param primaryHome Indicate to use primary home intent as parameter, otherwise, use
- * secondary home intent.
- * @param forceSystemProvided Indicate to force using system provided home activity.
- */
- private void mockResolveHomeActivity(boolean primaryHome, boolean forceSystemProvided) {
- ActivityInfo targetActivityInfo = getFakeHomeActivityInfo(primaryHome);
- Intent targetIntent;
- if (primaryHome) {
- targetIntent = mAtm.getHomeIntent();
- } else {
- Resources resources = mContext.getResources();
- spyOn(resources);
- doReturn(targetActivityInfo.applicationInfo.packageName).when(resources).getString(
- com.android.internal.R.string.config_secondaryHomePackage);
- doReturn(forceSystemProvided).when(resources).getBoolean(
- com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
- targetIntent = mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
- }
- doReturn(targetActivityInfo).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
- refEq(targetIntent));
- }
-
- /**
- * Mock {@link RootWindowContainer#resolveSecondaryHomeActivity} for returning consistent
- * activity info for test cases.
- */
- private void mockResolveSecondaryHomeActivity() {
- final Intent secondaryHomeIntent = mAtm
- .getSecondaryHomeIntent(null /* preferredPackage */);
- final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false);
- doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer)
- .resolveSecondaryHomeActivity(anyInt(), any());
- }
-
- private ActivityInfo getFakeHomeActivityInfo(boolean primaryHome) {
- final ActivityInfo aInfo = new ActivityInfo();
- aInfo.name = primaryHome ? "fakeHomeActivity" : "fakeSecondaryHomeActivity";
- aInfo.applicationInfo = new ApplicationInfo();
- aInfo.applicationInfo.packageName =
- primaryHome ? "fakeHomePackage" : "fakeSecondaryHomePackage";
- return aInfo;
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 3a7954b3a5ce..748622b810d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.server.wm;
@@ -27,12 +27,14 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
@@ -49,6 +51,8 @@ import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.android.server.wm.TaskDisplayArea.getRootTaskAbove;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -56,26 +60,30 @@ import static com.google.common.truth.Truth.assertThat;
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.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
import android.app.ActivityManager;
import android.app.IApplicationThread;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import com.android.server.wm.TaskDisplayArea.OnRootTaskOrderChangedListener;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -84,15 +92,16 @@ import java.util.ArrayList;
import java.util.function.Consumer;
/**
- * Tests for the {@link ActivityStack} class.
+ * Tests for the root {@link Task} behavior.
*
* Build/Install/Run:
- * atest WmTests:ActivityStackTests
+ * atest WmTests:RootTaskTests
*/
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
-public class ActivityStackTests extends WindowTestsBase {
+public class RootTaskTests extends WindowTestsBase {
+
private TaskDisplayArea mDefaultTaskDisplayArea;
@Before
@@ -101,6 +110,172 @@ public class ActivityStackTests extends WindowTestsBase {
}
@Test
+ public void testRootTaskPositionChildAt() {
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task1 = createTaskInRootTask(rootTask, 0 /* userId */);
+ final Task task2 = createTaskInRootTask(rootTask, 1 /* userId */);
+
+ // Current user root task should be moved to top.
+ rootTask.positionChildAt(WindowContainer.POSITION_TOP, task1, false /* includingParents */);
+ assertEquals(rootTask.mChildren.get(0), task2);
+ assertEquals(rootTask.mChildren.get(1), task1);
+
+ // Non-current user won't be moved to top.
+ rootTask.positionChildAt(WindowContainer.POSITION_TOP, task2, false /* includingParents */);
+ assertEquals(rootTask.mChildren.get(0), task2);
+ assertEquals(rootTask.mChildren.get(1), task1);
+
+ // Non-leaf task should be moved to top regardless of the user id.
+ createTaskInRootTask(task2, 0 /* userId */);
+ createTaskInRootTask(task2, 1 /* userId */);
+ rootTask.positionChildAt(WindowContainer.POSITION_TOP, task2, false /* includingParents */);
+ assertEquals(rootTask.mChildren.get(0), task1);
+ assertEquals(rootTask.mChildren.get(1), task2);
+ }
+
+ @Test
+ public void testClosingAppDifferentTaskOrientation() {
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
+ activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
+ activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+ final WindowContainer parent = activity1.getTask().getParent();
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, parent.getOrientation());
+ mDisplayContent.mClosingApps.add(activity2);
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, parent.getOrientation());
+ }
+
+ @Test
+ public void testMoveTaskToBackDifferentTaskOrientation() {
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
+ activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
+ activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+ final WindowContainer parent = activity1.getTask().getParent();
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, parent.getOrientation());
+ }
+
+ @Test
+ public void testRootTaskRemoveImmediately() {
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ assertEquals(rootTask, task.getRootTask());
+
+ // Remove root task and check if its child is also removed.
+ rootTask.removeImmediately();
+ assertNull(rootTask.getDisplayContent());
+ assertNull(task.getParent());
+ }
+
+ @Test
+ public void testRemoveContainer() {
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+
+ assertNotNull(rootTask);
+ assertNotNull(task);
+ rootTask.removeIfPossible();
+ // Assert that the container was removed.
+ assertNull(rootTask.getParent());
+ assertEquals(0, rootTask.getChildCount());
+ assertNull(rootTask.getDisplayContent());
+ assertNull(task.getDisplayContent());
+ assertNull(task.getParent());
+ }
+
+ @Test
+ public void testRemoveContainer_deferRemoval() {
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+
+ // Root task removal is deferred if one of its child is animating.
+ doReturn(true).when(rootTask).hasWindowsAlive();
+ doReturn(rootTask).when(task).getAnimatingContainer(
+ eq(TRANSITION | CHILDREN), anyInt());
+
+ rootTask.removeIfPossible();
+ // For the case of deferred removal the task controller will still be connected to its
+ // container until the root task window container is removed.
+ assertNotNull(rootTask.getParent());
+ assertNotEquals(0, rootTask.getChildCount());
+ assertNotNull(task);
+
+ rootTask.removeImmediately();
+ // After removing, the task will be isolated.
+ assertNull(task.getParent());
+ assertEquals(0, task.getChildCount());
+ }
+
+ @Test
+ public void testReparent() {
+ // Create first root task on primary display.
+ final Task rootTask1 = createTask(mDisplayContent);
+ final Task task1 = createTaskInRootTask(rootTask1, 0 /* userId */);
+
+ // Create second display and put second root task on it.
+ final DisplayContent dc = createNewDisplay();
+ final Task rootTask2 = createTask(dc);
+
+ // Reparent
+ clearInvocations(task1); // reset the number of onDisplayChanged for task.
+ rootTask1.reparent(dc.getDefaultTaskDisplayArea(), true /* onTop */);
+ assertEquals(dc, rootTask1.getDisplayContent());
+ final int stack1PositionInParent = rootTask1.getParent().mChildren.indexOf(rootTask1);
+ final int stack2PositionInParent = rootTask1.getParent().mChildren.indexOf(rootTask2);
+ assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
+ verify(task1, times(1)).onDisplayChanged(any());
+ }
+
+ @Test
+ public void testTaskOutset() {
+ final Task task = createTask(mDisplayContent);
+ final int taskOutset = 10;
+ spyOn(task);
+ doReturn(taskOutset).when(task).getTaskOutset();
+ doReturn(true).when(task).inMultiWindowMode();
+
+ // Mock the resolved override windowing mode to non-fullscreen
+ final WindowConfiguration windowConfiguration =
+ task.getResolvedOverrideConfiguration().windowConfiguration;
+ spyOn(windowConfiguration);
+ doReturn(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
+ .when(windowConfiguration).getWindowingMode();
+
+ // Prevent adjust task dimensions
+ doNothing().when(task).adjustForMinimalTaskDimensions(any(), any(), any());
+
+ final Rect taskBounds = new Rect(200, 200, 800, 1000);
+ // Update surface position and size by the given bounds.
+ task.setBounds(taskBounds);
+
+ assertEquals(taskBounds.width() + 2 * taskOutset, task.getLastSurfaceSize().x);
+ assertEquals(taskBounds.height() + 2 * taskOutset, task.getLastSurfaceSize().y);
+ assertEquals(taskBounds.left - taskOutset, task.getLastSurfacePosition().x);
+ assertEquals(taskBounds.top - taskOutset, task.getLastSurfacePosition().y);
+ }
+
+ @Test
+ public void testActivityAndTaskGetsProperType() {
+ final Task task1 = new TaskBuilder(mSupervisor).build();
+ ActivityRecord activity1 = createNonAttachedActivityRecord(mDisplayContent);
+
+ // First activity should become standard
+ task1.addChild(activity1, 0);
+ assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, activity1.getActivityType());
+ assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType());
+
+ // Second activity should also become standard
+ ActivityRecord activity2 = createNonAttachedActivityRecord(mDisplayContent);
+ task1.addChild(activity2, WindowContainer.POSITION_TOP);
+ assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, activity2.getActivityType());
+ assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType());
+ }
+
+ @Test
public void testResumedActivity() {
final ActivityRecord r = new ActivityBuilder(mAtm).setCreateTask(true).build();
final Task task = r.getTask();
@@ -113,40 +288,40 @@ public class ActivityStackTests extends WindowTestsBase {
@Test
public void testResumedActivityFromTaskReparenting() {
- final Task parentTask = new TaskBuilder(mSupervisor).setOnTop(true).build();
+ final Task rootTask = new TaskBuilder(mSupervisor).setOnTop(true).build();
final ActivityRecord r = new ActivityBuilder(mAtm)
- .setCreateTask(true).setParentTask(parentTask).build();
+ .setCreateTask(true).setParentTask(rootTask).build();
final Task task = r.getTask();
- // Ensure moving task between two stacks updates resumed activity
+ // Ensure moving task between two root tasks updates resumed activity
r.setState(RESUMED, "testResumedActivityFromTaskReparenting");
- assertEquals(r, parentTask.getResumedActivity());
+ assertEquals(r, rootTask.getResumedActivity());
- final Task destStack = new TaskBuilder(mSupervisor).setOnTop(true).build();
- task.reparent(destStack, true /* toTop */, REPARENT_KEEP_ROOT_TASK_AT_FRONT,
+ final Task destRootTask = new TaskBuilder(mSupervisor).setOnTop(true).build();
+ task.reparent(destRootTask, true /* toTop */, REPARENT_KEEP_ROOT_TASK_AT_FRONT,
false /* animate */, true /* deferResume*/,
"testResumedActivityFromTaskReparenting");
- assertNull(parentTask.getResumedActivity());
- assertEquals(r, destStack.getResumedActivity());
+ assertNull(rootTask.getResumedActivity());
+ assertEquals(r, destRootTask.getResumedActivity());
}
@Test
public void testResumedActivityFromActivityReparenting() {
- final Task parentTask = new TaskBuilder(mSupervisor).setOnTop(true).build();
+ final Task rootTask = new TaskBuilder(mSupervisor).setOnTop(true).build();
final ActivityRecord r = new ActivityBuilder(mAtm)
- .setCreateTask(true).setParentTask(parentTask).build();
+ .setCreateTask(true).setParentTask(rootTask).build();
final Task task = r.getTask();
- // Ensure moving task between two stacks updates resumed activity
+ // Ensure moving task between two root tasks updates resumed activity
r.setState(RESUMED, "testResumedActivityFromActivityReparenting");
- assertEquals(r, parentTask.getResumedActivity());
+ assertEquals(r, rootTask.getResumedActivity());
- final Task destStack = new TaskBuilder(mSupervisor).setOnTop(true).build();
- task.reparent(destStack, true /*toTop*/, REPARENT_MOVE_ROOT_TASK_TO_FRONT,
+ final Task destRootTask = new TaskBuilder(mSupervisor).setOnTop(true).build();
+ task.reparent(destRootTask, true /*toTop*/, REPARENT_MOVE_ROOT_TASK_TO_FRONT,
false /* animate */, false /* deferResume*/,
"testResumedActivityFromActivityReparenting");
- assertNull(parentTask.getResumedActivity());
- assertEquals(r, destStack.getResumedActivity());
+ assertNull(rootTask.getResumedActivity());
+ assertEquals(r, destRootTask.getResumedActivity());
}
@Test
@@ -155,7 +330,7 @@ public class ActivityStackTests extends WindowTestsBase {
// We're testing an edge case here where we have primary + fullscreen rather than secondary.
organizer.setMoveToSecondaryOnEnter(false);
- // Create primary splitscreen stack.
+ // Create primary splitscreen root task.
final Task primarySplitScreen = new TaskBuilder(mAtm.mTaskSupervisor)
.setParentTask(organizer.mPrimary)
.setOnTop(true)
@@ -168,7 +343,7 @@ public class ActivityStackTests extends WindowTestsBase {
primarySplitScreen.moveToBack("testPrimarySplitScreenToFullscreenWhenMovedToBack",
null /* task */);
- // Assert that stack is at the bottom.
+ // Assert that root task is at the bottom.
assertEquals(0, getTaskIndexOf(mDefaultTaskDisplayArea, primarySplitScreen));
// Ensure no longer in splitscreen.
@@ -182,7 +357,7 @@ public class ActivityStackTests extends WindowTestsBase {
@Test
public void testMoveToPrimarySplitScreenThenMoveToBack() {
TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
- // This time, start with a fullscreen activitystack
+ // This time, start with a fullscreen activity root task.
final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -196,7 +371,7 @@ public class ActivityStackTests extends WindowTestsBase {
primarySplitScreen.moveToBack("testPrimarySplitScreenToFullscreenWhenMovedToBack",
null /* task */);
- // Assert that stack is at the bottom.
+ // Assert that root task is at the bottom.
assertEquals(primarySplitScreen, organizer.mSecondary.getChildAt(0));
// Ensure that the override mode is restored to what it was (fullscreen)
@@ -208,7 +383,7 @@ public class ActivityStackTests extends WindowTestsBase {
public void testSplitScreenMoveToBack() {
TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
// Explicitly reparent task to primary split root to enter split mode, in which implies
- // primary on top and secondary containing the home task below another stack.
+ // primary on top and secondary containing the home task below another root task.
final Task primaryTask = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task secondaryTask = mDefaultTaskDisplayArea.createRootTask(
@@ -244,24 +419,24 @@ public class ActivityStackTests extends WindowTestsBase {
}
@Test
- public void testRemoveOrganizedTask_UpdateStackReference() {
+ public void testRemoveOrganizedTask_UpdateRootTaskReference() {
final Task rootHomeTask = mDefaultTaskDisplayArea.getRootHomeTask();
final ActivityRecord homeActivity = new ActivityBuilder(mAtm)
.setTask(rootHomeTask)
.build();
- final Task secondaryStack = mAtm.mTaskOrganizerController.createRootTask(
+ final Task secondaryRootTask = mAtm.mTaskOrganizerController.createRootTask(
rootHomeTask.getDisplayContent(), WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
- rootHomeTask.reparent(secondaryStack, POSITION_TOP);
- assertEquals(secondaryStack, rootHomeTask.getParent());
+ rootHomeTask.reparent(secondaryRootTask, POSITION_TOP);
+ assertEquals(secondaryRootTask, rootHomeTask.getParent());
- // This should call to {@link TaskDisplayArea#removeStackReferenceIfNeeded}.
+ // This should call to {@link TaskDisplayArea#removeRootTaskReferenceIfNeeded}.
homeActivity.removeImmediately();
assertNull(mDefaultTaskDisplayArea.getRootHomeTask());
}
@Test
- public void testStackInheritsDisplayWindowingMode() {
+ public void testRootTaskInheritsDisplayWindowingMode() {
final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -276,7 +451,7 @@ public class ActivityStackTests extends WindowTestsBase {
}
@Test
- public void testStackOverridesDisplayWindowingMode() {
+ public void testRootTaskOverridesDisplayWindowingMode() {
final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -358,95 +533,92 @@ public class ActivityStackTests extends WindowTestsBase {
}
@Test
- public void testMoveStackToBackIncludingParent() {
+ public void testMoveRootTaskToBackIncludingParent() {
final TaskDisplayArea taskDisplayArea = addNewDisplayContentAt(DisplayContent.POSITION_TOP)
.getDefaultTaskDisplayArea();
- final Task stack1 = createStackForShouldBeVisibleTest(taskDisplayArea,
+ final Task rootTask1 = createTaskForShouldBeVisibleTest(taskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */,
true /* twoLevelTask */);
- final Task stack2 = createStackForShouldBeVisibleTest(taskDisplayArea,
+ final Task rootTask2 = createTaskForShouldBeVisibleTest(taskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */,
true /* twoLevelTask */);
- // Do not move display to back because there is still another stack.
- stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.getTopMostTask());
- verify(stack2).positionChildAtBottom(any(), eq(false) /* includingParents */);
+ // Do not move display to back because there is still another root task.
+ rootTask2.moveToBack("testMoveRootTaskToBackIncludingParent", rootTask2.getTopMostTask());
+ verify(rootTask2).positionChildAtBottom(any(), eq(false) /* includingParents */);
- // Also move display to back because there is only one stack left.
- taskDisplayArea.removeRootTask(stack1);
- stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.getTopMostTask());
- verify(stack2).positionChildAtBottom(any(), eq(true) /* includingParents */);
+ // Also move display to back because there is only one root task left.
+ taskDisplayArea.removeRootTask(rootTask1);
+ rootTask2.moveToBack("testMoveRootTaskToBackIncludingParent", rootTask2.getTopMostTask());
+ verify(rootTask2).positionChildAtBottom(any(), eq(true) /* includingParents */);
}
@Test
public void testShouldBeVisible_Fullscreen() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task pinnedRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- // Add an activity to the pinned stack so it isn't considered empty for visibility check.
+ // Add an activity to the pinned root task so it isn't considered empty for visibility
+ // check.
final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
- .setTask(pinnedStack)
+ .setTask(pinnedRootTask)
.build();
- assertTrue(homeStack.shouldBeVisible(null /* starting */));
- assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
-
- final Task fullscreenStack = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- // Home stack shouldn't be visible behind an opaque fullscreen stack, but pinned stack
- // should be visible since it is always on-top.
- doReturn(false).when(fullscreenStack).isTranslucent(any());
- assertFalse(homeStack.shouldBeVisible(null /* starting */));
- assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
- assertTrue(fullscreenStack.shouldBeVisible(null /* starting */));
+ assertTrue(homeRootTask.shouldBeVisible(null /* starting */));
+ assertTrue(pinnedRootTask.shouldBeVisible(null /* starting */));
- // Home stack should be visible behind a translucent fullscreen stack.
- doReturn(true).when(fullscreenStack).isTranslucent(any());
- assertTrue(homeStack.shouldBeVisible(null /* starting */));
- assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
+ final Task fullscreenRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ // Home root task shouldn't be visible behind an opaque fullscreen root task, but pinned
+ // root task should be visible since it is always on-top.
+ doReturn(false).when(fullscreenRootTask).isTranslucent(any());
+ assertFalse(homeRootTask.shouldBeVisible(null /* starting */));
+ assertTrue(pinnedRootTask.shouldBeVisible(null /* starting */));
+ assertTrue(fullscreenRootTask.shouldBeVisible(null /* starting */));
+
+ // Home root task should be visible behind a translucent fullscreen root task.
+ doReturn(true).when(fullscreenRootTask).isTranslucent(any());
+ assertTrue(homeRootTask.shouldBeVisible(null /* starting */));
+ assertTrue(pinnedRootTask.shouldBeVisible(null /* starting */));
}
@Test
public void testShouldBeVisible_SplitScreen() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- // Home stack should always be fullscreen for this test.
- doReturn(false).when(homeStack).supportsSplitScreenWindowingMode();
- final Task splitScreenPrimary =
- createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ // Home root task should always be fullscreen for this test.
+ doReturn(false).when(homeRootTask).supportsSplitScreenWindowingMode();
+ final Task splitScreenPrimary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task splitScreenSecondary =
- createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task splitScreenSecondary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- // Home stack shouldn't be visible if both halves of split-screen are opaque.
+ // Home root task shouldn't be visible if both halves of split-screen are opaque.
doReturn(false).when(splitScreenPrimary).isTranslucent(any());
doReturn(false).when(splitScreenSecondary).isTranslucent(any());
- assertFalse(homeStack.shouldBeVisible(null /* starting */));
+ assertFalse(homeRootTask.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
- assertEquals(TASK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE, homeRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- // Home stack should be visible if one of the halves of split-screen is translucent.
+ // Home root task should be visible if one of the halves of split-screen is translucent.
doReturn(true).when(splitScreenPrimary).isTranslucent(any());
- assertTrue(homeStack.shouldBeVisible(null /* starting */));
+ assertTrue(homeRootTask.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
- homeStack.getVisibility(null /* starting */));
+ homeRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- final Task splitScreenSecondary2 =
- createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task splitScreenSecondary2 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// First split-screen secondary shouldn't be visible behind another opaque split-split
// secondary.
@@ -468,18 +640,17 @@ public class ActivityStackTests extends WindowTestsBase {
assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
- final Task assistantStack = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT,
- true /* onTop */);
+ final Task assistantRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
- // Split-screen stacks shouldn't be visible behind an opaque fullscreen stack.
- doReturn(false).when(assistantStack).isTranslucent(any());
- assertTrue(assistantStack.shouldBeVisible(null /* starting */));
+ // Split-screen root tasks shouldn't be visible behind an opaque fullscreen root task.
+ doReturn(false).when(assistantRootTask).isTranslucent(any());
+ assertTrue(assistantRootTask.shouldBeVisible(null /* starting */));
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
- assistantStack.getVisibility(null /* starting */));
+ assistantRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_INVISIBLE,
@@ -487,14 +658,14 @@ public class ActivityStackTests extends WindowTestsBase {
assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
- // Split-screen stacks should be visible behind a translucent fullscreen stack.
- doReturn(true).when(assistantStack).isTranslucent(any());
- assertTrue(assistantStack.shouldBeVisible(null /* starting */));
+ // Split-screen root tasks should be visible behind a translucent fullscreen root task.
+ doReturn(true).when(assistantRootTask).isTranslucent(any());
+ assertTrue(assistantRootTask.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
- assistantStack.getVisibility(null /* starting */));
+ assistantRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenPrimary.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
@@ -502,20 +673,20 @@ public class ActivityStackTests extends WindowTestsBase {
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary2.getVisibility(null /* starting */));
- // Assistant stack shouldn't be visible behind translucent split-screen stack,
+ // Assistant root task shouldn't be visible behind translucent split-screen root task,
// unless it is configured to show on top of everything.
- doReturn(false).when(assistantStack).isTranslucent(any());
+ doReturn(false).when(assistantRootTask).isTranslucent(any());
doReturn(true).when(splitScreenPrimary).isTranslucent(any());
doReturn(true).when(splitScreenSecondary2).isTranslucent(any());
splitScreenSecondary2.moveToFront("testShouldBeVisible_SplitScreen");
splitScreenPrimary.moveToFront("testShouldBeVisible_SplitScreen");
if (isAssistantOnTop()) {
- assertTrue(assistantStack.shouldBeVisible(null /* starting */));
+ assertTrue(assistantRootTask.shouldBeVisible(null /* starting */));
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
- assistantStack.getVisibility(null /* starting */));
+ assistantRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_INVISIBLE,
@@ -523,11 +694,11 @@ public class ActivityStackTests extends WindowTestsBase {
assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
} else {
- assertFalse(assistantStack.shouldBeVisible(null /* starting */));
+ assertFalse(assistantRootTask.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
assertEquals(TASK_VISIBILITY_INVISIBLE,
- assistantStack.getVisibility(null /* starting */));
+ assistantRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_INVISIBLE,
@@ -539,35 +710,33 @@ public class ActivityStackTests extends WindowTestsBase {
@Test
public void testGetVisibility_MultiLevel() {
- final Task homeStack = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME,
- true /* onTop */);
- final Task splitPrimary = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
- ACTIVITY_TYPE_UNDEFINED, true /* onTop */);
- final Task splitSecondary = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
- ACTIVITY_TYPE_UNDEFINED, true /* onTop */);
-
- doReturn(false).when(homeStack).isTranslucent(any());
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, true /* onTop */);
+ final Task splitPrimary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED, true /* onTop */);
+ final Task splitSecondary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_UNDEFINED, true /* onTop */);
+
+ doReturn(false).when(homeRootTask).isTranslucent(any());
doReturn(false).when(splitPrimary).isTranslucent(any());
doReturn(false).when(splitSecondary).isTranslucent(any());
// Re-parent home to split secondary.
- homeStack.reparent(splitSecondary, POSITION_TOP);
+ homeRootTask.reparent(splitSecondary, POSITION_TOP);
// Current tasks should be visible.
assertEquals(TASK_VISIBILITY_VISIBLE, splitPrimary.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE, splitSecondary.getVisibility(null /* starting */));
// Home task should still be visible even though it is a child of another visible task.
- assertEquals(TASK_VISIBILITY_VISIBLE, homeStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, homeRootTask.getVisibility(null /* starting */));
// Add fullscreen translucent task that partially occludes split tasks
- final Task translucentStack = createStandardStackForVisibilityTest(
+ final Task translucentRootTask = createStandardRootTaskForVisibilityTest(
WINDOWING_MODE_FULLSCREEN, true /* translucent */);
// Fullscreen translucent task should be visible
- assertEquals(TASK_VISIBILITY_VISIBLE, translucentStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE,
+ translucentRootTask.getVisibility(null /* starting */));
// Split tasks should be visible behind translucent
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitPrimary.getVisibility(null /* starting */));
@@ -576,415 +745,400 @@ public class ActivityStackTests extends WindowTestsBase {
// Home task should be visible behind translucent since its parent is visible behind
// translucent.
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
- homeStack.getVisibility(null /* starting */));
+ homeRootTask.getVisibility(null /* starting */));
// Hide split-secondary
splitSecondary.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, true /* set */);
// Home split secondary and home task should be invisible.
assertEquals(TASK_VISIBILITY_INVISIBLE, splitSecondary.getVisibility(null /* starting */));
- assertEquals(TASK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE, homeRootTask.getVisibility(null /* starting */));
}
@Test
public void testGetVisibility_FullscreenBehindTranslucent() {
- final Task bottomStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task bottomRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final Task translucentStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task translucentRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
- bottomStack.getVisibility(null /* starting */));
+ bottomRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
- translucentStack.getVisibility(null /* starting */));
+ translucentRootTask.getVisibility(null /* starting */));
}
@Test
public void testGetVisibility_FullscreenBehindTranslucentAndOpaque() {
- final Task bottomStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task bottomRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final Task translucentStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task translucentRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- final Task opaqueStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task opaqueRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- assertEquals(TASK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE, bottomRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_INVISIBLE,
- translucentStack.getVisibility(null /* starting */));
- assertEquals(TASK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
+ translucentRootTask.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, opaqueRootTask.getVisibility(null /* starting */));
}
@Test
public void testGetVisibility_FullscreenBehindOpaqueAndTranslucent() {
- final Task bottomStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task bottomRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final Task opaqueStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task opaqueRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final Task translucentStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task translucentRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- assertEquals(TASK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE, bottomRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
- opaqueStack.getVisibility(null /* starting */));
+ opaqueRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
- translucentStack.getVisibility(null /* starting */));
+ translucentRootTask.getVisibility(null /* starting */));
}
@Test
public void testGetVisibility_FullscreenTranslucentBehindTranslucent() {
- final Task bottomTranslucentStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task bottomTranslucentRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- final Task translucentStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task translucentRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
- bottomTranslucentStack.getVisibility(null /* starting */));
+ bottomTranslucentRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
- translucentStack.getVisibility(null /* starting */));
+ translucentRootTask.getVisibility(null /* starting */));
}
@Test
public void testGetVisibility_FullscreenTranslucentBehindOpaque() {
- final Task bottomTranslucentStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task bottomTranslucentRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- final Task opaqueStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task opaqueRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
assertEquals(TASK_VISIBILITY_INVISIBLE,
- bottomTranslucentStack.getVisibility(null /* starting */));
- assertEquals(TASK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
+ bottomTranslucentRootTask.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, opaqueRootTask.getVisibility(null /* starting */));
}
@Test
public void testGetVisibility_FullscreenBehindTranslucentAndPip() {
- final Task bottomStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task bottomRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- final Task translucentStack =
- createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+ final Task translucentRootTask =
+ createStandardRootTaskForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task pinnedRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
- bottomStack.getVisibility(null /* starting */));
+ bottomRootTask.getVisibility(null /* starting */));
assertEquals(TASK_VISIBILITY_VISIBLE,
- translucentStack.getVisibility(null /* starting */));
- // Add an activity to the pinned stack so it isn't considered empty for visibility check.
+ translucentRootTask.getVisibility(null /* starting */));
+ // Add an activity to the pinned root task so it isn't considered empty for visibility
+ // check.
final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
- .setTask(pinnedStack)
+ .setTask(pinnedRootTask)
.build();
- assertEquals(TASK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, pinnedRootTask.getVisibility(null /* starting */));
}
@Test
public void testShouldBeVisible_Finishing() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
+ ActivityRecord topRunningHomeActivity = homeRootTask.topRunningActivity();
if (topRunningHomeActivity == null) {
topRunningHomeActivity = new ActivityBuilder(mAtm)
- .setTask(homeStack)
+ .setTask(homeRootTask)
.build();
}
- final Task translucentStack = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- doReturn(true).when(translucentStack).isTranslucent(any());
+ final Task translucentRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ doReturn(true).when(translucentRootTask).isTranslucent(any());
- assertTrue(homeStack.shouldBeVisible(null /* starting */));
- assertTrue(translucentStack.shouldBeVisible(null /* starting */));
+ assertTrue(homeRootTask.shouldBeVisible(null /* starting */));
+ assertTrue(translucentRootTask.shouldBeVisible(null /* starting */));
topRunningHomeActivity.finishing = true;
final ActivityRecord topRunningTranslucentActivity =
- translucentStack.topRunningActivity();
+ translucentRootTask.topRunningActivity();
topRunningTranslucentActivity.finishing = true;
- // Home stack should be visible even there are no running activities.
- assertTrue(homeStack.shouldBeVisible(null /* starting */));
+ // Home root task should be visible even there are no running activities.
+ assertTrue(homeRootTask.shouldBeVisible(null /* starting */));
// Home should be visible if we are starting an activity within it.
- assertTrue(homeStack.shouldBeVisible(topRunningHomeActivity /* starting */));
- // The translucent stack shouldn't be visible since its activity marked as finishing.
- assertFalse(translucentStack.shouldBeVisible(null /* starting */));
+ assertTrue(homeRootTask.shouldBeVisible(topRunningHomeActivity /* starting */));
+ // The translucent root task shouldn't be visible since its activity marked as finishing.
+ assertFalse(translucentRootTask.shouldBeVisible(null /* starting */));
}
@Test
- public void testShouldBeVisible_FullscreenBehindTranslucentInHomeStack() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ public void testShouldBeVisible_FullscreenBehindTranslucentInHomeRootTask() {
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
- .setParentTask(homeStack)
- .setCreateTask(true)
- .build();
+ .setParentTask(homeRootTask)
+ .setCreateTask(true)
+ .build();
final Task task = firstActivity.getTask();
final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
.setTask(task)
.build();
doReturn(false).when(secondActivity).occludesParent();
- homeStack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ homeRootTask.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */);
assertTrue(firstActivity.shouldBeVisible());
}
@Test
- public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindFullscreen() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ public void testMoveHomeRootTaskBehindBottomMostVisible_NoMoveHomeBehindFullscreen() {
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final Task fullscreenStack = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
+ final Task fullscreenRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- doReturn(false).when(homeStack).isTranslucent(any());
- doReturn(false).when(fullscreenStack).isTranslucent(any());
+ doReturn(false).when(homeRootTask).isTranslucent(any());
+ doReturn(false).when(fullscreenRootTask).isTranslucent(any());
- // Ensure that we don't move the home stack if it is already behind the top fullscreen stack
- int homeStackIndex = getTaskIndexOf(mDefaultTaskDisplayArea, homeStack);
- assertEquals(fullscreenStack, getRootTaskAbove(homeStack));
- mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
- assertEquals(homeStackIndex, getTaskIndexOf(mDefaultTaskDisplayArea, homeStack));
+ // Ensure that we don't move the home root task if it is already behind the top fullscreen
+ // root task.
+ int homeRootTaskIndex = getTaskIndexOf(mDefaultTaskDisplayArea, homeRootTask);
+ assertEquals(fullscreenRootTask, getRootTaskAbove(homeRootTask));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeRootTask);
+ assertEquals(homeRootTaskIndex, getTaskIndexOf(mDefaultTaskDisplayArea, homeRootTask));
}
@Test
- public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindTranslucent() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ public void testMoveHomeRootTaskBehindBottomMostVisible_NoMoveHomeBehindTranslucent() {
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final Task fullscreenStack = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea,
+ final Task fullscreenRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- doReturn(false).when(homeStack).isTranslucent(any());
- doReturn(true).when(fullscreenStack).isTranslucent(any());
+ doReturn(false).when(homeRootTask).isTranslucent(any());
+ doReturn(true).when(fullscreenRootTask).isTranslucent(any());
- // Ensure that we don't move the home stack if it is already behind the top fullscreen stack
- int homeStackIndex = getTaskIndexOf(mDefaultTaskDisplayArea, homeStack);
- assertEquals(fullscreenStack, getRootTaskAbove(homeStack));
- mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
- assertEquals(homeStackIndex, getTaskIndexOf(mDefaultTaskDisplayArea, homeStack));
+ // Ensure that we don't move the home root task if it is already behind the top fullscreen
+ // root task.
+ int homeRootTaskIndex = getTaskIndexOf(mDefaultTaskDisplayArea, homeRootTask);
+ assertEquals(fullscreenRootTask, getRootTaskAbove(homeRootTask));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeRootTask);
+ assertEquals(homeRootTaskIndex, getTaskIndexOf(mDefaultTaskDisplayArea, homeRootTask));
}
@Test
- public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeOnTop() {
- final Task fullscreenStack = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ public void testMoveHomeRootTaskBehindBottomMostVisible_NoMoveHomeOnTop() {
+ final Task fullscreenRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- doReturn(false).when(homeStack).isTranslucent(any());
- doReturn(false).when(fullscreenStack).isTranslucent(any());
+ doReturn(false).when(homeRootTask).isTranslucent(any());
+ doReturn(false).when(fullscreenRootTask).isTranslucent(any());
- // Ensure we don't move the home stack if it is already on top
- int homeStackIndex = getTaskIndexOf(mDefaultTaskDisplayArea, homeStack);
- assertNull(getRootTaskAbove(homeStack));
- mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
- assertEquals(homeStackIndex, getTaskIndexOf(mDefaultTaskDisplayArea, homeStack));
+ // Ensure we don't move the home root task if it is already on top
+ int homeRootTaskIndex = getTaskIndexOf(mDefaultTaskDisplayArea, homeRootTask);
+ assertNull(getRootTaskAbove(homeRootTask));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeRootTask);
+ assertEquals(homeRootTaskIndex, getTaskIndexOf(mDefaultTaskDisplayArea, homeRootTask));
}
@Test
- public void testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreen() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ public void testMoveHomeRootTaskBehindBottomMostVisible_MoveHomeBehindFullscreen() {
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final Task fullscreenStack1 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task fullscreenStack2 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task fullscreenRootTask1 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task fullscreenRootTask2 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task pinnedRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- doReturn(false).when(homeStack).isTranslucent(any());
- doReturn(false).when(fullscreenStack1).isTranslucent(any());
- doReturn(false).when(fullscreenStack2).isTranslucent(any());
+ doReturn(false).when(homeRootTask).isTranslucent(any());
+ doReturn(false).when(fullscreenRootTask1).isTranslucent(any());
+ doReturn(false).when(fullscreenRootTask2).isTranslucent(any());
- // Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the
- // pinned stack
- assertEquals(fullscreenStack1, getRootTaskAbove(homeStack));
- mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
- assertEquals(fullscreenStack2, getRootTaskAbove(homeStack));
+ // Ensure that we move the home root task behind the bottom most fullscreen root task,
+ // ignoring the pinned root task.
+ assertEquals(fullscreenRootTask1, getRootTaskAbove(homeRootTask));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeRootTask);
+ assertEquals(fullscreenRootTask2, getRootTaskAbove(homeRootTask));
}
@Test
public void
- testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreenAndTranslucent() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ testMoveHomeRootTaskBehindBottomMostVisible_MoveHomeBehindFullscreenAndTranslucent() {
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final Task fullscreenStack1 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task fullscreenStack2 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
+ final Task fullscreenRootTask1 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task fullscreenRootTask2 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- doReturn(false).when(homeStack).isTranslucent(any());
- doReturn(false).when(fullscreenStack1).isTranslucent(any());
- doReturn(true).when(fullscreenStack2).isTranslucent(any());
+ doReturn(false).when(homeRootTask).isTranslucent(any());
+ doReturn(false).when(fullscreenRootTask1).isTranslucent(any());
+ doReturn(true).when(fullscreenRootTask2).isTranslucent(any());
- // Ensure that we move the home stack behind the bottom most non-translucent fullscreen
- // stack
- assertEquals(fullscreenStack1, getRootTaskAbove(homeStack));
- mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
- assertEquals(fullscreenStack1, getRootTaskAbove(homeStack));
+ // Ensure that we move the home root task behind the bottom most non-translucent fullscreen
+ // root task.
+ assertEquals(fullscreenRootTask1, getRootTaskAbove(homeRootTask));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeRootTask);
+ assertEquals(fullscreenRootTask1, getRootTaskAbove(homeRootTask));
}
@Test
- public void testMoveHomeStackBehindStack_BehindHomeStack() {
- final Task fullscreenStack1 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task fullscreenStack2 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ public void testMoveHomeRootTaskBehindRootTask_BehindHomeRootTask() {
+ final Task fullscreenRootTask1 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task fullscreenRootTask2 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- doReturn(false).when(homeStack).isTranslucent(any());
- doReturn(false).when(fullscreenStack1).isTranslucent(any());
- doReturn(false).when(fullscreenStack2).isTranslucent(any());
+ doReturn(false).when(homeRootTask).isTranslucent(any());
+ doReturn(false).when(fullscreenRootTask1).isTranslucent(any());
+ doReturn(false).when(fullscreenRootTask2).isTranslucent(any());
- // Ensure we don't move the home stack behind itself
- int homeStackIndex = getTaskIndexOf(mDefaultTaskDisplayArea, homeStack);
- mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, homeStack);
- assertEquals(homeStackIndex, getTaskIndexOf(mDefaultTaskDisplayArea, homeStack));
+ // Ensure we don't move the home root task behind itself
+ int homeRootTaskIndex = getTaskIndexOf(mDefaultTaskDisplayArea, homeRootTask);
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeRootTask, homeRootTask);
+ assertEquals(homeRootTaskIndex, getTaskIndexOf(mDefaultTaskDisplayArea, homeRootTask));
}
@Test
- public void testMoveHomeStackBehindStack() {
- final Task fullscreenStack1 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task fullscreenStack2 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task fullscreenStack3 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task fullscreenStack4 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ public void testMoveHomeRootTaskBehindRootTask() {
+ final Task fullscreenRootTask1 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task fullscreenRootTask2 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task fullscreenRootTask3 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task fullscreenRootTask4 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack1);
- assertEquals(fullscreenStack1, getRootTaskAbove(homeStack));
- mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack2);
- assertEquals(fullscreenStack2, getRootTaskAbove(homeStack));
- mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack4);
- assertEquals(fullscreenStack4, getRootTaskAbove(homeStack));
- mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack2);
- assertEquals(fullscreenStack2, getRootTaskAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeRootTask, fullscreenRootTask1);
+ assertEquals(fullscreenRootTask1, getRootTaskAbove(homeRootTask));
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeRootTask, fullscreenRootTask2);
+ assertEquals(fullscreenRootTask2, getRootTaskAbove(homeRootTask));
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeRootTask, fullscreenRootTask4);
+ assertEquals(fullscreenRootTask4, getRootTaskAbove(homeRootTask));
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeRootTask, fullscreenRootTask2);
+ assertEquals(fullscreenRootTask2, getRootTaskAbove(homeRootTask));
}
@Test
public void testSetAlwaysOnTop() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task pinnedRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- assertEquals(pinnedStack, getRootTaskAbove(homeStack));
+ assertEquals(pinnedRootTask, getRootTaskAbove(homeRootTask));
- final Task alwaysOnTopStack = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- alwaysOnTopStack.setAlwaysOnTop(true);
- assertTrue(alwaysOnTopStack.isAlwaysOnTop());
- // Ensure (non-pinned) always on top stack is put below pinned stack.
- assertEquals(pinnedStack, getRootTaskAbove(alwaysOnTopStack));
+ final Task alwaysOnTopRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ alwaysOnTopRootTask.setAlwaysOnTop(true);
+ assertTrue(alwaysOnTopRootTask.isAlwaysOnTop());
+ // Ensure (non-pinned) always on top root task is put below pinned root task.
+ assertEquals(pinnedRootTask, getRootTaskAbove(alwaysOnTopRootTask));
- final Task nonAlwaysOnTopStack = createStackForShouldBeVisibleTest(
+ final Task nonAlwaysOnTopRootTask = createTaskForShouldBeVisibleTest(
mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- // Ensure non always on top stack is put below always on top stacks.
- assertEquals(alwaysOnTopStack, getRootTaskAbove(nonAlwaysOnTopStack));
-
- final Task alwaysOnTopStack2 = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- alwaysOnTopStack2.setAlwaysOnTop(true);
- assertTrue(alwaysOnTopStack2.isAlwaysOnTop());
- // Ensure newly created always on top stack is placed above other all always on top stacks.
- assertEquals(pinnedStack, getRootTaskAbove(alwaysOnTopStack2));
-
- alwaysOnTopStack2.setAlwaysOnTop(false);
- // Ensure, when always on top is turned off for a stack, the stack is put just below all
- // other always on top stacks.
- assertEquals(alwaysOnTopStack, getRootTaskAbove(alwaysOnTopStack2));
- alwaysOnTopStack2.setAlwaysOnTop(true);
+ // Ensure non always on top root task is put below always on top root tasks.
+ assertEquals(alwaysOnTopRootTask, getRootTaskAbove(nonAlwaysOnTopRootTask));
+
+ final Task alwaysOnTopRootTask2 = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ alwaysOnTopRootTask2.setAlwaysOnTop(true);
+ assertTrue(alwaysOnTopRootTask2.isAlwaysOnTop());
+ // Ensure newly created always on top root task is placed above other all always on top
+ // root tasks.
+ assertEquals(pinnedRootTask, getRootTaskAbove(alwaysOnTopRootTask2));
+
+ alwaysOnTopRootTask2.setAlwaysOnTop(false);
+ // Ensure, when always on top is turned off for a root task, the root task is put just below
+ // all other always on top root tasks.
+ assertEquals(alwaysOnTopRootTask, getRootTaskAbove(alwaysOnTopRootTask2));
+ alwaysOnTopRootTask2.setAlwaysOnTop(true);
// Ensure always on top state changes properly when windowing mode changes.
- alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- assertFalse(alwaysOnTopStack2.isAlwaysOnTop());
- assertEquals(alwaysOnTopStack, getRootTaskAbove(alwaysOnTopStack2));
- alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FREEFORM);
- assertTrue(alwaysOnTopStack2.isAlwaysOnTop());
- assertEquals(pinnedStack, getRootTaskAbove(alwaysOnTopStack2));
+ alwaysOnTopRootTask2.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertFalse(alwaysOnTopRootTask2.isAlwaysOnTop());
+ assertEquals(alwaysOnTopRootTask, getRootTaskAbove(alwaysOnTopRootTask2));
+ alwaysOnTopRootTask2.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertTrue(alwaysOnTopRootTask2.isAlwaysOnTop());
+ assertEquals(pinnedRootTask, getRootTaskAbove(alwaysOnTopRootTask2));
}
@Test
public void testSplitScreenMoveToFront() {
- final Task splitScreenPrimary = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
- ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task splitScreenSecondary = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
- ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task assistantStack = createStackForShouldBeVisibleTest(
- mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT,
- true /* onTop */);
+ final Task splitScreenPrimary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task splitScreenSecondary = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task assistantRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
doReturn(false).when(splitScreenPrimary).isTranslucent(any());
doReturn(false).when(splitScreenSecondary).isTranslucent(any());
- doReturn(false).when(assistantStack).isTranslucent(any());
+ doReturn(false).when(assistantRootTask).isTranslucent(any());
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
- assertTrue(assistantStack.shouldBeVisible(null /* starting */));
+ assertTrue(assistantRootTask.shouldBeVisible(null /* starting */));
splitScreenSecondary.moveToFront("testSplitScreenMoveToFront");
if (isAssistantOnTop()) {
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
- assertTrue(assistantStack.shouldBeVisible(null /* starting */));
+ assertTrue(assistantRootTask.shouldBeVisible(null /* starting */));
} else {
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
- assertFalse(assistantStack.shouldBeVisible(null /* starting */));
+ assertFalse(assistantRootTask.shouldBeVisible(null /* starting */));
}
}
- private Task createStandardStackForVisibilityTest(int windowingMode,
+ private Task createStandardRootTaskForVisibilityTest(int windowingMode,
boolean translucent) {
- final Task stack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ final Task rootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- doReturn(translucent).when(stack).isTranslucent(any());
- return stack;
+ doReturn(translucent).when(rootTask).isTranslucent(any());
+ return rootTask;
}
- private Task createStackForShouldBeVisibleTest(
+ private Task createTaskForShouldBeVisibleTest(
TaskDisplayArea taskDisplayArea, int windowingMode, int activityType, boolean onTop) {
- return createStackForShouldBeVisibleTest(taskDisplayArea,
+ return createTaskForShouldBeVisibleTest(taskDisplayArea,
windowingMode, activityType, onTop, false /* twoLevelTask */);
}
@SuppressWarnings("TypeParameterUnusedInFormals")
- private Task createStackForShouldBeVisibleTest(TaskDisplayArea taskDisplayArea,
+ private Task createTaskForShouldBeVisibleTest(TaskDisplayArea taskDisplayArea,
int windowingMode, int activityType, boolean onTop, boolean twoLevelTask) {
final Task task;
if (activityType == ACTIVITY_TYPE_HOME) {
@@ -1157,20 +1311,20 @@ public class ActivityStackTests extends WindowTestsBase {
}
@Test
- public void testWontFinishHomeStackImmediately() {
- final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
+ public void testWontFinishHomeRootTaskImmediately() {
+ final Task homeRootTask = createTaskForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- ActivityRecord activity = homeStack.topRunningActivity();
+ ActivityRecord activity = homeRootTask.topRunningActivity();
if (activity == null) {
activity = new ActivityBuilder(mAtm)
- .setParentTask(homeStack)
+ .setParentTask(homeRootTask)
.setCreateTask(true)
.build();
}
- // Home stack should not be destroyed immediately.
- final ActivityRecord activity1 = finishTopActivity(homeStack);
+ // Home root task should not be destroyed immediately.
+ final ActivityRecord activity1 = finishTopActivity(homeRootTask);
assertEquals(FINISHING, activity1.getState());
}
@@ -1178,30 +1332,28 @@ public class ActivityStackTests extends WindowTestsBase {
public void testFinishCurrentActivity() {
// Create 2 activities on a new display.
final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
- final Task stack1 = createStackForShouldBeVisibleTest(
- display.getDefaultTaskDisplayArea(),
+ final Task rootTask1 = createTaskForShouldBeVisibleTest(display.getDefaultTaskDisplayArea(),
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task stack2 = createStackForShouldBeVisibleTest(
- display.getDefaultTaskDisplayArea(),
+ final Task rootTask2 = createTaskForShouldBeVisibleTest(display.getDefaultTaskDisplayArea(),
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- // There is still an activity1 in stack1 so the activity2 should be added to finishing list
- // that will be destroyed until idle.
- stack2.getTopNonFinishingActivity().mVisibleRequested = true;
- final ActivityRecord activity2 = finishTopActivity(stack2);
+ // There is still an activity1 in rootTask1 so the activity2 should be added to finishing
+ // list that will be destroyed until idle.
+ rootTask2.getTopNonFinishingActivity().mVisibleRequested = true;
+ final ActivityRecord activity2 = finishTopActivity(rootTask2);
assertEquals(STOPPING, activity2.getState());
assertThat(mSupervisor.mStoppingActivities).contains(activity2);
// The display becomes empty. Since there is no next activity to be idle, the activity
// should be destroyed immediately with updating configuration to restore original state.
- final ActivityRecord activity1 = finishTopActivity(stack1);
+ final ActivityRecord activity1 = finishTopActivity(rootTask1);
assertEquals(DESTROYING, activity1.getState());
verify(mRootWindowContainer).ensureVisibilityAndConfig(eq(null) /* starting */,
eq(display.mDisplayId), anyBoolean(), anyBoolean());
}
- private ActivityRecord finishTopActivity(Task stack) {
- final ActivityRecord activity = stack.topRunningActivity();
+ private ActivityRecord finishTopActivity(Task task) {
+ final ActivityRecord activity = task.topRunningActivity();
assertNotNull(activity);
activity.setState(STOPPED, "finishTopActivity");
activity.makeFinishingLocked();
@@ -1214,24 +1366,24 @@ public class ActivityStackTests extends WindowTestsBase {
// When focused activity and keyguard is going away, we should not sleep regardless
// of the display state, but keyguard-going-away should only take effects on default
// display since there is no keyguard on secondary displays (yet).
- verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/,
+ verifyShouldSleepActivities(true /* focusedRootTask */, true /*keyguardGoingAway*/,
true /* displaySleeping */, true /* isDefaultDisplay */, false /* expected */);
- verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/,
+ verifyShouldSleepActivities(true /* focusedRootTask */, true /*keyguardGoingAway*/,
true /* displaySleeping */, false /* isDefaultDisplay */, true /* expected */);
- // When not the focused stack, defer to display sleeping state.
- verifyShouldSleepActivities(false /* focusedStack */, true /*keyguardGoingAway*/,
+ // When not the focused root task, defer to display sleeping state.
+ verifyShouldSleepActivities(false /* focusedRootTask */, true /*keyguardGoingAway*/,
true /* displaySleeping */, true /* isDefaultDisplay */, true /* expected */);
// If keyguard is going away, defer to the display sleeping state.
- verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
+ verifyShouldSleepActivities(true /* focusedRootTask */, false /*keyguardGoingAway*/,
true /* displaySleeping */, true /* isDefaultDisplay */, true /* expected */);
- verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
+ verifyShouldSleepActivities(true /* focusedRootTask */, false /*keyguardGoingAway*/,
false /* displaySleeping */, true /* isDefaultDisplay */, false /* expected */);
}
@Test
- public void testStackOrderChangedOnRemoveStack() {
+ public void testRootTaskOrderChangedOnRemoveRootTask() {
final Task task = new TaskBuilder(mSupervisor).build();
RootTaskOrderChangedListener listener = new RootTaskOrderChangedListener();
mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(listener);
@@ -1244,7 +1396,7 @@ public class ActivityStackTests extends WindowTestsBase {
}
@Test
- public void testStackOrderChangedOnAddPositionStack() {
+ public void testRootTaskOrderChangedOnAddPositionRootTask() {
final Task task = new TaskBuilder(mSupervisor).build();
mDefaultTaskDisplayArea.removeRootTask(task);
@@ -1260,14 +1412,14 @@ public class ActivityStackTests extends WindowTestsBase {
}
@Test
- public void testStackOrderChangedOnPositionStack() {
+ public void testRootTaskOrderChangedOnPositionRootTask() {
RootTaskOrderChangedListener listener = new RootTaskOrderChangedListener();
try {
- final Task fullscreenStack1 = createStackForShouldBeVisibleTest(
+ final Task fullscreenRootTask1 = createTaskForShouldBeVisibleTest(
mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(listener);
- mDefaultTaskDisplayArea.positionChildAt(POSITION_BOTTOM, fullscreenStack1,
+ mDefaultTaskDisplayArea.positionChildAt(POSITION_BOTTOM, fullscreenRootTask1,
false /*includingParents*/);
} finally {
mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(listener);
@@ -1443,7 +1595,7 @@ public class ActivityStackTests extends WindowTestsBase {
com.android.internal.R.bool.config_assistantOnTopOfDream);
}
- private void verifyShouldSleepActivities(boolean focusedStack,
+ private void verifyShouldSleepActivities(boolean focusedRootTask,
boolean keyguardGoingAway, boolean displaySleeping, boolean isDefaultDisplay,
boolean expected) {
final Task task = new TaskBuilder(mSupervisor).build();
@@ -1454,13 +1606,13 @@ public class ActivityStackTests extends WindowTestsBase {
task.mDisplayContent = display;
doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway();
doReturn(displaySleeping).when(display).isSleeping();
- doReturn(focusedStack).when(task).isFocusedRootTaskOnDisplay();
+ doReturn(focusedRootTask).when(task).isFocusedRootTaskOnDisplay();
assertEquals(expected, task.shouldSleepActivities());
}
private static class RootTaskOrderChangedListener
- implements OnRootTaskOrderChangedListener {
+ implements TaskDisplayArea.OnRootTaskOrderChangedListener {
public boolean mChanged = false;
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 1b114c194bfb..20bced252764 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -16,42 +16,93 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.TYPE_VIRTUAL;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.Task.ActivityState.FINISHING;
import static com.android.server.wm.Task.ActivityState.PAUSED;
import static com.android.server.wm.Task.ActivityState.PAUSING;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.google.common.truth.Truth.assertThat;
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.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.contains;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.refEq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.platform.test.annotations.Presubmit;
+import android.util.MergedConfiguration;
+import android.util.Pair;
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.MediumTest;
+import com.android.internal.app.ResolverActivity;
+
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
+
/**
- * Tests for RootWindowContainer.
+ * Tests for {@link RootWindowContainer}.
*
* Build/Install/Run:
* atest WmTests:RootWindowContainerTests
*/
-@SmallTest
+@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
public class RootWindowContainerTests extends WindowTestsBase {
+ @Before
+ public void setUp() throws Exception {
+ doNothing().when(mAtm).updateSleepIfNeededLocked();
+ }
+
@Test
public void testUpdateDefaultDisplayWindowingModeOnSettingsRetrieved() {
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
@@ -166,5 +217,860 @@ public class RootWindowContainerTests extends WindowTestsBase {
assertFalse(task.hasChild());
assertFalse(wpc.hasActivities());
}
+
+ /**
+ * This test ensures that we do not try to restore a task based off an invalid task id. We
+ * should expect {@code null} to be returned in this case.
+ */
+ @Test
+ public void testRestoringInvalidTask() {
+ mRootWindowContainer.getDefaultDisplay().removeAllTasks();
+ Task task = mRootWindowContainer.anyTaskForId(0 /*taskId*/,
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
+ assertNull(task);
+ }
+
+ /**
+ * This test ensures that an existing task in the pinned root task is moved to the fullscreen
+ * activity root task when a new task is added.
+ */
+ @Test
+ public void testReplacingTaskInPinnedRootTask() {
+ Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(fullscreenTask).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+ .setTask(fullscreenTask).build();
+
+ fullscreenTask.moveToFront("testReplacingTaskInPinnedRootTask");
+
+ // Ensure full screen root task has both tasks.
+ ensureTaskPlacement(fullscreenTask, firstActivity, secondActivity);
+
+ // Move first activity to pinned root task.
+ mRootWindowContainer.moveActivityToPinnedRootTask(firstActivity, "initialMove");
+
+ final TaskDisplayArea taskDisplayArea = fullscreenTask.getDisplayArea();
+ Task pinnedRootTask = taskDisplayArea.getRootPinnedTask();
+ // Ensure a task has moved over.
+ ensureTaskPlacement(pinnedRootTask, firstActivity);
+ ensureTaskPlacement(fullscreenTask, secondActivity);
+
+ // Move second activity to pinned root task.
+ mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "secondMove");
+
+ // Need to get root tasks again as a new instance might have been created.
+ pinnedRootTask = taskDisplayArea.getRootPinnedTask();
+ fullscreenTask = taskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
+ // Ensure root tasks have swapped tasks.
+ ensureTaskPlacement(pinnedRootTask, secondActivity);
+ ensureTaskPlacement(fullscreenTask, firstActivity);
+ }
+
+ @Test
+ public void testMovingBottomMostRootTaskActivityToPinnedRootTask() {
+ final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(fullscreenTask).build();
+ final Task task = firstActivity.getTask();
+
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+ .setTask(fullscreenTask).build();
+
+ fullscreenTask.moveTaskToBack(task);
+
+ // Ensure full screen task has both tasks.
+ ensureTaskPlacement(fullscreenTask, firstActivity, secondActivity);
+ assertEquals(task.getTopMostActivity(), secondActivity);
+ firstActivity.setState(STOPPED, "testMovingBottomMostRootTaskActivityToPinnedRootTask");
+
+
+ // Move first activity to pinned root task.
+ mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "initialMove");
+
+ assertTrue(firstActivity.mRequestForceTransition);
+ }
+
+ private static void ensureTaskPlacement(Task task, ActivityRecord... activities) {
+ final ArrayList<ActivityRecord> taskActivities = new ArrayList<>();
+
+ task.forAllActivities((Consumer<ActivityRecord>) taskActivities::add, false);
+
+ assertEquals("Expecting " + Arrays.deepToString(activities) + " got " + taskActivities,
+ taskActivities.size(), activities != null ? activities.length : 0);
+
+ if (activities == null) {
+ return;
+ }
+
+ for (ActivityRecord activity : activities) {
+ assertTrue(taskActivities.contains(activity));
+ }
+ }
+
+ @Test
+ public void testApplySleepTokens() {
+ final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
+ final KeyguardController keyguard = mSupervisor.getKeyguardController();
+ final Task task = new TaskBuilder(mSupervisor)
+ .setDisplay(display)
+ .setOnTop(false)
+ .build();
+
+ // Make sure we wake and resume in the case the display is turning on and the keyguard is
+ // not showing.
+ verifySleepTokenBehavior(display, keyguard, task, true /*displaySleeping*/,
+ false /* displayShouldSleep */, true /* isFocusedTask */,
+ false /* keyguardShowing */, true /* expectWakeFromSleep */,
+ true /* expectResumeTopActivity */);
+
+ // Make sure we wake and don't resume when the display is turning on and the keyguard is
+ // showing.
+ verifySleepTokenBehavior(display, keyguard, task, true /*displaySleeping*/,
+ false /* displayShouldSleep */, true /* isFocusedTask */,
+ true /* keyguardShowing */, true /* expectWakeFromSleep */,
+ false /* expectResumeTopActivity */);
+
+ // Make sure we wake and don't resume when the display is turning on and the keyguard is
+ // not showing as unfocused.
+ verifySleepTokenBehavior(display, keyguard, task, true /*displaySleeping*/,
+ false /* displayShouldSleep */, false /* isFocusedTask */,
+ false /* keyguardShowing */, true /* expectWakeFromSleep */,
+ false /* expectResumeTopActivity */);
+
+ // Should not do anything if the display state hasn't changed.
+ verifySleepTokenBehavior(display, keyguard, task, false /*displaySleeping*/,
+ false /* displayShouldSleep */, true /* isFocusedTask */,
+ false /* keyguardShowing */, false /* expectWakeFromSleep */,
+ false /* expectResumeTopActivity */);
+ }
+
+ private void verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard,
+ Task task, boolean displaySleeping, boolean displayShouldSleep,
+ boolean isFocusedTask, boolean keyguardShowing, boolean expectWakeFromSleep,
+ boolean expectResumeTopActivity) {
+ reset(task);
+
+ doReturn(displayShouldSleep).when(display).shouldSleep();
+ doReturn(displaySleeping).when(display).isSleeping();
+ doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt());
+
+ doReturn(isFocusedTask).when(task).isFocusedRootTaskOnDisplay();
+ doReturn(isFocusedTask ? task : null).when(display).getFocusedRootTask();
+ TaskDisplayArea defaultTaskDisplayArea = display.getDefaultTaskDisplayArea();
+ doReturn(isFocusedTask ? task : null).when(defaultTaskDisplayArea).getFocusedRootTask();
+ mRootWindowContainer.applySleepTokens(true);
+ verify(task, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked();
+ verify(task, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
+ null /* target */, null /* targetOptions */);
+ }
+
+ @Test
+ public void testAwakeFromSleepingWithAppConfiguration() {
+ final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ activity.moveFocusableActivityToTop("test");
+ assertTrue(activity.getRootTask().isFocusedRootTaskOnDisplay());
+ ActivityRecordTests.setRotatedScreenOrientationSilently(activity);
+
+ final Configuration rotatedConfig = new Configuration();
+ display.computeScreenConfiguration(rotatedConfig, display.getDisplayRotation()
+ .rotationForOrientation(activity.getOrientation(), display.getRotation()));
+ assertNotEquals(activity.getConfiguration().orientation, rotatedConfig.orientation);
+ // Assume the activity was shown in different orientation. For example, the top activity is
+ // landscape and the portrait lockscreen is shown.
+ activity.setLastReportedConfiguration(
+ new MergedConfiguration(mAtm.getGlobalConfiguration(), rotatedConfig));
+ activity.setState(Task.ActivityState.STOPPED, "sleep");
+
+ display.setIsSleeping(true);
+ doReturn(false).when(display).shouldSleep();
+ // Allow to resume when awaking.
+ setBooted(mAtm);
+ mRootWindowContainer.applySleepTokens(true);
+
+ // The display orientation should be changed by the activity so there is no relaunch.
+ verify(activity, never()).relaunchActivityLocked(anyBoolean());
+ assertEquals(rotatedConfig.orientation, display.getConfiguration().orientation);
+ }
+
+ /**
+ * Verifies that removal of activity with task and root task is done correctly.
+ */
+ @Test
+ public void testRemovingRootTaskOnAppCrash() {
+ final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
+ .getDefaultTaskDisplayArea();
+ final int originalRootTaskCount = defaultTaskDisplayArea.getRootTaskCount();
+ final Task rootTask = defaultTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(rootTask).build();
+
+ assertEquals(originalRootTaskCount + 1, defaultTaskDisplayArea.getRootTaskCount());
+
+ // Let's pretend that the app has crashed.
+ firstActivity.app.setThread(null);
+ mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
+
+ // Verify that the root task was removed.
+ assertEquals(originalRootTaskCount, defaultTaskDisplayArea.getRootTaskCount());
+ }
+
+ /**
+ * Verifies that removal of activities with task and root task is done correctly when there are
+ * several task display areas.
+ */
+ @Test
+ public void testRemovingRootTaskOnAppCrash_multipleDisplayAreas() {
+ final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
+ .getDefaultTaskDisplayArea();
+ final int originalRootTaskCount = defaultTaskDisplayArea.getRootTaskCount();
+ final Task rootTask = defaultTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(rootTask).build();
+ assertEquals(originalRootTaskCount + 1, defaultTaskDisplayArea.getRootTaskCount());
+
+ final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent();
+ final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
+ dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST);
+ final Task secondRootTask = secondTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ new ActivityBuilder(mAtm).setTask(secondRootTask).setUseProcess(firstActivity.app).build();
+ assertEquals(1, secondTaskDisplayArea.getRootTaskCount());
+
+ // Let's pretend that the app has crashed.
+ firstActivity.app.setThread(null);
+ mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
+
+ // Verify that the root tasks were removed.
+ assertEquals(originalRootTaskCount, defaultTaskDisplayArea.getRootTaskCount());
+ assertEquals(0, secondTaskDisplayArea.getRootTaskCount());
+ }
+
+ @Test
+ public void testFocusability() {
+ final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
+ .getDefaultTaskDisplayArea();
+ final Task task = defaultTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
+
+ // Created tasks are focusable by default.
+ assertTrue(task.isTopActivityFocusable());
+ assertTrue(activity.isFocusable());
+
+ // If the task is made unfocusable, its activities should inherit that.
+ task.setFocusable(false);
+ assertFalse(task.isTopActivityFocusable());
+ assertFalse(activity.isFocusable());
+
+ final Task pinnedTask = defaultTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
+ .setTask(pinnedTask).build();
+
+ // We should not be focusable when in pinned mode
+ assertFalse(pinnedTask.isTopActivityFocusable());
+ assertFalse(pinnedActivity.isFocusable());
+
+ // Add flag forcing focusability.
+ pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE;
+
+ // Task with FLAG_ALWAYS_FOCUSABLE should be focusable.
+ assertTrue(pinnedTask.isTopActivityFocusable());
+ assertTrue(pinnedActivity.isFocusable());
+ }
+
+ /**
+ * Verify that split-screen primary root task will be chosen if activity is launched that
+ * targets split-screen secondary, but a matching existing instance is found on top of
+ * split-screen primary root task.
+ */
+ @Test
+ public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() {
+ // Create primary split-screen root task with a task and an activity.
+ final Task primaryRootTask = mRootWindowContainer.getDefaultTaskDisplayArea()
+ .createRootTask(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(primaryRootTask).build();
+ final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build();
+
+ // Find a launch root task for the top activity in split-screen primary, while requesting
+ // split-screen secondary.
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
+ final Task result =
+ mRootWindowContainer.getLaunchRootTask(r, options, task, true /* onTop */);
+
+ // Assert that the primary root task is returned.
+ assertEquals(primaryRootTask, result);
+ }
+
+ /**
+ * Verify that home root task would be moved to front when the top activity is Recents.
+ */
+ @Test
+ public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
+ // Create root task/task on default display.
+ final Task targetRootTask = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
+ .setOnTop(false)
+ .build();
+ final Task targetTask = targetRootTask.getBottomMostTask();
+
+ // Create Recents on top of the display.
+ final Task rootTask = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true)
+ .setActivityType(ACTIVITY_TYPE_RECENTS)
+ .build();
+
+ final String reason = "findTaskToMoveToFront";
+ mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
+ false);
+
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ verify(taskDisplayArea).moveHomeRootTaskToFront(contains(reason));
+ }
+
+ /**
+ * Verify that home root task won't be moved to front if the top activity on other display is
+ * Recents.
+ */
+ @Test
+ public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() {
+ // Create tasks on default display.
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final Task targetRootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final Task targetTask = new TaskBuilder(mSupervisor).setParentTask(targetRootTask).build();
+
+ // Create Recents on secondary display.
+ final TestDisplayContent secondDisplay = addNewDisplayContentAt(
+ DisplayContent.POSITION_TOP);
+ final Task rootTask = secondDisplay.getDefaultTaskDisplayArea()
+ .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */);
+ new ActivityBuilder(mAtm).setTask(rootTask).build();
+
+ final String reason = "findTaskToMoveToFront";
+ mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
+ false);
+
+ verify(taskDisplayArea, never()).moveHomeRootTaskToFront(contains(reason));
+ }
+
+ /**
+ * Verify if a root task is not at the topmost position, it should be able to resume its
+ * activity if the root task is the top focused.
+ */
+ @Test
+ public void testResumeActivityWhenNonTopmostRootTaskIsTopFocused() {
+ // Create a root task at bottom.
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, false /* onTop */));
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build();
+ taskDisplayArea.positionChildAt(POSITION_BOTTOM, rootTask, false /*includingParents*/);
+
+ // Assume the task is not at the topmost position (e.g. behind always-on-top root tasks)
+ // but it is the current top focused task.
+ assertFalse(rootTask.isTopRootTaskInDisplayArea());
+ doReturn(rootTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
+
+ // Use the task as target to resume.
+ mRootWindowContainer.resumeFocusedTasksTopActivities(
+ rootTask, activity, null /* targetOptions */);
+
+ // Verify the target task should resume its activity.
+ verify(rootTask, times(1)).resumeTopActivityUncheckedLocked(
+ eq(activity), eq(null /* targetOptions */));
+ }
+
+ /**
+ * Verify that home activity will be started on a display even if another display has a
+ * focusable activity.
+ */
+ @Test
+ public void testResumeFocusedRootTasksStartsHomeActivity_NoActivities() {
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ taskDisplayArea.getRootHomeTask().removeIfPossible();
+ taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+
+ doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
+
+ mAtm.setBooted(true);
+
+ // Trigger resume on all displays
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
+
+ // Verify that home activity was started on the default display
+ verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea));
+ }
+
+ /**
+ * Verify that home activity will be started on a display even if another display has a
+ * focusable activity.
+ */
+ @Test
+ public void testResumeFocusedRootTasksStartsHomeActivity_ActivityOnSecondaryScreen() {
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ taskDisplayArea.getRootHomeTask().removeIfPossible();
+ taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+
+ // Create an activity on secondary display.
+ final TestDisplayContent secondDisplay = addNewDisplayContentAt(
+ DisplayContent.POSITION_TOP);
+ final Task rootTask = secondDisplay.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ new ActivityBuilder(mAtm).setTask(rootTask).build();
+
+ doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
+
+ mAtm.setBooted(true);
+
+ // Trigger resume on all displays
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
+
+ // Verify that home activity was started on the default display
+ verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea));
+ }
+
+ /**
+ * Verify that a lingering transition is being executed in case the activity to be resumed is
+ * already resumed
+ */
+ @Test
+ public void testResumeActivityLingeringTransition() {
+ // Create a root task at top.
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, false /* onTop */));
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(rootTask).setOnTop(true).build();
+ activity.setState(Task.ActivityState.RESUMED, "test");
+
+ // Assume the task is at the topmost position
+ assertTrue(rootTask.isTopRootTaskInDisplayArea());
+
+ // Use the task as target to resume.
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
+
+ // Verify the lingering app transition is being executed because it's already resumed
+ verify(rootTask, times(1)).executeAppTransition(any());
+ }
+
+ @Test
+ public void testResumeActivityLingeringTransition_notExecuted() {
+ // Create a root task at bottom.
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, false /* onTop */));
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(rootTask).setOnTop(true).build();
+ activity.setState(Task.ActivityState.RESUMED, "test");
+ taskDisplayArea.positionChildAt(POSITION_BOTTOM, rootTask, false /*includingParents*/);
+
+ // Assume the task is at the topmost position
+ assertFalse(rootTask.isTopRootTaskInDisplayArea());
+ doReturn(rootTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
+
+ // Use the task as target to resume.
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
+
+ // Verify the lingering app transition is being executed because it's already resumed
+ verify(rootTask, never()).executeAppTransition(any());
+ }
+
+ /**
+ * Tests that home activities can be started on the displays that supports system decorations.
+ */
+ @Test
+ public void testStartHomeOnAllDisplays() {
+ mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
+ mockResolveSecondaryHomeActivity();
+
+ // Create secondary displays.
+ final TestDisplayContent secondDisplay =
+ new TestDisplayContent.Builder(mAtm, 1000, 1500)
+ .setSystemDecorations(true).build();
+
+ doReturn(true).when(mRootWindowContainer)
+ .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
+ doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
+ anyBoolean());
+
+ mRootWindowContainer.startHomeOnAllDisplays(0, "testStartHome");
+
+ assertTrue(mRootWindowContainer.getDefaultDisplay().getTopRootTask().isActivityTypeHome());
+ assertNotNull(secondDisplay.getTopRootTask());
+ assertTrue(secondDisplay.getTopRootTask().isActivityTypeHome());
+ }
+
+ /**
+ * Tests that home activities won't be started before booting when display added.
+ */
+ @Test
+ public void testNotStartHomeBeforeBoot() {
+ final int displayId = 1;
+ final boolean isBooting = mAtm.mAmInternal.isBooting();
+ final boolean isBooted = mAtm.mAmInternal.isBooted();
+ try {
+ mAtm.mAmInternal.setBooting(false);
+ mAtm.mAmInternal.setBooted(false);
+ mRootWindowContainer.onDisplayAdded(displayId);
+ verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
+ } finally {
+ mAtm.mAmInternal.setBooting(isBooting);
+ mAtm.mAmInternal.setBooted(isBooted);
+ }
+ }
+
+ /**
+ * Tests whether home can be started if being instrumented.
+ */
+ @Test
+ public void testCanStartHomeWhenInstrumented() {
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ final WindowProcessController app = mock(WindowProcessController.class);
+ doReturn(app).when(mAtm).getProcessController(any(), anyInt());
+
+ // Can not start home if we don't want to start home while home is being instrumented.
+ doReturn(true).when(app).isInstrumenting();
+ final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
+ .getDefaultTaskDisplayArea();
+ assertFalse(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
+ false /* allowInstrumenting*/));
+
+ // Can start home for other cases.
+ assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
+ true /* allowInstrumenting*/));
+
+ doReturn(false).when(app).isInstrumenting();
+ assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
+ false /* allowInstrumenting*/));
+ assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
+ true /* allowInstrumenting*/));
+ }
+
+ /**
+ * Tests that secondary home activity should not be resolved if device is still locked.
+ */
+ @Test
+ public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() {
+ // Create secondary displays.
+ final TestDisplayContent secondDisplay =
+ new TestDisplayContent.Builder(mAtm, 1000, 1500)
+ .setSystemDecorations(true).build();
+
+ // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false.
+ final int currentUser = mRootWindowContainer.mCurrentUser;
+ mRootWindowContainer.mCurrentUser = -1;
+
+ mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
+ secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
+
+ try {
+ verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any());
+ } finally {
+ mRootWindowContainer.mCurrentUser = currentUser;
+ }
+ }
+
+ /**
+ * Tests that secondary home activity should not be resolved if display does not support system
+ * decorations.
+ */
+ @Test
+ public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() {
+ // Create secondary displays.
+ final TestDisplayContent secondDisplay =
+ new TestDisplayContent.Builder(mAtm, 1000, 1500)
+ .setSystemDecorations(false).build();
+
+ mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
+ secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
+
+ verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any());
+ }
+
+ /**
+ * Tests that when starting {@link #ResolverActivity} for home, it should use the standard
+ * activity type (in a new root task) so the order of back stack won't be broken.
+ */
+ @Test
+ public void testStartResolverActivityForHome() {
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ info.applicationInfo.packageName = "android";
+ info.name = ResolverActivity.class.getName();
+ doReturn(info).when(mRootWindowContainer).resolveHomeActivity(anyInt(), any());
+
+ mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "test", DEFAULT_DISPLAY);
+ final ActivityRecord resolverActivity = mRootWindowContainer.topRunningActivity();
+
+ assertEquals(info, resolverActivity.info);
+ assertEquals(ACTIVITY_TYPE_STANDARD, resolverActivity.getRootTask().getActivityType());
+ }
+
+ /**
+ * Tests that secondary home should be selected if primary home not set.
+ */
+ @Test
+ public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet() {
+ // Setup: primary home not set.
+ final Intent primaryHomeIntent = mAtm.getHomeIntent();
+ final ActivityInfo aInfoPrimary = new ActivityInfo();
+ aInfoPrimary.name = ResolverActivity.class.getName();
+ doReturn(aInfoPrimary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
+ refEq(primaryHomeIntent));
+ // Setup: set secondary home.
+ mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
+
+ // Run the test.
+ final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
+ .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
+ final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
+ assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
+ assertEquals(aInfoSecondary.applicationInfo.packageName,
+ resolvedInfo.first.applicationInfo.packageName);
+ }
+
+ /**
+ * Tests that the default secondary home activity is always picked when it is in forced by
+ * config_useSystemProvidedLauncherForSecondary.
+ */
+ @Test
+ public void testResolveSecondaryHomeActivityForced() {
+ // SetUp: set primary home.
+ mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
+ // SetUp: set secondary home and force it.
+ mockResolveHomeActivity(false /* primaryHome */, true /* forceSystemProvided */);
+ final Intent secondaryHomeIntent =
+ mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
+ final List<ResolveInfo> resolutions = new ArrayList<>();
+ final ResolveInfo resolveInfo = new ResolveInfo();
+ final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
+ resolveInfo.activityInfo = aInfoSecondary;
+ resolutions.add(resolveInfo);
+ doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(),
+ refEq(secondaryHomeIntent));
+ doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
+ anyBoolean());
+
+ // Run the test.
+ final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
+ .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
+ assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
+ assertEquals(aInfoSecondary.applicationInfo.packageName,
+ resolvedInfo.first.applicationInfo.packageName);
+ }
+
+ /**
+ * Tests that secondary home should be selected if primary home not support secondary displays
+ * or there is no matched activity in the same package as selected primary home.
+ */
+ @Test
+ public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSupportMultiDisplay() {
+ // Setup: there is no matched activity in the same package as selected primary home.
+ mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
+ final List<ResolveInfo> resolutions = new ArrayList<>();
+ doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
+ // Setup: set secondary home.
+ mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
+
+ // Run the test.
+ final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
+ .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
+ final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
+ assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
+ assertEquals(aInfoSecondary.applicationInfo.packageName,
+ resolvedInfo.first.applicationInfo.packageName);
+ }
+ /**
+ * Tests that primary home activity should be selected if it already support secondary displays.
+ */
+ @Test
+ public void testResolveSecondaryHomeActivityWhenPrimaryHomeSupportMultiDisplay() {
+ // SetUp: set primary home.
+ mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
+ // SetUp: put primary home info on 2nd item
+ final List<ResolveInfo> resolutions = new ArrayList<>();
+ final ResolveInfo infoFake1 = new ResolveInfo();
+ infoFake1.activityInfo = new ActivityInfo();
+ infoFake1.activityInfo.name = "fakeActivity1";
+ infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
+ infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
+ final ResolveInfo infoFake2 = new ResolveInfo();
+ final ActivityInfo aInfoPrimary = getFakeHomeActivityInfo(true /* primaryHome */);
+ infoFake2.activityInfo = aInfoPrimary;
+ resolutions.add(infoFake1);
+ resolutions.add(infoFake2);
+ doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
+
+ doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
+ anyBoolean());
+
+ // Run the test.
+ final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
+ .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
+ assertEquals(aInfoPrimary.name, resolvedInfo.first.name);
+ assertEquals(aInfoPrimary.applicationInfo.packageName,
+ resolvedInfo.first.applicationInfo.packageName);
+ }
+
+ /**
+ * Tests that the first one that matches should be selected if there are multiple activities.
+ */
+ @Test
+ public void testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay() {
+ // SetUp: set primary home.
+ mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
+ // Setup: prepare two eligible activity info.
+ final List<ResolveInfo> resolutions = new ArrayList<>();
+ final ResolveInfo infoFake1 = new ResolveInfo();
+ infoFake1.activityInfo = new ActivityInfo();
+ infoFake1.activityInfo.name = "fakeActivity1";
+ infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
+ infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
+ final ResolveInfo infoFake2 = new ResolveInfo();
+ infoFake2.activityInfo = new ActivityInfo();
+ infoFake2.activityInfo.name = "fakeActivity2";
+ infoFake2.activityInfo.applicationInfo = new ApplicationInfo();
+ infoFake2.activityInfo.applicationInfo.packageName = "fakePackage2";
+ resolutions.add(infoFake1);
+ resolutions.add(infoFake2);
+ doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
+
+ doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
+ anyBoolean());
+
+ // Use the first one of matched activities in the same package as selected primary home.
+ final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
+ .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
+
+ assertEquals(infoFake1.activityInfo.applicationInfo.packageName,
+ resolvedInfo.first.applicationInfo.packageName);
+ assertEquals(infoFake1.activityInfo.name, resolvedInfo.first.name);
+ }
+
+ /**
+ * Test that {@link RootWindowContainer#getLaunchRootTask} with the real caller id will get the
+ * expected root task when requesting the activity launch on the secondary display.
+ */
+ @Test
+ public void testGetLaunchRootTaskWithRealCallerId() {
+ // Create a non-system owned virtual display.
+ final TestDisplayContent secondaryDisplay =
+ new TestDisplayContent.Builder(mAtm, 1000, 1500)
+ .setType(TYPE_VIRTUAL).setOwnerUid(100).build();
+
+ // Create an activity with specify the original launch pid / uid.
+ final ActivityRecord r = new ActivityBuilder(mAtm).setLaunchedFromPid(200)
+ .setLaunchedFromUid(200).build();
+
+ // Simulate ActivityStarter to find a launch root task for requesting the activity to launch
+ // on the secondary display with realCallerId.
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(secondaryDisplay.mDisplayId);
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
+ 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
+ final Task result = mRootWindowContainer.getLaunchRootTask(r, options,
+ null /* task */, true /* onTop */, null, 300 /* test realCallerPid */,
+ 300 /* test realCallerUid */);
+
+ // Assert that the root task is returned as expected.
+ assertNotNull(result);
+ assertEquals("The display ID of the root task should same as secondary display ",
+ secondaryDisplay.mDisplayId, result.getDisplayId());
+ }
+
+ @Test
+ public void testGetValidLaunchRootTaskOnDisplayWithCandidateRootTask() {
+ // Create a root task with an activity on secondary display.
+ final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mAtm, 300,
+ 600).build();
+ final Task task = new TaskBuilder(mSupervisor)
+ .setDisplay(secondaryDisplay).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
+
+ // Make sure the root task is valid and can be reused on default display.
+ final Task rootTask = mRootWindowContainer.getValidLaunchRootTaskInTaskDisplayArea(
+ mRootWindowContainer.getDefaultTaskDisplayArea(), activity, task,
+ null /* options */, null /* launchParams */);
+ assertEquals(task, rootTask);
+ }
+
+ @Test
+ public void testSwitchUser_missingHomeRootTask() {
+ final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ doReturn(fullscreenTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
+
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ Task rootHomeTask = taskDisplayArea.getRootHomeTask();
+ if (rootHomeTask != null) {
+ rootHomeTask.removeImmediately();
+ }
+ assertNull(taskDisplayArea.getRootHomeTask());
+
+ int currentUser = mRootWindowContainer.mCurrentUser;
+ int otherUser = currentUser + 1;
+
+ mRootWindowContainer.switchUser(otherUser, null);
+
+ assertNotNull(taskDisplayArea.getRootHomeTask());
+ assertEquals(taskDisplayArea.getTopRootTask(), taskDisplayArea.getRootHomeTask());
+ }
+
+ /**
+ * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
+ * info for test cases.
+ *
+ * @param primaryHome Indicate to use primary home intent as parameter, otherwise, use
+ * secondary home intent.
+ * @param forceSystemProvided Indicate to force using system provided home activity.
+ */
+ private void mockResolveHomeActivity(boolean primaryHome, boolean forceSystemProvided) {
+ ActivityInfo targetActivityInfo = getFakeHomeActivityInfo(primaryHome);
+ Intent targetIntent;
+ if (primaryHome) {
+ targetIntent = mAtm.getHomeIntent();
+ } else {
+ Resources resources = mContext.getResources();
+ spyOn(resources);
+ doReturn(targetActivityInfo.applicationInfo.packageName).when(resources).getString(
+ com.android.internal.R.string.config_secondaryHomePackage);
+ doReturn(forceSystemProvided).when(resources).getBoolean(
+ com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
+ targetIntent = mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
+ }
+ doReturn(targetActivityInfo).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
+ refEq(targetIntent));
+ }
+
+ /**
+ * Mock {@link RootWindowContainer#resolveSecondaryHomeActivity} for returning consistent
+ * activity info for test cases.
+ */
+ private void mockResolveSecondaryHomeActivity() {
+ final Intent secondaryHomeIntent = mAtm
+ .getSecondaryHomeIntent(null /* preferredPackage */);
+ final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false);
+ doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer)
+ .resolveSecondaryHomeActivity(anyInt(), any());
+ }
+
+ private ActivityInfo getFakeHomeActivityInfo(boolean primaryHome) {
+ final ActivityInfo aInfo = new ActivityInfo();
+ aInfo.name = primaryHome ? "fakeHomeActivity" : "fakeSecondaryHomeActivity";
+ aInfo.applicationInfo = new ApplicationInfo();
+ aInfo.applicationInfo.packageName =
+ primaryHome ? "fakeHomePackage" : "fakeSecondaryHomePackage";
+ return aInfo;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index eba5634e4355..92d4edec85f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -28,6 +28,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
@@ -35,13 +36,16 @@ import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import static com.android.server.wm.Task.ActivityState.RESUMED;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -56,8 +60,6 @@ import androidx.test.filters.SmallTest;
import com.android.server.wm.LaunchParamsController.LaunchParams;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -72,35 +74,17 @@ import org.junit.runner.RunWith;
@RunWith(WindowTestRunner.class)
public class TaskDisplayAreaTests extends WindowTestsBase {
- private Task mPinnedTask;
-
- @Before
- public void setUp() throws Exception {
- mPinnedTask = createTaskStackOnDisplay(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
- // Stack should contain visible app window to be considered visible.
- assertFalse(mPinnedTask.isVisible());
- final ActivityRecord pinnedApp = createNonAttachedActivityRecord(mDisplayContent);
- mPinnedTask.addChild(pinnedApp, 0 /* addPos */);
- assertTrue(mPinnedTask.isVisible());
- }
-
- @After
- public void tearDown() throws Exception {
- mPinnedTask.removeImmediately();
- }
-
@Test
public void getOrCreateLaunchRootRespectsResolvedWindowingMode() {
- final Task rootTask = createTaskStackOnDisplay(
- WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task rootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
rootTask.mCreatedByOrganizer = true;
final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
taskDisplayArea.setLaunchRootTask(
rootTask, new int[]{WINDOWING_MODE_FREEFORM}, new int[]{ACTIVITY_TYPE_STANDARD});
- final Task candidateRootTask = createTaskStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task candidateRootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
final LaunchParams launchParams = new LaunchParams();
launchParams.mWindowingMode = WINDOWING_MODE_FREEFORM;
@@ -113,15 +97,15 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
@Test
public void getOrCreateLaunchRootUsesActivityOptionsWindowingMode() {
- final Task rootTask = createTaskStackOnDisplay(
- WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task rootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
rootTask.mCreatedByOrganizer = true;
final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
taskDisplayArea.setLaunchRootTask(
rootTask, new int[]{WINDOWING_MODE_FREEFORM}, new int[]{ACTIVITY_TYPE_STANDARD});
- final Task candidateRootTask = createTaskStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task candidateRootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -134,9 +118,8 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
@Test
public void testActivityWithZBoost_taskDisplayAreaDoesNotMoveUp() {
- final Task stack = createTaskStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task task = createTaskInStack(stack, 0 /* userId */);
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
task.addChild(activity, 0 /* addPos */);
final TaskDisplayArea taskDisplayArea = activity.getDisplayArea();
@@ -152,87 +135,103 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
}
@Test
- public void testStackPositionChildAt() {
- // Test that always-on-top stack can't be moved to position other than top.
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final Task stack2 = createTaskStackOnDisplay(mDisplayContent);
-
- final WindowContainer taskStackContainer = stack1.getParent();
-
- final int stack1Pos = taskStackContainer.mChildren.indexOf(stack1);
- final int stack2Pos = taskStackContainer.mChildren.indexOf(stack2);
- final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedTask);
- assertThat(pinnedStackPos).isGreaterThan(stack2Pos);
- assertThat(stack2Pos).isGreaterThan(stack1Pos);
-
- taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, mPinnedTask, false);
- assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1);
- assertEquals(taskStackContainer.mChildren.get(stack2Pos), stack2);
- assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedTask);
-
- taskStackContainer.positionChildAt(1, mPinnedTask, false);
- assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1);
- assertEquals(taskStackContainer.mChildren.get(stack2Pos), stack2);
- assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedTask);
+ public void testRootTaskPositionChildAt() {
+ Task pinnedTask = createTask(
+ mDisplayContent, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
+ // Root task should contain visible app window to be considered visible.
+ assertFalse(pinnedTask.isVisible());
+ final ActivityRecord pinnedApp = createNonAttachedActivityRecord(mDisplayContent);
+ pinnedTask.addChild(pinnedApp, 0 /* addPos */);
+ assertTrue(pinnedTask.isVisible());
+
+ // Test that always-on-top root task can't be moved to position other than top.
+ final Task rootTask1 = createTask(mDisplayContent);
+ final Task rootTask2 = createTask(mDisplayContent);
+
+ final WindowContainer taskContainer = rootTask1.getParent();
+
+ final int rootTask1Pos = taskContainer.mChildren.indexOf(rootTask1);
+ final int rootTask2Pos = taskContainer.mChildren.indexOf(rootTask2);
+ final int pinnedTaskPos = taskContainer.mChildren.indexOf(pinnedTask);
+ assertThat(pinnedTaskPos).isGreaterThan(rootTask2Pos);
+ assertThat(rootTask2Pos).isGreaterThan(rootTask1Pos);
+
+ taskContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, pinnedTask, false);
+ assertEquals(taskContainer.mChildren.get(rootTask1Pos), rootTask1);
+ assertEquals(taskContainer.mChildren.get(rootTask2Pos), rootTask2);
+ assertEquals(taskContainer.mChildren.get(pinnedTaskPos), pinnedTask);
+
+ taskContainer.positionChildAt(1, pinnedTask, false);
+ assertEquals(taskContainer.mChildren.get(rootTask1Pos), rootTask1);
+ assertEquals(taskContainer.mChildren.get(rootTask2Pos), rootTask2);
+ assertEquals(taskContainer.mChildren.get(pinnedTaskPos), pinnedTask);
}
@Test
- public void testStackPositionBelowPinnedStack() {
- // Test that no stack can be above pinned stack.
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
+ public void testRootTaskPositionBelowPinnedRootTask() {
+ Task pinnedTask = createTask(
+ mDisplayContent, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
+ // Root task should contain visible app window to be considered visible.
+ assertFalse(pinnedTask.isVisible());
+ final ActivityRecord pinnedApp = createNonAttachedActivityRecord(mDisplayContent);
+ pinnedTask.addChild(pinnedApp, 0 /* addPos */);
+ assertTrue(pinnedTask.isVisible());
+
+ // Test that no root task can be above pinned root task.
+ final Task rootTask1 = createTask(mDisplayContent);
- final WindowContainer taskStackContainer = stack1.getParent();
+ final WindowContainer taskContainer = rootTask1.getParent();
- final int stackPos = taskStackContainer.mChildren.indexOf(stack1);
- final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedTask);
- assertThat(pinnedStackPos).isGreaterThan(stackPos);
+ final int rootTaskPos = taskContainer.mChildren.indexOf(rootTask1);
+ final int pinnedTaskPos = taskContainer.mChildren.indexOf(pinnedTask);
+ assertThat(pinnedTaskPos).isGreaterThan(rootTaskPos);
- taskStackContainer.positionChildAt(WindowContainer.POSITION_TOP, stack1, false);
- assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
- assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedTask);
+ taskContainer.positionChildAt(WindowContainer.POSITION_TOP, rootTask1, false);
+ assertEquals(taskContainer.mChildren.get(rootTaskPos), rootTask1);
+ assertEquals(taskContainer.mChildren.get(pinnedTaskPos), pinnedTask);
- taskStackContainer.positionChildAt(taskStackContainer.mChildren.size() - 1, stack1, false);
- assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
- assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedTask);
+ taskContainer.positionChildAt(taskContainer.mChildren.size() - 1, rootTask1, false);
+ assertEquals(taskContainer.mChildren.get(rootTaskPos), rootTask1);
+ assertEquals(taskContainer.mChildren.get(pinnedTaskPos), pinnedTask);
}
@Test
- public void testDisplayPositionWithPinnedStack() {
- // Make sure the display is trusted display which capable to move the stack to top.
+ public void testDisplayPositionWithPinnedRootTask() {
+ // Make sure the display is trusted display which capable to move the root task to top.
spyOn(mDisplayContent);
doReturn(true).when(mDisplayContent).isTrusted();
- // Allow child stack to move to top.
+ // Allow child root task to move to top.
mDisplayContent.mDontMoveToTop = false;
- // The display contains pinned stack that was added in {@link #setUp}.
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack, 0 /* userId */);
+ // The display contains pinned root task that was added in {@link #setUp}.
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
// Add another display at top.
mWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
false /* includingParents */);
// Move the task of {@code mDisplayContent} to top.
- stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
- final int indexOfDisplayWithPinnedStack = mWm.mRoot.mChildren.indexOf(mDisplayContent);
+ rootTask.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
+ final int indexOfDisplayWithPinnedRootTask = mWm.mRoot.mChildren.indexOf(mDisplayContent);
assertEquals("The testing DisplayContent should be moved to top with task",
- mWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack);
+ mWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedRootTask);
}
@Test
public void testMovingChildTaskOnTop() {
- // Make sure the display is trusted display which capable to move the stack to top.
+ // Make sure the display is trusted display which capable to move the root task to top.
spyOn(mDisplayContent);
doReturn(true).when(mDisplayContent).isTrusted();
- // Allow child stack to move to top.
+ // Allow child root task to move to top.
mDisplayContent.mDontMoveToTop = false;
- // The display contains pinned stack that was added in {@link #setUp}.
- Task stack = createTaskStackOnDisplay(mDisplayContent);
- Task task = createTaskInStack(stack, 0 /* userId */);
+ // The display contains pinned root task that was added in {@link #setUp}.
+ Task rootTask = createTask(mDisplayContent);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
// Add another display at top.
mWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
@@ -243,7 +242,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
mWm.mRoot.getChildCount() - 2, mWm.mRoot.mChildren.indexOf(mDisplayContent));
// Move the task of {@code mDisplayContent} to top.
- stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
+ rootTask.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
// Ensure that original display ({@code mDisplayContent}) is now on the top.
assertEquals("The testing DisplayContent should be moved to top with task",
@@ -252,16 +251,16 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
@Test
public void testDontMovingChildTaskOnTop() {
- // Make sure the display is trusted display which capable to move the stack to top.
+ // Make sure the display is trusted display which capable to move the root task to top.
spyOn(mDisplayContent);
doReturn(true).when(mDisplayContent).isTrusted();
- // Allow child stack to move to top.
+ // Allow child root task to move to top.
mDisplayContent.mDontMoveToTop = true;
- // The display contains pinned stack that was added in {@link #setUp}.
- Task stack = createTaskStackOnDisplay(mDisplayContent);
- Task task = createTaskInStack(stack, 0 /* userId */);
+ // The display contains pinned root task that was added in {@link #setUp}.
+ Task rootTask = createTask(mDisplayContent);
+ Task task = createTaskInRootTask(rootTask, 0 /* userId */);
// Add another display at top.
mWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
@@ -272,7 +271,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
mWm.mRoot.getChildCount() - 2, mWm.mRoot.mChildren.indexOf(mDisplayContent));
// Try moving the task of {@code mDisplayContent} to top.
- stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
+ rootTask.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
// Ensure that original display ({@code mDisplayContent}) hasn't moved and is not
// on the top.
@@ -282,8 +281,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
@Test
public void testReuseTaskAsRootTask() {
- final Task candidateTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task candidateTask = createTask(mDisplayContent);
final int type = ACTIVITY_TYPE_STANDARD;
assertGetOrCreateRootTask(WINDOWING_MODE_FULLSCREEN, type, candidateTask,
true /* reuseCandidate */);
@@ -312,7 +310,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
}
@Test
- public void testGetOrientation_nonResizableHomeStackWithHomeActivityPendingVisibilityChange() {
+ public void testGetOrientation_nonResizableHomeTaskWithHomeActivityPendingVisibilityChange() {
final RootWindowContainer rootWindowContainer = mWm.mAtmService.mRootWindowContainer;
final TaskDisplayArea defaultTaskDisplayArea =
rootWindowContainer.getDefaultTaskDisplayArea();
@@ -330,7 +328,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
ActivityRecord primarySplitActivity = primarySplitTask.getTopNonFinishingActivity();
assertNotNull(primarySplitActivity);
primarySplitActivity.setState(RESUMED,
- "testGetOrientation_nonResizableHomeStackWithHomeActivityPendingVisibilityChange");
+ "testGetOrientation_nonResizableHomeTaskWithHomeActivityPendingVisibilityChange");
ActivityRecord homeActivity = rootHomeTask.getTopNonFinishingActivity();
if (homeActivity == null) {
@@ -350,14 +348,14 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea",
FEATURE_VENDOR_FIRST);
- final Task firstStack = firstTaskDisplayArea.createRootTask(
+ final Task firstRootTask = firstTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final Task secondStack = secondTaskDisplayArea.createRootTask(
+ final Task secondRootTask = secondTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
- .setTask(firstStack).build();
+ .setTask(firstRootTask).build();
final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
- .setTask(secondStack).build();
+ .setTask(secondRootTask).build();
// Activity on TDA1 is focused
mDisplayContent.setFocusedApp(firstActivity);
@@ -384,14 +382,14 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea",
FEATURE_VENDOR_FIRST);
- final Task firstStack = firstTaskDisplayArea.createRootTask(
+ final Task firstRootTask = firstTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final Task secondStack = secondTaskDisplayArea.createRootTask(
+ final Task secondRootTask = secondTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
- .setTask(firstStack).build();
+ .setTask(firstRootTask).build();
final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
- .setTask(secondStack).build();
+ .setTask(secondRootTask).build();
firstTaskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
secondTaskDisplayArea.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
@@ -411,9 +409,9 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
@Test
public void testIgnoreOrientationRequest() {
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
- final Task stack = taskDisplayArea.createRootTask(
+ final Task task = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
mDisplayContent.setFocusedApp(activity);
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -428,7 +426,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
@Test
@UseTestDisplay
public void testRemove_reparentToDefault() {
- final Task task = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTask(mDisplayContent);
final TaskDisplayArea displayArea = task.getDisplayArea();
displayArea.remove();
assertTrue(displayArea.isRemoved());
@@ -442,8 +440,8 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
@Test
@UseTestDisplay
- public void testRemove_stackCreatedByOrganizer() {
- final Task task = createTaskStackOnDisplay(mDisplayContent);
+ public void testRemove_rootTaskCreatedByOrganizer() {
+ final Task task = createTask(mDisplayContent);
task.mCreatedByOrganizer = true;
final TaskDisplayArea displayArea = task.getDisplayArea();
displayArea.remove();
@@ -464,4 +462,221 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
null /* activityOptions */);
assertEquals(reuseCandidate, rootTask == candidateTask);
}
+
+ @Test
+ public void testGetOrCreateRootHomeTask_defaultDisplay() {
+ TaskDisplayArea defaultTaskDisplayArea = mWm.mRoot.getDefaultTaskDisplayArea();
+
+ // Remove the current home root task if it exists so a new one can be created below.
+ Task homeTask = defaultTaskDisplayArea.getRootHomeTask();
+ if (homeTask != null) {
+ defaultTaskDisplayArea.removeChild(homeTask);
+ }
+ assertNull(defaultTaskDisplayArea.getRootHomeTask());
+
+ assertNotNull(defaultTaskDisplayArea.getOrCreateRootHomeTask());
+ }
+
+ @Test
+ public void testGetOrCreateRootHomeTask_supportedSecondaryDisplay() {
+ DisplayContent display = createNewDisplay();
+ doReturn(true).when(display).supportsSystemDecorations();
+
+ // Remove the current home root task if it exists so a new one can be created below.
+ TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
+ Task homeTask = taskDisplayArea.getRootHomeTask();
+ if (homeTask != null) {
+ taskDisplayArea.removeChild(homeTask);
+ }
+ assertNull(taskDisplayArea.getRootHomeTask());
+
+ assertNotNull(taskDisplayArea.getOrCreateRootHomeTask());
+ }
+
+ @Test
+ public void testGetOrCreateRootHomeTask_unsupportedSystemDecorations() {
+ DisplayContent display = createNewDisplay();
+ TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
+ doReturn(false).when(display).supportsSystemDecorations();
+
+ assertNull(taskDisplayArea.getRootHomeTask());
+ assertNull(taskDisplayArea.getOrCreateRootHomeTask());
+ }
+
+ @Test
+ public void testGetOrCreateRootHomeTask_untrustedDisplay() {
+ DisplayContent display = createNewDisplay();
+ TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
+ doReturn(false).when(display).isTrusted();
+
+ assertNull(taskDisplayArea.getRootHomeTask());
+ assertNull(taskDisplayArea.getOrCreateRootHomeTask());
+ }
+
+ @Test
+ public void testGetOrCreateRootHomeTask_dontMoveToTop() {
+ DisplayContent display = createNewDisplay();
+ display.mDontMoveToTop = true;
+ TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
+
+ assertNull(taskDisplayArea.getRootHomeTask());
+ assertNull(taskDisplayArea.getOrCreateRootHomeTask());
+ }
+
+ @Test
+ public void testLastFocusedRootTaskIsUpdatedWhenMovingRootTask() {
+ // Create a root task at bottom.
+ final TaskDisplayArea taskDisplayAreas =
+ mRootWindowContainer.getDefaultDisplay().getDefaultTaskDisplayArea();
+ final Task rootTask =
+ new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build();
+ final Task prevFocusedRootTask = taskDisplayAreas.getFocusedRootTask();
+
+ rootTask.moveToFront("moveRootTaskToFront");
+ // After moving the root task to front, the previous focused should be the last focused.
+ assertTrue(rootTask.isFocusedRootTaskOnDisplay());
+ assertEquals(prevFocusedRootTask, taskDisplayAreas.getLastFocusedRootTask());
+
+ rootTask.moveToBack("moveRootTaskToBack", null /* task */);
+ // After moving the root task to back, the root task should be the last focused.
+ assertEquals(rootTask, taskDisplayAreas.getLastFocusedRootTask());
+ }
+
+ /**
+ * This test simulates the picture-in-picture menu activity launches an activity to fullscreen
+ * root task. The fullscreen root task should be the top focused for resuming correctly.
+ */
+ @Test
+ public void testFullscreenRootTaskCanBeFocusedWhenFocusablePinnedRootTaskExists() {
+ // Create a pinned root task and move to front.
+ final Task pinnedRootTask = mRootWindowContainer.getDefaultTaskDisplayArea()
+ .createRootTask(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final Task pinnedTask = new TaskBuilder(mAtm.mTaskSupervisor)
+ .setParentTask(pinnedRootTask).build();
+ new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
+ .setTask(pinnedTask).build();
+ pinnedRootTask.moveToFront("movePinnedRootTaskToFront");
+
+ // The focused root task should be the pinned root task.
+ assertTrue(pinnedRootTask.isFocusedRootTaskOnDisplay());
+
+ // Create a fullscreen root task and move to front.
+ final Task fullscreenRootTask = createTaskWithActivity(
+ mRootWindowContainer.getDefaultTaskDisplayArea(),
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP, true);
+ fullscreenRootTask.moveToFront("moveFullscreenRootTaskToFront");
+
+ // The focused root task should be the fullscreen root task.
+ assertTrue(fullscreenRootTask.isFocusedRootTaskOnDisplay());
+ }
+
+ /**
+ * Test {@link TaskDisplayArea#mPreferredTopFocusableRootTask} will be cleared when
+ * the root task is removed or moved to back, and the focused root task will be according to
+ * z-order.
+ */
+ @Test
+ public void testRootTaskShouldNotBeFocusedAfterMovingToBackOrRemoving() {
+ // Create a display which only contains 2 root task.
+ final DisplayContent display = addNewDisplayContentAt(POSITION_TOP);
+ final Task rootTask1 = createTaskWithActivity(display.getDefaultTaskDisplayArea(),
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP, true /* twoLevelTask */);
+ final Task rootTask2 = createTaskWithActivity(display.getDefaultTaskDisplayArea(),
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP, true /* twoLevelTask */);
+
+ // Put rootTask1 and rootTask2 on top.
+ rootTask1.moveToFront("moveRootTask1ToFront");
+ rootTask2.moveToFront("moveRootTask2ToFront");
+ assertTrue(rootTask2.isFocusedRootTaskOnDisplay());
+
+ // rootTask1 should be focused after moving rootTask2 to back.
+ rootTask2.moveToBack("moveRootTask2ToBack", null /* task */);
+ assertTrue(rootTask1.isFocusedRootTaskOnDisplay());
+
+ // rootTask2 should be focused after removing rootTask1.
+ rootTask1.getDisplayArea().removeRootTask(rootTask1);
+ assertTrue(rootTask2.isFocusedRootTaskOnDisplay());
+ }
+
+ /**
+ * This test enforces that alwaysOnTop root task is placed at proper position.
+ */
+ @Test
+ public void testAlwaysOnTopRootTaskLocation() {
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final Task alwaysOnTopRootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(alwaysOnTopRootTask).build();
+ alwaysOnTopRootTask.setAlwaysOnTop(true);
+ taskDisplayArea.positionChildAt(POSITION_TOP, alwaysOnTopRootTask,
+ false /* includingParents */);
+ assertTrue(alwaysOnTopRootTask.isAlwaysOnTop());
+ // Ensure always on top state is synced to the children of the root task.
+ assertTrue(alwaysOnTopRootTask.getTopNonFinishingActivity().isAlwaysOnTop());
+ assertEquals(alwaysOnTopRootTask, taskDisplayArea.getTopRootTask());
+
+ final Task pinnedRootTask = taskDisplayArea.createRootTask(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ assertEquals(pinnedRootTask, taskDisplayArea.getRootPinnedTask());
+ assertEquals(pinnedRootTask, taskDisplayArea.getTopRootTask());
+
+ final Task anotherAlwaysOnTopRootTask = taskDisplayArea.createRootTask(
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ anotherAlwaysOnTopRootTask.setAlwaysOnTop(true);
+ taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopRootTask,
+ false /* includingParents */);
+ assertTrue(anotherAlwaysOnTopRootTask.isAlwaysOnTop());
+ int topPosition = taskDisplayArea.getRootTaskCount() - 1;
+ // Ensure the new alwaysOnTop root task is put below the pinned root task, but on top of the
+ // existing alwaysOnTop root task.
+ assertEquals(topPosition - 1, getTaskIndexOf(taskDisplayArea, anotherAlwaysOnTopRootTask));
+
+ final Task nonAlwaysOnTopRootTask = taskDisplayArea.createRootTask(
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ assertEquals(taskDisplayArea, nonAlwaysOnTopRootTask.getDisplayArea());
+ topPosition = taskDisplayArea.getRootTaskCount() - 1;
+ // Ensure the non-alwaysOnTop root task is put below the three alwaysOnTop root tasks, but
+ // above the existing other non-alwaysOnTop root tasks.
+ assertEquals(topPosition - 3, getTaskIndexOf(taskDisplayArea, nonAlwaysOnTopRootTask));
+
+ anotherAlwaysOnTopRootTask.setAlwaysOnTop(false);
+ taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopRootTask,
+ false /* includingParents */);
+ assertFalse(anotherAlwaysOnTopRootTask.isAlwaysOnTop());
+ // Ensure, when always on top is turned off for a root task, the root task is put just below
+ // all other always on top root tasks.
+ assertEquals(topPosition - 2, getTaskIndexOf(taskDisplayArea, anotherAlwaysOnTopRootTask));
+ anotherAlwaysOnTopRootTask.setAlwaysOnTop(true);
+
+ // Ensure always on top state changes properly when windowing mode changes.
+ anotherAlwaysOnTopRootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertFalse(anotherAlwaysOnTopRootTask.isAlwaysOnTop());
+ assertEquals(topPosition - 2, getTaskIndexOf(taskDisplayArea, anotherAlwaysOnTopRootTask));
+ anotherAlwaysOnTopRootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertTrue(anotherAlwaysOnTopRootTask.isAlwaysOnTop());
+ assertEquals(topPosition - 1, getTaskIndexOf(taskDisplayArea, anotherAlwaysOnTopRootTask));
+
+ final Task dreamRootTask = taskDisplayArea.createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM, true /* onTop */);
+ assertEquals(taskDisplayArea, dreamRootTask.getDisplayArea());
+ assertTrue(dreamRootTask.isAlwaysOnTop());
+ topPosition = taskDisplayArea.getRootTaskCount() - 1;
+ // Ensure dream shows above all activities, including PiP
+ assertEquals(dreamRootTask, taskDisplayArea.getTopRootTask());
+ assertEquals(topPosition - 1, getTaskIndexOf(taskDisplayArea, pinnedRootTask));
+
+ final Task assistRootTask = taskDisplayArea.createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
+ assertEquals(taskDisplayArea, assistRootTask.getDisplayArea());
+ assertFalse(assistRootTask.isAlwaysOnTop());
+ topPosition = taskDisplayArea.getRootTaskCount() - 1;
+
+ // Ensure Assistant shows as a non-always-on-top activity when config_assistantOnTopOfDream
+ // is false and on top of everything when true.
+ final boolean isAssistantOnTop = mContext.getResources()
+ .getBoolean(com.android.internal.R.bool.config_assistantOnTopOfDream);
+ assertEquals(isAssistantOnTop ? topPosition : topPosition - 4,
+ getTaskIndexOf(taskDisplayArea, assistRootTask));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index ed5729400a39..de4c40df1c79 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -403,8 +403,8 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
public void testOverridesDisplayAreaWithStandardTypeAndFullscreenMode() {
final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay,
mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
- final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+ final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
launchRoot.mCreatedByOrganizer = true;
secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN },
@@ -419,8 +419,8 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
public void testOverridesDisplayAreaWithHomeTypeAndFullscreenMode() {
final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay,
mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
- final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+ final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
launchRoot.mCreatedByOrganizer = true;
mActivity.setActivityType(ACTIVITY_TYPE_HOME);
@@ -438,8 +438,8 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
WINDOWING_MODE_FREEFORM);
final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(freeformDisplay,
mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
- final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+ final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
launchRoot.mCreatedByOrganizer = true;
secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
@@ -455,8 +455,8 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
public void testNotOverrideDisplayAreaWhenActivityOptionsHasDisplayArea() {
final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay,
mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
- final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+ final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
launchRoot.mCreatedByOrganizer = true;
secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN },
@@ -481,8 +481,8 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
secondaryDisplayArea.setBounds(DISPLAY_BOUNDS.width() / 2, 0,
DISPLAY_BOUNDS.width(), DISPLAY_BOUNDS.height());
- final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+ final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
launchRoot.mCreatedByOrganizer = true;
secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
new int[] { ACTIVITY_TYPE_STANDARD });
@@ -512,8 +512,8 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
secondaryDisplayArea.setBounds(DISPLAY_BOUNDS.width() / 2, 0,
DISPLAY_BOUNDS.width(), DISPLAY_BOUNDS.height());
- final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+ final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
launchRoot.mCreatedByOrganizer = true;
secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
new int[] { ACTIVITY_TYPE_STANDARD });
@@ -1687,16 +1687,16 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
}
private ActivityRecord createSourceActivity(TestDisplayContent display) {
- final Task stack = display.getDefaultTaskDisplayArea()
+ final Task rootTask = display.getDefaultTaskDisplayArea()
.createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
- return new ActivityBuilder(mAtm).setTask(stack).build();
+ return new ActivityBuilder(mAtm).setTask(rootTask).build();
}
private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
- final Task stack = display.getDefaultTaskDisplayArea()
+ final Task rootTask = display.getDefaultTaskDisplayArea()
.createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
- stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
- final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
+ rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
// Just work around the unnecessary adjustments for bounds.
task.getWindowConfiguration().setBounds(bounds);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
deleted file mode 100644
index d853b930af11..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ /dev/null
@@ -1,1161 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-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_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
-import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.util.DisplayMetrics.DENSITY_DEFAULT;
-import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_90;
-import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.sameInstance;
-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.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.same;
-
-import android.app.ActivityManager;
-import android.app.TaskInfo;
-import android.app.WindowConfiguration;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.platform.test.annotations.Presubmit;
-import android.util.DisplayMetrics;
-import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
-import android.util.Xml;
-import android.view.DisplayInfo;
-
-import androidx.test.filters.MediumTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-
-/**
- * Tests for exercising {@link Task}.
- *
- * Build/Install/Run:
- * atest WmTests:TaskRecordTests
- */
-@MediumTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class TaskRecordTests extends WindowTestsBase {
-
- private static final String TASK_TAG = "task";
-
- private Rect mParentBounds;
-
- @Before
- public void setUp() throws Exception {
- mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
- removeGlobalMinSizeRestriction();
- }
-
- @Test
- public void testRestoreWindowedTask() throws Exception {
- final Task expected = createTask(64);
- expected.mLastNonFullscreenBounds = new Rect(50, 50, 100, 100);
-
- final byte[] serializedBytes = serializeToBytes(expected);
- final Task actual = restoreFromBytes(serializedBytes);
- assertEquals(expected.mTaskId, actual.mTaskId);
- assertEquals(expected.mLastNonFullscreenBounds, actual.mLastNonFullscreenBounds);
- }
-
- /** Ensure we have no chance to modify the original intent. */
- @Test
- public void testCopyBaseIntentForTaskInfo() {
- final Task task = createTask(1);
- task.setTaskDescription(new ActivityManager.TaskDescription());
- final TaskInfo info = task.getTaskInfo();
-
- // The intent of info should be a copy so assert that they are different instances.
- assertThat(info.baseIntent, not(sameInstance(task.getBaseIntent())));
- }
-
- @Test
- public void testReturnsToHomeStack() throws Exception {
- final Task task = createTask(1);
- spyOn(task);
- doReturn(true).when(task).hasChild();
- assertFalse(task.returnsToHomeRootTask());
- task.intent = null;
- assertFalse(task.returnsToHomeRootTask());
- task.intent = new Intent();
- assertFalse(task.returnsToHomeRootTask());
- task.intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
- assertTrue(task.returnsToHomeRootTask());
- }
-
- /** Ensures that empty bounds cause appBounds to inherit from parent. */
- @Test
- public void testAppBounds_EmptyBounds() {
- final Rect emptyBounds = new Rect();
- testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, emptyBounds,
- mParentBounds);
- }
-
- /** Ensures that bounds on freeform stacks are not clipped. */
- @Test
- public void testAppBounds_FreeFormBounds() {
- final Rect freeFormBounds = new Rect(mParentBounds);
- freeFormBounds.offset(10, 10);
- testStackBoundsConfiguration(WINDOWING_MODE_FREEFORM, mParentBounds, freeFormBounds,
- freeFormBounds);
- }
-
- /** Ensures that fully contained bounds are not clipped. */
- @Test
- public void testAppBounds_ContainedBounds() {
- final Rect insetBounds = new Rect(mParentBounds);
- insetBounds.inset(5, 5, 5, 5);
- testStackBoundsConfiguration(
- WINDOWING_MODE_FREEFORM, mParentBounds, insetBounds, insetBounds);
- }
-
- @Test
- public void testFitWithinBounds() {
- final Rect parentBounds = new Rect(10, 10, 200, 200);
- TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
- Task stack = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM,
- ACTIVITY_TYPE_STANDARD, true /* onTop */);
- Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
- final Configuration parentConfig = stack.getConfiguration();
- parentConfig.windowConfiguration.setBounds(parentBounds);
- parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
-
- // check top and left
- Rect reqBounds = new Rect(-190, -190, 0, 0);
- task.setBounds(reqBounds);
- // Make sure part of it is exposed
- assertTrue(task.getBounds().right > parentBounds.left);
- assertTrue(task.getBounds().bottom > parentBounds.top);
- // Should still be more-or-less in that corner
- assertTrue(task.getBounds().left <= parentBounds.left);
- assertTrue(task.getBounds().top <= parentBounds.top);
-
- assertEquals(reqBounds.width(), task.getBounds().width());
- assertEquals(reqBounds.height(), task.getBounds().height());
-
- // check bottom and right
- reqBounds = new Rect(210, 210, 400, 400);
- task.setBounds(reqBounds);
- // Make sure part of it is exposed
- assertTrue(task.getBounds().left < parentBounds.right);
- assertTrue(task.getBounds().top < parentBounds.bottom);
- // Should still be more-or-less in that corner
- assertTrue(task.getBounds().right >= parentBounds.right);
- assertTrue(task.getBounds().bottom >= parentBounds.bottom);
-
- assertEquals(reqBounds.width(), task.getBounds().width());
- assertEquals(reqBounds.height(), task.getBounds().height());
- }
-
- /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
- @Test
- public void testBoundsOnModeChangeFreeformToFullscreen() {
- DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
- Task stack = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true)
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- Task task = stack.getBottomMostTask();
- task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
- DisplayInfo info = new DisplayInfo();
- display.mDisplay.getDisplayInfo(info);
- final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
- final Rect freeformBounds = new Rect(fullScreenBounds);
- freeformBounds.inset((int) (freeformBounds.width() * 0.2),
- (int) (freeformBounds.height() * 0.2));
- task.setBounds(freeformBounds);
-
- assertEquals(freeformBounds, task.getBounds());
-
- // FULLSCREEN inherits bounds
- stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- assertEquals(fullScreenBounds, task.getBounds());
- assertEquals(freeformBounds, task.mLastNonFullscreenBounds);
-
- // FREEFORM restores bounds
- stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
- assertEquals(freeformBounds, task.getBounds());
- }
-
- /**
- * Tests that a task with forced orientation has orientation-consistent bounds within the
- * parent.
- */
- @Test
- public void testFullscreenBoundsForcedOrientation() {
- final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
- final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
- final DisplayContent display = new TestDisplayContent.Builder(mAtm,
- fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
- assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
- // Fix the display orientation to landscape which is the natural rotation (0) for the test
- // display.
- final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
- dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
- dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
-
- final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true)
- .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- final Task task = stack.getBottomMostTask();
- final ActivityRecord root = task.getTopNonFinishingActivity();
-
- assertEquals(fullScreenBounds, task.getBounds());
-
- // Setting app to fixed portrait fits within parent
- root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
- assertEquals(root, task.getRootActivity());
- assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
- // Portrait orientation is enforced on activity level. Task should fill fullscreen bounds.
- assertThat(task.getBounds().height()).isLessThan(task.getBounds().width());
- assertEquals(fullScreenBounds, task.getBounds());
-
- // Top activity gets used
- final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setParentTask(stack)
- .build();
- assertEquals(top, task.getTopNonFinishingActivity());
- top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
- assertEquals(task.getBounds().width(), fullScreenBounds.width());
-
- // Setting app to unspecified restores
- top.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
- assertEquals(fullScreenBounds, task.getBounds());
-
- // Setting app to fixed landscape and changing display
- top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- // Fix the display orientation to portrait which is 90 degrees for the test display.
- dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90);
-
- // Fixed orientation request should be resolved on activity level. Task fills display
- // bounds.
- assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
- assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
- assertEquals(fullScreenBoundsPort, task.getBounds());
-
- // in FREEFORM, no constraint
- final Rect freeformBounds = new Rect(display.getBounds());
- freeformBounds.inset((int) (freeformBounds.width() * 0.2),
- (int) (freeformBounds.height() * 0.2));
- stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
- task.setBounds(freeformBounds);
- assertEquals(freeformBounds, task.getBounds());
-
- // FULLSCREEN letterboxes bounds on activity level, no constraint on task level.
- stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
- assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
- assertEquals(fullScreenBoundsPort, task.getBounds());
-
- // FREEFORM restores bounds as before
- stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
- assertEquals(freeformBounds, task.getBounds());
- }
-
- @Test
- public void testReportsOrientationRequestInLetterboxForOrientation() {
- final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
- final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
- final DisplayContent display = new TestDisplayContent.Builder(mAtm,
- fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
- assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
- // Fix the display orientation to landscape which is the natural rotation (0) for the test
- // display.
- final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
- dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
- dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
-
- final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true)
- .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- final Task task = stack.getBottomMostTask();
- ActivityRecord root = task.getTopNonFinishingActivity();
-
- assertEquals(fullScreenBounds, task.getBounds());
-
- // Setting app to fixed portrait fits within parent on activity level. Task fills parent.
- root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
- assertThat(root.getBounds().width()).isLessThan(root.getBounds().height());
- assertEquals(task.getBounds(), fullScreenBounds);
-
- assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getOrientation());
- }
-
- @Test
- public void testIgnoresForcedOrientationWhenParentHandles() {
- final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
- DisplayContent display = new TestDisplayContent.Builder(
- mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
-
- display.getRequestedOverrideConfiguration().orientation =
- Configuration.ORIENTATION_LANDSCAPE;
- display.onRequestedOverrideConfigurationChanged(
- display.getRequestedOverrideConfiguration());
- Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true)
- .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
- Task task = stack.getBottomMostTask();
- ActivityRecord root = task.getTopNonFinishingActivity();
-
- final WindowContainer parentWindowContainer =
- new WindowContainer(mSystemServicesTestRule.getWindowManagerService());
- spyOn(parentWindowContainer);
- parentWindowContainer.setBounds(fullScreenBounds);
- doReturn(parentWindowContainer).when(task).getParent();
- doReturn(display.getDefaultTaskDisplayArea()).when(task).getDisplayArea();
- doReturn(stack).when(task).getRootTask();
- doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
-
- // Setting app to fixed portrait fits within parent, but Task shouldn't adjust the
- // bounds because its parent says it will handle it at a later time.
- root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
- assertEquals(root, task.getRootActivity());
- assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
- assertEquals(fullScreenBounds, task.getBounds());
- }
-
- @Test
- public void testComputeConfigResourceOverrides() {
- final Rect fullScreenBounds = new Rect(0, 0, 1080, 1920);
- TestDisplayContent display = new TestDisplayContent.Builder(
- mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
- final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
- final Configuration inOutConfig = new Configuration();
- final Configuration parentConfig = new Configuration();
- final int longSide = 1200;
- final int shortSide = 600;
- final Rect parentBounds = new Rect(0, 0, 250, 500);
- final Rect parentAppBounds = new Rect(0, 0, 250, 480);
- parentConfig.windowConfiguration.setBounds(parentBounds);
- parentConfig.windowConfiguration.setAppBounds(parentAppBounds);
- parentConfig.densityDpi = 400;
- parentConfig.screenHeightDp = (parentBounds.bottom * 160) / parentConfig.densityDpi; // 200
- parentConfig.screenWidthDp = (parentBounds.right * 160) / parentConfig.densityDpi; // 100
- parentConfig.windowConfiguration.setRotation(ROTATION_0);
-
- // By default, the input bounds will fill parent.
- task.computeConfigResourceOverrides(inOutConfig, parentConfig);
-
- assertEquals(parentConfig.screenHeightDp, inOutConfig.screenHeightDp);
- assertEquals(parentConfig.screenWidthDp, inOutConfig.screenWidthDp);
- assertEquals(parentAppBounds, inOutConfig.windowConfiguration.getAppBounds());
- assertEquals(Configuration.ORIENTATION_PORTRAIT, inOutConfig.orientation);
-
- // If bounds are overridden, config properties should be made to match. Surface hierarchy
- // will crop for policy.
- inOutConfig.setToDefaults();
- final Rect largerPortraitBounds = new Rect(0, 0, shortSide, longSide);
- inOutConfig.windowConfiguration.setBounds(largerPortraitBounds);
- task.computeConfigResourceOverrides(inOutConfig, parentConfig);
- // The override bounds are beyond the parent, the out appBounds should not be intersected
- // by parent appBounds.
- assertEquals(largerPortraitBounds, inOutConfig.windowConfiguration.getAppBounds());
- assertEquals(longSide, inOutConfig.screenHeightDp * parentConfig.densityDpi / 160);
- assertEquals(shortSide, inOutConfig.screenWidthDp * parentConfig.densityDpi / 160);
-
- inOutConfig.setToDefaults();
- // Landscape bounds.
- final Rect largerLandscapeBounds = new Rect(0, 0, longSide, shortSide);
- inOutConfig.windowConfiguration.setBounds(largerLandscapeBounds);
-
- // Setup the display with a top stable inset. The later assertion will ensure the inset is
- // excluded from screenHeightDp.
- final int statusBarHeight = 100;
- final DisplayPolicy policy = display.getDisplayPolicy();
- doAnswer(invocationOnMock -> {
- final Rect insets = invocationOnMock.<Rect>getArgument(0);
- insets.top = statusBarHeight;
- return null;
- }).when(policy).convertNonDecorInsetsToStableInsets(any(), eq(ROTATION_0));
-
- // Without limiting to be inside the parent bounds, the out screen size should keep relative
- // to the input bounds.
- final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
- final ActivityRecord.CompatDisplayInsets compatIntsets =
- new ActivityRecord.CompatDisplayInsets(
- display, activity, /* fixedOrientationBounds= */ null);
- task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
-
- assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
- assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
- inOutConfig.screenHeightDp);
- assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
- inOutConfig.screenWidthDp);
- assertEquals(Configuration.ORIENTATION_LANDSCAPE, inOutConfig.orientation);
- }
-
- @Test
- public void testComputeConfigResourceLayoutOverrides() {
- final Rect fullScreenBounds = new Rect(0, 0, 1000, 2500);
- TestDisplayContent display = new TestDisplayContent.Builder(
- mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
- final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
- final Configuration inOutConfig = new Configuration();
- final Configuration parentConfig = new Configuration();
- final Rect nonLongBounds = new Rect(0, 0, 1000, 1250);
- parentConfig.windowConfiguration.setBounds(fullScreenBounds);
- parentConfig.windowConfiguration.setAppBounds(fullScreenBounds);
- parentConfig.densityDpi = 400;
- parentConfig.screenHeightDp = (fullScreenBounds.bottom * 160) / parentConfig.densityDpi;
- parentConfig.screenWidthDp = (fullScreenBounds.right * 160) / parentConfig.densityDpi;
- parentConfig.windowConfiguration.setRotation(ROTATION_0);
-
- // Set BOTH screenW/H to an override value
- inOutConfig.screenWidthDp = nonLongBounds.width() * 160 / parentConfig.densityDpi;
- inOutConfig.screenHeightDp = nonLongBounds.height() * 160 / parentConfig.densityDpi;
- task.computeConfigResourceOverrides(inOutConfig, parentConfig);
-
- // screenLayout should honor override when both screenW/H are set.
- assertTrue((inOutConfig.screenLayout & Configuration.SCREENLAYOUT_LONG_NO) != 0);
- }
-
- @Test
- public void testComputeNestedConfigResourceOverrides() {
- final Task task = new TaskBuilder(mSupervisor).build();
- assertTrue(task.getResolvedOverrideBounds().isEmpty());
- int origScreenH = task.getConfiguration().screenHeightDp;
- Configuration stackConfig = new Configuration();
- stackConfig.setTo(task.getRootTask().getRequestedOverrideConfiguration());
- stackConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-
- // Set bounds on stack (not task) and verify that the task resource configuration changes
- // despite it's override bounds being empty.
- Rect bounds = new Rect(task.getRootTask().getBounds());
- bounds.bottom = (int) (bounds.bottom * 0.6f);
- stackConfig.windowConfiguration.setBounds(bounds);
- task.getRootTask().onRequestedOverrideConfigurationChanged(stackConfig);
- assertNotEquals(origScreenH, task.getConfiguration().screenHeightDp);
- }
-
- @Test
- public void testFullScreenTaskNotAdjustedByMinimalSize() {
- final Task fullscreenTask = new TaskBuilder(mSupervisor).build();
- final Rect originalTaskBounds = new Rect(fullscreenTask.getBounds());
- final ActivityInfo aInfo = new ActivityInfo();
- aInfo.windowLayout = new ActivityInfo.WindowLayout(0 /* width */, 0 /* widthFraction */,
- 0 /* height */, 0 /* heightFraction */, 0 /* gravity */,
- originalTaskBounds.width() * 2 /* minWidth */,
- originalTaskBounds.height() * 2 /* minHeight */);
- fullscreenTask.setMinDimensions(aInfo);
- fullscreenTask.onConfigurationChanged(fullscreenTask.getParent().getConfiguration());
-
- assertEquals(originalTaskBounds, fullscreenTask.getBounds());
- }
-
- @Test
- public void testInsetDisregardedWhenFreeformOverlapsNavBar() {
- TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
- Task stack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, true /* onTop */);
- DisplayInfo displayInfo = new DisplayInfo();
- mAtm.mContext.getDisplay().getDisplayInfo(displayInfo);
- final int displayHeight = displayInfo.logicalHeight;
- final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
- final Configuration inOutConfig = new Configuration();
- final Configuration parentConfig = new Configuration();
- final int longSide = 1200;
- final int shortSide = 600;
- parentConfig.densityDpi = 400;
- parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
- parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
- parentConfig.windowConfiguration.setRotation(ROTATION_0);
-
- final int longSideDp = 480; // longSide / density = 1200 / 400 * 160
- final int shortSideDp = 240; // shortSide / density = 600 / 400 * 160
- final int screenLayout = parentConfig.screenLayout
- & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
- final int reducedScreenLayout =
- Configuration.reduceScreenLayout(screenLayout, longSideDp, shortSideDp);
-
- // Portrait bounds overlapping with navigation bar, without insets.
- final Rect freeformBounds = new Rect(0,
- displayHeight - 10 - longSide,
- shortSide,
- displayHeight - 10);
- inOutConfig.windowConfiguration.setBounds(freeformBounds);
- // Set to freeform mode to verify bug fix.
- inOutConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-
- task.computeConfigResourceOverrides(inOutConfig, parentConfig);
-
- // screenW/H should not be effected by parent since overridden and freeform
- assertEquals(freeformBounds.width() * 160 / parentConfig.densityDpi,
- inOutConfig.screenWidthDp);
- assertEquals(freeformBounds.height() * 160 / parentConfig.densityDpi,
- inOutConfig.screenHeightDp);
- assertEquals(reducedScreenLayout, inOutConfig.screenLayout);
-
- inOutConfig.setToDefaults();
- // Landscape bounds overlapping with navigtion bar, without insets.
- freeformBounds.set(0,
- displayHeight - 10 - shortSide,
- longSide,
- displayHeight - 10);
- inOutConfig.windowConfiguration.setBounds(freeformBounds);
- inOutConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-
- task.computeConfigResourceOverrides(inOutConfig, parentConfig);
-
- assertEquals(freeformBounds.width() * 160 / parentConfig.densityDpi,
- inOutConfig.screenWidthDp);
- assertEquals(freeformBounds.height() * 160 / parentConfig.densityDpi,
- inOutConfig.screenHeightDp);
- assertEquals(reducedScreenLayout, inOutConfig.screenLayout);
- }
-
- /** Ensures that the alias intent won't have target component resolved. */
- @Test
- public void testTaskIntentActivityAlias() {
- final String aliasClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".aliasActivity";
- final String targetClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".targetActivity";
- final ComponentName aliasComponent =
- new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, aliasClassName);
- final ComponentName targetComponent =
- new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, targetClassName);
-
- final Intent intent = new Intent();
- intent.setComponent(aliasComponent);
- final ActivityInfo info = new ActivityInfo();
- info.applicationInfo = new ApplicationInfo();
- info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
- info.targetActivity = targetClassName;
-
- final Task task = new Task.Builder(mAtm)
- .setTaskId(1)
- .setActivityInfo(info)
- .setIntent(intent)
- .build();
- assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
- task.intent.getComponent().getClassName());
-
- ActivityRecord aliasActivity = new ActivityBuilder(mAtm).setComponent(
- aliasComponent).setTargetActivity(targetClassName).build();
- assertEquals("Should be the same intent filter.", true,
- task.isSameIntentFilter(aliasActivity));
-
- ActivityRecord targetActivity = new ActivityBuilder(mAtm).setComponent(
- targetComponent).build();
- assertEquals("Should be the same intent filter.", true,
- task.isSameIntentFilter(targetActivity));
-
- ActivityRecord defaultActivity = new ActivityBuilder(mAtm).build();
- assertEquals("Should not be the same intent filter.", false,
- task.isSameIntentFilter(defaultActivity));
- }
-
- /** Test that root activity index is reported correctly for several activities in the task. */
- @Test
- public void testFindRootIndex() {
- final Task task = getTestTask();
- // Add an extra activity on top of the root one
- new ActivityBuilder(mAtm).setTask(task).build();
-
- assertEquals("The root activity in the task must be reported.", task.getChildAt(0),
- task.getRootActivity(
- true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
- }
-
- /**
- * Test that root activity index is reported correctly for several activities in the task when
- * the activities on the bottom are finishing.
- */
- @Test
- public void testFindRootIndex_finishing() {
- final Task task = getTestTask();
- // Add extra two activities and mark the two on the bottom as finishing.
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.finishing = true;
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
- activity1.finishing = true;
- new ActivityBuilder(mAtm).setTask(task).build();
-
- assertEquals("The first non-finishing activity in the task must be reported.",
- task.getChildAt(2), task.getRootActivity(
- true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
- }
-
- /**
- * Test that root activity index is reported correctly for several activities in the task when
- * looking for the 'effective root'.
- */
- @Test
- public void testFindRootIndex_effectiveRoot() {
- final Task task = getTestTask();
- // Add an extra activity on top of the root one
- new ActivityBuilder(mAtm).setTask(task).build();
-
- assertEquals("The root activity in the task must be reported.",
- task.getChildAt(0), task.getRootActivity(
- false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
- }
-
- /**
- * Test that root activity index is reported correctly when looking for the 'effective root' in
- * case when bottom activities are relinquishing task identity or finishing.
- */
- @Test
- public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() {
- final Task task = getTestTask();
- // Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
- // one above as finishing.
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
- activity1.finishing = true;
- new ActivityBuilder(mAtm).setTask(task).build();
-
- assertEquals("The first non-finishing activity and non-relinquishing task identity "
- + "must be reported.", task.getChildAt(2), task.getRootActivity(
- false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
- }
-
- /**
- * Test that root activity index is reported correctly when looking for the 'effective root'
- * for the case when there is only a single activity that also has relinquishTaskIdentity set.
- */
- @Test
- public void testFindRootIndex_effectiveRoot_relinquishingAndSingleActivity() {
- final Task task = getTestTask();
- // Set relinquishTaskIdentity for the only activity in the task
- task.getBottomMostActivity().info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
-
- assertEquals("The root activity in the task must be reported.",
- task.getChildAt(0), task.getRootActivity(
- false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
- }
-
- /**
- * Test that the topmost activity index is reported correctly when looking for the
- * 'effective root' for the case when all activities have relinquishTaskIdentity set.
- */
- @Test
- public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
- final Task task = getTestTask();
- // Set relinquishTaskIdentity for all activities in the task
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
- activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
-
- assertEquals("The topmost activity in the task must be reported.",
- task.getChildAt(task.getChildCount() - 1), task.getRootActivity(
- false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
- }
-
- /** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */
- @Test
- public void testGetRootActivity() {
- final Task task = getTestTask();
- // Add an extra activity on top of the root one
- new ActivityBuilder(mAtm).setTask(task).build();
-
- assertEquals("The root activity in the task must be reported.",
- task.getBottomMostActivity(), task.getRootActivity());
- }
-
- /**
- * Test that first non-finishing activity is reported in {@link Task#getRootActivity()}.
- */
- @Test
- public void testGetRootActivity_finishing() {
- final Task task = getTestTask();
- // Add an extra activity on top of the root one
- new ActivityBuilder(mAtm).setTask(task).build();
- // Mark the root as finishing
- task.getBottomMostActivity().finishing = true;
-
- assertEquals("The first non-finishing activity in the task must be reported.",
- task.getChildAt(1), task.getRootActivity());
- }
-
- /**
- * Test that relinquishTaskIdentity flag is ignored in {@link Task#getRootActivity()}.
- */
- @Test
- public void testGetRootActivity_relinquishTaskIdentity() {
- final Task task = getTestTask();
- // Mark the bottom-most activity with FLAG_RELINQUISH_TASK_IDENTITY.
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
- // Add an extra activity on top of the root one.
- new ActivityBuilder(mAtm).setTask(task).build();
-
- assertEquals("The root activity in the task must be reported.",
- task.getBottomMostActivity(), task.getRootActivity());
- }
-
- /**
- * Test that no activity is reported in {@link Task#getRootActivity()} when all activities
- * in the task are finishing.
- */
- @Test
- public void testGetRootActivity_allFinishing() {
- final Task task = getTestTask();
- // Mark the bottom-most activity as finishing.
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.finishing = true;
- // Add an extra activity on top of the root one and mark it as finishing
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
- activity1.finishing = true;
-
- assertNull("No activity must be reported if all are finishing", task.getRootActivity());
- }
-
- /**
- * Test that first non-finishing activity is the root of task.
- */
- @Test
- public void testIsRootActivity() {
- final Task task = getTestTask();
- // Mark the bottom-most activity as finishing.
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.finishing = true;
- // Add an extra activity on top of the root one.
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
-
- assertFalse("Finishing activity must not be the root of task", activity0.isRootOfTask());
- assertTrue("Non-finishing activity must be the root of task", activity1.isRootOfTask());
- }
-
- /**
- * Test that if all activities in the task are finishing, then the one on the bottom is the
- * root of task.
- */
- @Test
- public void testIsRootActivity_allFinishing() {
- final Task task = getTestTask();
- // Mark the bottom-most activity as finishing.
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.finishing = true;
- // Add an extra activity on top of the root one and mark it as finishing
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
- activity1.finishing = true;
-
- assertTrue("Bottom activity must be the root of task", activity0.isRootOfTask());
- assertFalse("Finishing activity on top must not be the root of task",
- activity1.isRootOfTask());
- }
-
- /**
- * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)}.
- */
- @Test
- public void testGetTaskForActivity() {
- final Task task0 = getTestTask();
- final ActivityRecord activity0 = task0.getBottomMostActivity();
-
- final Task task1 = getTestTask();
- final ActivityRecord activity1 = task1.getBottomMostActivity();
-
- assertEquals(task0.mTaskId,
- ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
- assertEquals(task1.mTaskId,
- ActivityRecord.getTaskForActivityLocked(activity1.appToken, false /* onlyRoot */));
- }
-
- /**
- * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with finishing
- * activity.
- */
- @Test
- public void testGetTaskForActivity_onlyRoot_finishing() {
- final Task task = getTestTask();
- // Make the current root activity finishing
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.finishing = true;
- // Add an extra activity on top - this will be the new root
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
- // Add one more on top
- final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
-
- assertEquals(task.mTaskId,
- ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
- assertEquals(task.mTaskId,
- ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
- assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
- ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
- }
-
- /**
- * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with activity that
- * relinquishes task identity.
- */
- @Test
- public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
- final Task task = getTestTask();
- // Make the current root activity relinquish task identity
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
- // Add an extra activity on top - this will be the new root
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
- // Add one more on top
- final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
-
- assertEquals(task.mTaskId,
- ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
- assertEquals(task.mTaskId,
- ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
- assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
- ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
- }
-
- /**
- * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} allowing non-root
- * entries.
- */
- @Test
- public void testGetTaskForActivity_notOnlyRoot() {
- final Task task = getTestTask();
- // Mark the bottom-most activity as finishing.
- final ActivityRecord activity0 = task.getBottomMostActivity();
- activity0.finishing = true;
-
- // Add an extra activity on top of the root one and make it relinquish task identity
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
- activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
-
- // Add one more activity on top
- final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
-
- assertEquals(task.mTaskId,
- ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
- assertEquals(task.mTaskId,
- ActivityRecord.getTaskForActivityLocked(activity1.appToken, false /* onlyRoot */));
- assertEquals(task.mTaskId,
- ActivityRecord.getTaskForActivityLocked(activity2.appToken, false /* onlyRoot */));
- }
-
- /**
- * Test {@link Task#updateEffectiveIntent()}.
- */
- @Test
- public void testUpdateEffectiveIntent() {
- // Test simple case with a single activity.
- final Task task = getTestTask();
- final ActivityRecord activity0 = task.getBottomMostActivity();
-
- spyOn(task);
- task.updateEffectiveIntent();
- verify(task).setIntent(eq(activity0));
- }
-
- /**
- * Test {@link Task#updateEffectiveIntent()} with root activity marked as finishing. This
- * should make the task use the second activity when updating the intent.
- */
- @Test
- public void testUpdateEffectiveIntent_rootFinishing() {
- // Test simple case with a single activity.
- final Task task = getTestTask();
- final ActivityRecord activity0 = task.getBottomMostActivity();
- // Mark the bottom-most activity as finishing.
- activity0.finishing = true;
- // Add an extra activity on top of the root one
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
-
- spyOn(task);
- task.updateEffectiveIntent();
- verify(task).setIntent(eq(activity1));
- }
-
- /**
- * Test {@link Task#updateEffectiveIntent()} when all activities are finishing or
- * relinquishing task identity. In this case the root activity should still be used when
- * updating the intent (legacy behavior).
- */
- @Test
- public void testUpdateEffectiveIntent_allFinishing() {
- // Test simple case with a single activity.
- final Task task = getTestTask();
- final ActivityRecord activity0 = task.getBottomMostActivity();
- // Mark the bottom-most activity as finishing.
- activity0.finishing = true;
- // Add an extra activity on top of the root one and make it relinquish task identity
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
- activity1.finishing = true;
-
- // Task must still update the intent using the root activity (preserving legacy behavior).
- spyOn(task);
- task.updateEffectiveIntent();
- verify(task).setIntent(eq(activity0));
- }
-
- @Test
- public void testSaveLaunchingStateWhenConfigurationChanged() {
- LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
- spyOn(persister);
-
- final Task task = getTestTask();
- task.setHasBeenVisible(false);
- task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
- task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-
- task.setHasBeenVisible(true);
- task.onConfigurationChanged(task.getParent().getConfiguration());
-
- verify(persister).saveTask(task, task.getDisplayContent());
- }
-
- @Test
- public void testSaveLaunchingStateWhenClearingParent() {
- LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
- spyOn(persister);
-
- final Task task = getTestTask();
- task.setHasBeenVisible(false);
- task.getDisplayContent().setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
- task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- final DisplayContent oldDisplay = task.getDisplayContent();
-
- LaunchParamsController.LaunchParams params = new LaunchParamsController.LaunchParams();
- params.mWindowingMode = WINDOWING_MODE_UNDEFINED;
- persister.getLaunchParams(task, null, params);
- assertEquals(WINDOWING_MODE_UNDEFINED, params.mWindowingMode);
-
- task.setHasBeenVisible(true);
- task.removeImmediately();
-
- verify(persister).saveTask(task, oldDisplay);
-
- persister.getLaunchParams(task, null, params);
- assertEquals(WINDOWING_MODE_FULLSCREEN, params.mWindowingMode);
- }
-
- @Test
- public void testNotSaveLaunchingStateNonFreeformDisplay() {
- LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
- spyOn(persister);
-
- final Task task = getTestTask();
- task.setHasBeenVisible(false);
- task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-
- task.setHasBeenVisible(true);
- task.onConfigurationChanged(task.getParent().getConfiguration());
-
- verify(persister, never()).saveTask(same(task), any());
- }
-
- @Test
- public void testNotSaveLaunchingStateWhenNotFullscreenOrFreeformWindow() {
- LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
- spyOn(persister);
-
- final Task task = getTestTask();
- task.setHasBeenVisible(false);
- task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
- task.getRootTask().setWindowingMode(WINDOWING_MODE_PINNED);
-
- task.setHasBeenVisible(true);
- task.onConfigurationChanged(task.getParent().getConfiguration());
-
- verify(persister, never()).saveTask(same(task), any());
- }
-
- @Test
- public void testNotSaveLaunchingStateForNonLeafTask() {
- LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
- spyOn(persister);
-
- final Task task = getTestTask();
- task.setHasBeenVisible(false);
- task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
- task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-
- final Task leafTask = createTaskInStack(task, 0 /* userId */);
-
- leafTask.setHasBeenVisible(true);
- task.setHasBeenVisible(true);
- task.onConfigurationChanged(task.getParent().getConfiguration());
-
- verify(persister, never()).saveTask(same(task), any());
- verify(persister).saveTask(same(leafTask), any());
- }
-
- @Test
- public void testNotSpecifyOrientationByFloatingTask() {
- final Task task = new TaskBuilder(mSupervisor)
- .setCreateActivity(true).setCreateParentTask(true).build();
- final ActivityRecord activity = task.getTopMostActivity();
- final WindowContainer<?> parentContainer = task.getParent();
- final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
- activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
-
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, parentContainer.getOrientation());
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskDisplayArea.getOrientation());
-
- task.setWindowingMode(WINDOWING_MODE_PINNED);
-
- // TDA returns the last orientation when child returns UNSET
- assertEquals(SCREEN_ORIENTATION_UNSET, parentContainer.getOrientation());
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskDisplayArea.getOrientation());
- }
-
- @Test
- public void testNotSpecifyOrientation_taskDisplayAreaNotFocused() {
- final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
- final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
- mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea",
- FEATURE_VENDOR_FIRST);
- final Task firstStack = firstTaskDisplayArea.createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final Task secondStack = secondTaskDisplayArea.createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
- .setTask(firstStack).build();
- final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
- .setTask(secondStack).build();
- firstActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- secondActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
-
- // Activity on TDA1 is focused
- mDisplayContent.setFocusedApp(firstActivity);
-
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, firstTaskDisplayArea.getOrientation());
- assertEquals(SCREEN_ORIENTATION_UNSET, secondTaskDisplayArea.getOrientation());
-
- // No focused app, TDA1 is still recorded as last focused.
- mDisplayContent.setFocusedApp(null);
-
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, firstTaskDisplayArea.getOrientation());
- assertEquals(SCREEN_ORIENTATION_UNSET, secondTaskDisplayArea.getOrientation());
-
- // Activity on TDA2 is focused
- mDisplayContent.setFocusedApp(secondActivity);
-
- assertEquals(SCREEN_ORIENTATION_UNSET, firstTaskDisplayArea.getOrientation());
- assertEquals(SCREEN_ORIENTATION_PORTRAIT, secondTaskDisplayArea.getOrientation());
- }
-
- @Test
- public void testNotifyOrientationChangeCausedByConfigurationChange() {
- final Task task = getTestTask();
- final ActivityRecord activity = task.getTopMostActivity();
- final DisplayContent display = task.getDisplayContent();
- display.setWindowingMode(WINDOWING_MODE_FREEFORM);
-
- activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
- verify(display).onDescendantOrientationChanged(same(task));
- reset(display);
-
- display.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, task.getOrientation());
- verify(display).onDescendantOrientationChanged(same(task));
- }
-
- private Task getTestTask() {
- final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
- return stack.getBottomMostTask();
- }
-
- private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
- Rect expectedConfigBounds) {
-
- TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
- Task stack = taskDisplayArea.createRootTask(windowingMode, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
- Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
-
- final Configuration parentConfig = stack.getConfiguration();
- parentConfig.windowConfiguration.setAppBounds(parentBounds);
- task.setBounds(bounds);
-
- task.resolveOverrideConfiguration(parentConfig);
- // Assert that both expected and actual are null or are equal to each other
- assertEquals(expectedConfigBounds,
- task.getResolvedOverrideConfiguration().windowConfiguration.getAppBounds());
- }
-
- private byte[] serializeToBytes(Task r) throws Exception {
- try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
- final TypedXmlSerializer serializer = Xml.newFastSerializer();
- serializer.setOutput(os, "UTF-8");
- serializer.startDocument(null, true);
- serializer.startTag(null, TASK_TAG);
- r.saveToXml(serializer);
- serializer.endTag(null, TASK_TAG);
- serializer.endDocument();
-
- os.flush();
- return os.toByteArray();
- }
- }
-
- private Task restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
- try (Reader reader = new InputStreamReader(new ByteArrayInputStream(in))) {
- final TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(reader);
- assertEquals(XmlPullParser.START_TAG, parser.next());
- assertEquals(TASK_TAG, parser.getName());
- return Task.restoreFromXml(parser, mAtm.mTaskSupervisor);
- }
- }
-
- private Task createTask(int taskId) {
- return new Task.Builder(mAtm)
- .setTaskId(taskId)
- .setIntent(new Intent())
- .setRealActivity(ActivityBuilder.getDefaultComponent())
- .setEffectiveUid(10050)
- .buildInner();
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
deleted file mode 100644
index e58c162ceadd..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-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 android.app.WindowConfiguration;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for the {@link Task} class.
- *
- * Build/Install/Run:
- * atest WmTests:TaskStackTests
- */
-@SmallTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class TaskStackTests extends WindowTestsBase {
-
- @Test
- public void testStackPositionChildAt() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task1 = createTaskInStack(stack, 0 /* userId */);
- final Task task2 = createTaskInStack(stack, 1 /* userId */);
-
- // Current user task should be moved to top.
- stack.positionChildAt(WindowContainer.POSITION_TOP, task1, false /* includingParents */);
- assertEquals(stack.mChildren.get(0), task2);
- assertEquals(stack.mChildren.get(1), task1);
-
- // Non-current user won't be moved to top.
- stack.positionChildAt(WindowContainer.POSITION_TOP, task2, false /* includingParents */);
- assertEquals(stack.mChildren.get(0), task2);
- assertEquals(stack.mChildren.get(1), task1);
-
- // Non-leaf task should be moved to top regardless of the user id.
- createTaskInStack(task2, 0 /* userId */);
- createTaskInStack(task2, 1 /* userId */);
- stack.positionChildAt(WindowContainer.POSITION_TOP, task2, false /* includingParents */);
- assertEquals(stack.mChildren.get(0), task1);
- assertEquals(stack.mChildren.get(1), task2);
- }
-
- @Test
- public void testClosingAppDifferentTaskOrientation() {
- final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
- activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
-
- final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
- activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
-
- final WindowContainer parent = activity1.getTask().getParent();
- assertEquals(SCREEN_ORIENTATION_PORTRAIT, parent.getOrientation());
- mDisplayContent.mClosingApps.add(activity2);
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, parent.getOrientation());
- }
-
- @Test
- public void testMoveTaskToBackDifferentTaskOrientation() {
- final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
- activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
-
- final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
- activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
-
- final WindowContainer parent = activity1.getTask().getParent();
- assertEquals(SCREEN_ORIENTATION_PORTRAIT, parent.getOrientation());
- }
-
- @Test
- public void testStackRemoveImmediately() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack, 0 /* userId */);
- assertEquals(stack, task.getRootTask());
-
- // Remove stack and check if its child is also removed.
- stack.removeImmediately();
- assertNull(stack.getDisplayContent());
- assertNull(task.getParent());
- }
-
- @Test
- public void testRemoveContainer() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack, 0 /* userId */);
-
- assertNotNull(stack);
- assertNotNull(task);
- stack.removeIfPossible();
- // Assert that the container was removed.
- assertNull(stack.getParent());
- assertEquals(0, stack.getChildCount());
- assertNull(stack.getDisplayContent());
- assertNull(task.getDisplayContent());
- assertNull(task.getParent());
- }
-
- @Test
- public void testRemoveContainer_deferRemoval() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack, 0 /* userId */);
-
- // Stack removal is deferred if one of its child is animating.
- doReturn(true).when(stack).hasWindowsAlive();
- doReturn(stack).when(task).getAnimatingContainer(
- eq(TRANSITION | CHILDREN), anyInt());
-
- stack.removeIfPossible();
- // For the case of deferred removal the task controller will still be connected to the its
- // container until the stack window container is removed.
- assertNotNull(stack.getParent());
- assertNotEquals(0, stack.getChildCount());
- assertNotNull(task);
-
- stack.removeImmediately();
- // After removing, the task will be isolated.
- assertNull(task.getParent());
- assertEquals(0, task.getChildCount());
- }
-
- @Test
- public void testReparent() {
- // Create first stack on primary display.
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task1 = createTaskInStack(stack1, 0 /* userId */);
-
- // Create second display and put second stack on it.
- final DisplayContent dc = createNewDisplay();
- final Task stack2 = createTaskStackOnDisplay(dc);
-
- // Reparent
- clearInvocations(task1); // reset the number of onDisplayChanged for task.
- stack1.reparent(dc.getDefaultTaskDisplayArea(), true /* onTop */);
- assertEquals(dc, stack1.getDisplayContent());
- final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
- final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
- assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
- verify(task1, times(1)).onDisplayChanged(any());
- }
-
- @Test
- public void testStackOutset() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final int stackOutset = 10;
- spyOn(stack);
- doReturn(stackOutset).when(stack).getTaskOutset();
- doReturn(true).when(stack).inMultiWindowMode();
-
- // Mock the resolved override windowing mode to non-fullscreen
- final WindowConfiguration windowConfiguration =
- stack.getResolvedOverrideConfiguration().windowConfiguration;
- spyOn(windowConfiguration);
- doReturn(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
- .when(windowConfiguration).getWindowingMode();
-
- // Prevent adjust task dimensions
- doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any(), any());
-
- final Rect stackBounds = new Rect(200, 200, 800, 1000);
- // Update surface position and size by the given bounds.
- stack.setBounds(stackBounds);
-
- assertEquals(stackBounds.width() + 2 * stackOutset, stack.getLastSurfaceSize().x);
- assertEquals(stackBounds.height() + 2 * stackOutset, stack.getLastSurfaceSize().y);
- assertEquals(stackBounds.left - stackOutset, stack.getLastSurfacePosition().x);
- assertEquals(stackBounds.top - stackOutset, stack.getLastSurfacePosition().y);
- }
-
- @Test
- public void testActivityAndTaskGetsProperType() {
- final Task task1 = new TaskBuilder(mSupervisor).build();
- ActivityRecord activity1 = createNonAttachedActivityRecord(mDisplayContent);
-
- // First activity should become standard
- task1.addChild(activity1, 0);
- assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, activity1.getActivityType());
- assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType());
-
- // Second activity should also become standard
- ActivityRecord activity2 = createNonAttachedActivityRecord(mDisplayContent);
- task1.addChild(activity2, WindowContainer.POSITION_TOP);
- assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, activity2.getActivityType());
- assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType());
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index dca6b089d66b..2389d2d6e8d6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -16,20 +16,39 @@
package com.android.server.wm;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
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.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_90;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
import static com.google.common.truth.Truth.assertThat;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -39,18 +58,45 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import android.app.ActivityManager;
+import android.app.TaskInfo;
import android.app.WindowConfiguration;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
+import android.view.DisplayInfo;
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.MediumTest;
+import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
/**
* Test class for {@link Task}.
@@ -58,15 +104,25 @@ import org.junit.runner.RunWith;
* Build/Install/Run:
* atest WmTests:TaskTests
*/
-@SmallTest
+@MediumTest
@Presubmit
@RunWith(WindowTestRunner.class)
public class TaskTests extends WindowTestsBase {
+ private static final String TASK_TAG = "task";
+
+ private Rect mParentBounds;
+
+ @Before
+ public void setUp() throws Exception {
+ mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
+ removeGlobalMinSizeRestriction();
+ }
+
@Test
public void testRemoveContainer() {
- final Task stackController1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stackController1, 0 /* userId */);
+ final Task taskController1 = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(taskController1, 0 /* userId */);
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
task.removeIfPossible();
@@ -78,8 +134,8 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testRemoveContainer_deferRemoval() {
- final Task stackController1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stackController1, 0 /* userId */);
+ final Task taskController1 = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(taskController1, 0 /* userId */);
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
doReturn(true).when(task).shouldDeferRemoval();
@@ -99,14 +155,14 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testReparent() {
- final Task stackController1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stackController1, 0 /* userId */);
- final Task stackController2 = createTaskStackOnDisplay(mDisplayContent);
- final Task task2 = createTaskInStack(stackController2, 0 /* userId */);
+ final Task taskController1 = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(taskController1, 0 /* userId */);
+ final Task taskController2 = createTask(mDisplayContent);
+ final Task task2 = createTaskInRootTask(taskController2, 0 /* userId */);
boolean gotException = false;
try {
- task.reparent(stackController1, 0, false/* moveParents */, "testReparent");
+ task.reparent(taskController1, 0, false/* moveParents */, "testReparent");
} catch (IllegalArgumentException e) {
gotException = true;
}
@@ -118,29 +174,29 @@ public class TaskTests extends WindowTestsBase {
} catch (Exception e) {
gotException = true;
}
- assertTrue("Should not be able to reparent to a stack that doesn't exist", gotException);
+ assertTrue("Should not be able to reparent to a task that doesn't exist", gotException);
- task.reparent(stackController2, 0, false/* moveParents */, "testReparent");
- assertEquals(stackController2, task.getParent());
+ task.reparent(taskController2, 0, false/* moveParents */, "testReparent");
+ assertEquals(taskController2, task.getParent());
assertEquals(0, task.getParent().mChildren.indexOf(task));
assertEquals(1, task2.getParent().mChildren.indexOf(task2));
}
@Test
public void testReparent_BetweenDisplays() {
- // Create first stack on primary display.
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack1, 0 /* userId */);
- assertEquals(mDisplayContent, stack1.getDisplayContent());
+ // Create first task on primary display.
+ final Task rootTask1 = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask1, 0 /* userId */);
+ assertEquals(mDisplayContent, rootTask1.getDisplayContent());
- // Create second display and put second stack on it.
+ // Create second display and put second task on it.
final DisplayContent dc = createNewDisplay();
- final Task stack2 = createTaskStackOnDisplay(dc);
- final Task task2 = createTaskInStack(stack2, 0 /* userId */);
+ final Task rootTask2 = createTask(dc);
+ final Task task2 = createTaskInRootTask(rootTask2, 0 /* userId */);
// Reparent and check state
clearInvocations(task); // reset the number of onDisplayChanged for task.
- task.reparent(stack2, 0, false /* moveParents */, "testReparent_BetweenDisplays");
- assertEquals(stack2, task.getParent());
+ task.reparent(rootTask2, 0, false /* moveParents */, "testReparent_BetweenDisplays");
+ assertEquals(rootTask2, task.getParent());
assertEquals(0, task.getParent().mChildren.indexOf(task));
assertEquals(1, task2.getParent().mChildren.indexOf(task2));
verify(task, times(1)).onDisplayChanged(any());
@@ -148,8 +204,8 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testBounds() {
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack1, 0 /* userId */);
+ final Task rootTask1 = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask1, 0 /* userId */);
// Check that setting bounds also updates surface position
task.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -159,9 +215,9 @@ public class TaskTests extends WindowTestsBase {
}
@Test
- public void testIsInStack() {
- final Task task1 = createTaskStackOnDisplay(mDisplayContent);
- final Task task2 = createTaskStackOnDisplay(mDisplayContent);
+ public void testIsInTask() {
+ final Task task1 = createTask(mDisplayContent);
+ final Task task2 = createTask(mDisplayContent);
final ActivityRecord activity1 = createActivityRecord(mDisplayContent, task1);
final ActivityRecord activity2 = createActivityRecord(mDisplayContent, task2);
assertEquals(activity1, task1.isInTask(activity1));
@@ -170,7 +226,7 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testRemoveChildForOverlayTask() {
- final Task task = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTask(mDisplayContent);
final int taskId = task.mTaskId;
final ActivityRecord activity1 = createActivityRecord(mDisplayContent, task);
final ActivityRecord activity2 = createActivityRecord(mDisplayContent, task);
@@ -193,10 +249,10 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testSwitchUser() {
- final Task rootTask = createTaskStackOnDisplay(mDisplayContent);
- final Task childTask = createTaskInStack(rootTask, 0 /* userId */);
- final Task leafTask1 = createTaskInStack(childTask, 10 /* userId */);
- final Task leafTask2 = createTaskInStack(childTask, 0 /* userId */);
+ final Task rootTask = createTask(mDisplayContent);
+ final Task childTask = createTaskInRootTask(rootTask, 0 /* userId */);
+ final Task leafTask1 = createTaskInRootTask(childTask, 10 /* userId */);
+ final Task leafTask2 = createTaskInRootTask(childTask, 0 /* userId */);
assertEquals(1, rootTask.getChildCount());
assertEquals(leafTask2, childTask.getTopChild());
@@ -208,9 +264,9 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testEnsureActivitiesVisible() {
- final Task rootTask = createTaskStackOnDisplay(mDisplayContent);
- final Task leafTask1 = createTaskInStack(rootTask, 0 /* userId */);
- final Task leafTask2 = createTaskInStack(rootTask, 0 /* userId */);
+ final Task rootTask = createTask(mDisplayContent);
+ final Task leafTask1 = createTaskInRootTask(rootTask, 0 /* userId */);
+ final Task leafTask2 = createTaskInRootTask(rootTask, 0 /* userId */);
final ActivityRecord activity1 = createActivityRecord(mDisplayContent, leafTask1);
final ActivityRecord activity2 = createActivityRecord(mDisplayContent, leafTask2);
@@ -233,7 +289,7 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testResolveNonResizableTaskWindowingMode() {
- final Task task = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTask(mDisplayContent);
Configuration parentConfig = task.getParent().getConfiguration();
parentConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
doReturn(false).when(task).isResizeable();
@@ -264,10 +320,10 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testHandlesOrientationChangeFromDescendant() {
- final Task rootTask = createTaskStackOnDisplay(WINDOWING_MODE_MULTI_WINDOW,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task leafTask1 = createTaskInStack(rootTask, 0 /* userId */);
- final Task leafTask2 = createTaskInStack(rootTask, 0 /* userId */);
+ final Task rootTask = createTask(mDisplayContent,
+ WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+ final Task leafTask1 = createTaskInRootTask(rootTask, 0 /* userId */);
+ final Task leafTask2 = createTaskInRootTask(rootTask, 0 /* userId */);
leafTask1.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_HOME);
leafTask2.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_STANDARD);
@@ -281,7 +337,7 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testAlwaysOnTop() {
- final Task task = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTask(mDisplayContent);
task.setAlwaysOnTop(true);
task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
assertTrue(task.isAlwaysOnTop());
@@ -289,4 +345,1053 @@ public class TaskTests extends WindowTestsBase {
task.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, true /* set */);
assertFalse(task.isAlwaysOnTop());
}
+
+ @Test
+ public void testRestoreWindowedTask() throws Exception {
+ final Task expected = createTask(64);
+ expected.mLastNonFullscreenBounds = new Rect(50, 50, 100, 100);
+
+ final byte[] serializedBytes = serializeToBytes(expected);
+ final Task actual = restoreFromBytes(serializedBytes);
+ assertEquals(expected.mTaskId, actual.mTaskId);
+ assertEquals(expected.mLastNonFullscreenBounds, actual.mLastNonFullscreenBounds);
+ }
+
+ /** Ensure we have no chance to modify the original intent. */
+ @Test
+ public void testCopyBaseIntentForTaskInfo() {
+ final Task task = createTask(1);
+ task.setTaskDescription(new ActivityManager.TaskDescription());
+ final TaskInfo info = task.getTaskInfo();
+
+ // The intent of info should be a copy so assert that they are different instances.
+ Assert.assertThat(info.baseIntent, not(sameInstance(task.getBaseIntent())));
+ }
+
+ @Test
+ public void testReturnsToHomeRootTask() throws Exception {
+ final Task task = createTask(1);
+ spyOn(task);
+ doReturn(true).when(task).hasChild();
+ assertFalse(task.returnsToHomeRootTask());
+ task.intent = null;
+ assertFalse(task.returnsToHomeRootTask());
+ task.intent = new Intent();
+ assertFalse(task.returnsToHomeRootTask());
+ task.intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
+ assertTrue(task.returnsToHomeRootTask());
+ }
+
+ /** Ensures that empty bounds cause appBounds to inherit from parent. */
+ @Test
+ public void testAppBounds_EmptyBounds() {
+ final Rect emptyBounds = new Rect();
+ testRootTaskBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, emptyBounds,
+ mParentBounds);
+ }
+
+ /** Ensures that bounds on freeform root tasks are not clipped. */
+ @Test
+ public void testAppBounds_FreeFormBounds() {
+ final Rect freeFormBounds = new Rect(mParentBounds);
+ freeFormBounds.offset(10, 10);
+ testRootTaskBoundsConfiguration(WINDOWING_MODE_FREEFORM, mParentBounds, freeFormBounds,
+ freeFormBounds);
+ }
+
+ /** Ensures that fully contained bounds are not clipped. */
+ @Test
+ public void testAppBounds_ContainedBounds() {
+ final Rect insetBounds = new Rect(mParentBounds);
+ insetBounds.inset(5, 5, 5, 5);
+ testRootTaskBoundsConfiguration(
+ WINDOWING_MODE_FREEFORM, mParentBounds, insetBounds, insetBounds);
+ }
+
+ @Test
+ public void testFitWithinBounds() {
+ final Rect parentBounds = new Rect(10, 10, 200, 200);
+ TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
+ Task rootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+ final Configuration parentConfig = rootTask.getConfiguration();
+ parentConfig.windowConfiguration.setBounds(parentBounds);
+ parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
+
+ // check top and left
+ Rect reqBounds = new Rect(-190, -190, 0, 0);
+ task.setBounds(reqBounds);
+ // Make sure part of it is exposed
+ assertTrue(task.getBounds().right > parentBounds.left);
+ assertTrue(task.getBounds().bottom > parentBounds.top);
+ // Should still be more-or-less in that corner
+ assertTrue(task.getBounds().left <= parentBounds.left);
+ assertTrue(task.getBounds().top <= parentBounds.top);
+
+ assertEquals(reqBounds.width(), task.getBounds().width());
+ assertEquals(reqBounds.height(), task.getBounds().height());
+
+ // check bottom and right
+ reqBounds = new Rect(210, 210, 400, 400);
+ task.setBounds(reqBounds);
+ // Make sure part of it is exposed
+ assertTrue(task.getBounds().left < parentBounds.right);
+ assertTrue(task.getBounds().top < parentBounds.bottom);
+ // Should still be more-or-less in that corner
+ assertTrue(task.getBounds().right >= parentBounds.right);
+ assertTrue(task.getBounds().bottom >= parentBounds.bottom);
+
+ assertEquals(reqBounds.width(), task.getBounds().width());
+ assertEquals(reqBounds.height(), task.getBounds().height());
+ }
+
+ /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
+ @Test
+ public void testBoundsOnModeChangeFreeformToFullscreen() {
+ DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
+ Task rootTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ Task task = rootTask.getBottomMostTask();
+ task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
+ DisplayInfo info = new DisplayInfo();
+ display.mDisplay.getDisplayInfo(info);
+ final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
+ final Rect freeformBounds = new Rect(fullScreenBounds);
+ freeformBounds.inset((int) (freeformBounds.width() * 0.2),
+ (int) (freeformBounds.height() * 0.2));
+ task.setBounds(freeformBounds);
+
+ assertEquals(freeformBounds, task.getBounds());
+
+ // FULLSCREEN inherits bounds
+ rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertEquals(fullScreenBounds, task.getBounds());
+ assertEquals(freeformBounds, task.mLastNonFullscreenBounds);
+
+ // FREEFORM restores bounds
+ rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(freeformBounds, task.getBounds());
+ }
+
+ /**
+ * Tests that a task with forced orientation has orientation-consistent bounds within the
+ * parent.
+ */
+ @Test
+ public void testFullscreenBoundsForcedOrientation() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+ final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm,
+ fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
+ assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
+ // Fix the display orientation to landscape which is the natural rotation (0) for the test
+ // display.
+ final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
+ dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
+
+ final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ final Task task = rootTask.getBottomMostTask();
+ final ActivityRecord root = task.getTopNonFinishingActivity();
+
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed portrait fits within parent
+ root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ assertEquals(root, task.getRootActivity());
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
+ // Portrait orientation is enforced on activity level. Task should fill fullscreen bounds.
+ assertThat(task.getBounds().height()).isLessThan(task.getBounds().width());
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Top activity gets used
+ final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setParentTask(rootTask)
+ .build();
+ assertEquals(top, task.getTopNonFinishingActivity());
+ top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
+ assertEquals(task.getBounds().width(), fullScreenBounds.width());
+
+ // Setting app to unspecified restores
+ top.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed landscape and changing display
+ top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ // Fix the display orientation to portrait which is 90 degrees for the test display.
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90);
+
+ // Fixed orientation request should be resolved on activity level. Task fills display
+ // bounds.
+ assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
+ assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
+ assertEquals(fullScreenBoundsPort, task.getBounds());
+
+ // in FREEFORM, no constraint
+ final Rect freeformBounds = new Rect(display.getBounds());
+ freeformBounds.inset((int) (freeformBounds.width() * 0.2),
+ (int) (freeformBounds.height() * 0.2));
+ rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.setBounds(freeformBounds);
+ assertEquals(freeformBounds, task.getBounds());
+
+ // FULLSCREEN letterboxes bounds on activity level, no constraint on task level.
+ rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
+ assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
+ assertEquals(fullScreenBoundsPort, task.getBounds());
+
+ // FREEFORM restores bounds as before
+ rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(freeformBounds, task.getBounds());
+ }
+
+ @Test
+ public void testReportsOrientationRequestInLetterboxForOrientation() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+ final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm,
+ fullScreenBounds.width(), fullScreenBounds.height()).setCanRotate(false).build();
+ assertNotNull(mRootWindowContainer.getDisplayContent(display.mDisplayId));
+ // Fix the display orientation to landscape which is the natural rotation (0) for the test
+ // display.
+ final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
+ dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
+
+ final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ final Task task = rootTask.getBottomMostTask();
+ ActivityRecord root = task.getTopNonFinishingActivity();
+
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed portrait fits within parent on activity level. Task fills parent.
+ root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ assertThat(root.getBounds().width()).isLessThan(root.getBounds().height());
+ assertEquals(task.getBounds(), fullScreenBounds);
+
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getOrientation());
+ }
+
+ @Test
+ public void testIgnoresForcedOrientationWhenParentHandles() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+ DisplayContent display = new TestDisplayContent.Builder(
+ mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
+
+ display.getRequestedOverrideConfiguration().orientation =
+ Configuration.ORIENTATION_LANDSCAPE;
+ display.onRequestedOverrideConfigurationChanged(
+ display.getRequestedOverrideConfiguration());
+ Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ Task task = rootTask.getBottomMostTask();
+ ActivityRecord root = task.getTopNonFinishingActivity();
+
+ final WindowContainer parentWindowContainer =
+ new WindowContainer(mSystemServicesTestRule.getWindowManagerService());
+ spyOn(parentWindowContainer);
+ parentWindowContainer.setBounds(fullScreenBounds);
+ doReturn(parentWindowContainer).when(task).getParent();
+ doReturn(display.getDefaultTaskDisplayArea()).when(task).getDisplayArea();
+ doReturn(rootTask).when(task).getRootTask();
+ doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
+
+ // Setting app to fixed portrait fits within parent, but Task shouldn't adjust the
+ // bounds because its parent says it will handle it at a later time.
+ root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ assertEquals(root, task.getRootActivity());
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
+ assertEquals(fullScreenBounds, task.getBounds());
+ }
+
+ @Test
+ public void testComputeConfigResourceOverrides() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1080, 1920);
+ TestDisplayContent display = new TestDisplayContent.Builder(
+ mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
+ final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
+ final Configuration inOutConfig = new Configuration();
+ final Configuration parentConfig = new Configuration();
+ final int longSide = 1200;
+ final int shortSide = 600;
+ final Rect parentBounds = new Rect(0, 0, 250, 500);
+ final Rect parentAppBounds = new Rect(0, 0, 250, 480);
+ parentConfig.windowConfiguration.setBounds(parentBounds);
+ parentConfig.windowConfiguration.setAppBounds(parentAppBounds);
+ parentConfig.densityDpi = 400;
+ parentConfig.screenHeightDp = (parentBounds.bottom * 160) / parentConfig.densityDpi; // 200
+ parentConfig.screenWidthDp = (parentBounds.right * 160) / parentConfig.densityDpi; // 100
+ parentConfig.windowConfiguration.setRotation(ROTATION_0);
+
+ // By default, the input bounds will fill parent.
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+ assertEquals(parentConfig.screenHeightDp, inOutConfig.screenHeightDp);
+ assertEquals(parentConfig.screenWidthDp, inOutConfig.screenWidthDp);
+ assertEquals(parentAppBounds, inOutConfig.windowConfiguration.getAppBounds());
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, inOutConfig.orientation);
+
+ // If bounds are overridden, config properties should be made to match. Surface hierarchy
+ // will crop for policy.
+ inOutConfig.setToDefaults();
+ final Rect largerPortraitBounds = new Rect(0, 0, shortSide, longSide);
+ inOutConfig.windowConfiguration.setBounds(largerPortraitBounds);
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+ // The override bounds are beyond the parent, the out appBounds should not be intersected
+ // by parent appBounds.
+ assertEquals(largerPortraitBounds, inOutConfig.windowConfiguration.getAppBounds());
+ assertEquals(longSide, inOutConfig.screenHeightDp * parentConfig.densityDpi / 160);
+ assertEquals(shortSide, inOutConfig.screenWidthDp * parentConfig.densityDpi / 160);
+
+ inOutConfig.setToDefaults();
+ // Landscape bounds.
+ final Rect largerLandscapeBounds = new Rect(0, 0, longSide, shortSide);
+ inOutConfig.windowConfiguration.setBounds(largerLandscapeBounds);
+
+ // Setup the display with a top stable inset. The later assertion will ensure the inset is
+ // excluded from screenHeightDp.
+ final int statusBarHeight = 100;
+ final DisplayPolicy policy = display.getDisplayPolicy();
+ doAnswer(invocationOnMock -> {
+ final Rect insets = invocationOnMock.<Rect>getArgument(0);
+ insets.top = statusBarHeight;
+ return null;
+ }).when(policy).convertNonDecorInsetsToStableInsets(any(), eq(ROTATION_0));
+
+ // Without limiting to be inside the parent bounds, the out screen size should keep relative
+ // to the input bounds.
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
+ final ActivityRecord.CompatDisplayInsets compatIntsets =
+ new ActivityRecord.CompatDisplayInsets(
+ display, activity, /* fixedOrientationBounds= */ null);
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
+
+ assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
+ assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
+ inOutConfig.screenHeightDp);
+ assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
+ inOutConfig.screenWidthDp);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, inOutConfig.orientation);
+ }
+
+ @Test
+ public void testComputeConfigResourceLayoutOverrides() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1000, 2500);
+ TestDisplayContent display = new TestDisplayContent.Builder(
+ mAtm, fullScreenBounds.width(), fullScreenBounds.height()).build();
+ final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
+ final Configuration inOutConfig = new Configuration();
+ final Configuration parentConfig = new Configuration();
+ final Rect nonLongBounds = new Rect(0, 0, 1000, 1250);
+ parentConfig.windowConfiguration.setBounds(fullScreenBounds);
+ parentConfig.windowConfiguration.setAppBounds(fullScreenBounds);
+ parentConfig.densityDpi = 400;
+ parentConfig.screenHeightDp = (fullScreenBounds.bottom * 160) / parentConfig.densityDpi;
+ parentConfig.screenWidthDp = (fullScreenBounds.right * 160) / parentConfig.densityDpi;
+ parentConfig.windowConfiguration.setRotation(ROTATION_0);
+
+ // Set BOTH screenW/H to an override value
+ inOutConfig.screenWidthDp = nonLongBounds.width() * 160 / parentConfig.densityDpi;
+ inOutConfig.screenHeightDp = nonLongBounds.height() * 160 / parentConfig.densityDpi;
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+ // screenLayout should honor override when both screenW/H are set.
+ assertTrue((inOutConfig.screenLayout & Configuration.SCREENLAYOUT_LONG_NO) != 0);
+ }
+
+ @Test
+ public void testComputeNestedConfigResourceOverrides() {
+ final Task task = new TaskBuilder(mSupervisor).build();
+ assertTrue(task.getResolvedOverrideBounds().isEmpty());
+ int origScreenH = task.getConfiguration().screenHeightDp;
+ Configuration rootTaskConfig = new Configuration();
+ rootTaskConfig.setTo(task.getRootTask().getRequestedOverrideConfiguration());
+ rootTaskConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ // Set bounds on root task (not task) and verify that the task resource configuration
+ // changes despite it's override bounds being empty.
+ Rect bounds = new Rect(task.getRootTask().getBounds());
+ bounds.bottom = (int) (bounds.bottom * 0.6f);
+ rootTaskConfig.windowConfiguration.setBounds(bounds);
+ task.getRootTask().onRequestedOverrideConfigurationChanged(rootTaskConfig);
+ assertNotEquals(origScreenH, task.getConfiguration().screenHeightDp);
+ }
+
+ @Test
+ public void testFullScreenTaskNotAdjustedByMinimalSize() {
+ final Task fullscreenTask = new TaskBuilder(mSupervisor).build();
+ final Rect originalTaskBounds = new Rect(fullscreenTask.getBounds());
+ final ActivityInfo aInfo = new ActivityInfo();
+ aInfo.windowLayout = new ActivityInfo.WindowLayout(0 /* width */, 0 /* widthFraction */,
+ 0 /* height */, 0 /* heightFraction */, 0 /* gravity */,
+ originalTaskBounds.width() * 2 /* minWidth */,
+ originalTaskBounds.height() * 2 /* minHeight */);
+ fullscreenTask.setMinDimensions(aInfo);
+ fullscreenTask.onConfigurationChanged(fullscreenTask.getParent().getConfiguration());
+
+ assertEquals(originalTaskBounds, fullscreenTask.getBounds());
+ }
+
+ @Test
+ public void testInsetDisregardedWhenFreeformOverlapsNavBar() {
+ TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
+ Task rootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ DisplayInfo displayInfo = new DisplayInfo();
+ mAtm.mContext.getDisplay().getDisplayInfo(displayInfo);
+ final int displayHeight = displayInfo.logicalHeight;
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+ final Configuration inOutConfig = new Configuration();
+ final Configuration parentConfig = new Configuration();
+ final int longSide = 1200;
+ final int shortSide = 600;
+ parentConfig.densityDpi = 400;
+ parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
+ parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
+ parentConfig.windowConfiguration.setRotation(ROTATION_0);
+
+ final int longSideDp = 480; // longSide / density = 1200 / 400 * 160
+ final int shortSideDp = 240; // shortSide / density = 600 / 400 * 160
+ final int screenLayout = parentConfig.screenLayout
+ & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
+ final int reducedScreenLayout =
+ Configuration.reduceScreenLayout(screenLayout, longSideDp, shortSideDp);
+
+ // Portrait bounds overlapping with navigation bar, without insets.
+ final Rect freeformBounds = new Rect(0,
+ displayHeight - 10 - longSide,
+ shortSide,
+ displayHeight - 10);
+ inOutConfig.windowConfiguration.setBounds(freeformBounds);
+ // Set to freeform mode to verify bug fix.
+ inOutConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+ // screenW/H should not be effected by parent since overridden and freeform
+ assertEquals(freeformBounds.width() * 160 / parentConfig.densityDpi,
+ inOutConfig.screenWidthDp);
+ assertEquals(freeformBounds.height() * 160 / parentConfig.densityDpi,
+ inOutConfig.screenHeightDp);
+ assertEquals(reducedScreenLayout, inOutConfig.screenLayout);
+
+ inOutConfig.setToDefaults();
+ // Landscape bounds overlapping with navigtion bar, without insets.
+ freeformBounds.set(0,
+ displayHeight - 10 - shortSide,
+ longSide,
+ displayHeight - 10);
+ inOutConfig.windowConfiguration.setBounds(freeformBounds);
+ inOutConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+ assertEquals(freeformBounds.width() * 160 / parentConfig.densityDpi,
+ inOutConfig.screenWidthDp);
+ assertEquals(freeformBounds.height() * 160 / parentConfig.densityDpi,
+ inOutConfig.screenHeightDp);
+ assertEquals(reducedScreenLayout, inOutConfig.screenLayout);
+ }
+
+ /** Ensures that the alias intent won't have target component resolved. */
+ @Test
+ public void testTaskIntentActivityAlias() {
+ final String aliasClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".aliasActivity";
+ final String targetClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".targetActivity";
+ final ComponentName aliasComponent =
+ new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, aliasClassName);
+ final ComponentName targetComponent =
+ new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, targetClassName);
+
+ final Intent intent = new Intent();
+ intent.setComponent(aliasComponent);
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
+ info.targetActivity = targetClassName;
+
+ final Task task = new Task.Builder(mAtm)
+ .setTaskId(1)
+ .setActivityInfo(info)
+ .setIntent(intent)
+ .build();
+ assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
+ task.intent.getComponent().getClassName());
+
+ ActivityRecord aliasActivity = new ActivityBuilder(mAtm).setComponent(
+ aliasComponent).setTargetActivity(targetClassName).build();
+ assertEquals("Should be the same intent filter.", true,
+ task.isSameIntentFilter(aliasActivity));
+
+ ActivityRecord targetActivity = new ActivityBuilder(mAtm).setComponent(
+ targetComponent).build();
+ assertEquals("Should be the same intent filter.", true,
+ task.isSameIntentFilter(targetActivity));
+
+ ActivityRecord defaultActivity = new ActivityBuilder(mAtm).build();
+ assertEquals("Should not be the same intent filter.", false,
+ task.isSameIntentFilter(defaultActivity));
+ }
+
+ /** Test that root activity index is reported correctly for several activities in the task. */
+ @Test
+ public void testFindRootIndex() {
+ final Task task = getTestTask();
+ // Add an extra activity on top of the root one
+ new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertEquals("The root activity in the task must be reported.", task.getChildAt(0),
+ task.getRootActivity(
+ true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
+ }
+
+ /**
+ * Test that root activity index is reported correctly for several activities in the task when
+ * the activities on the bottom are finishing.
+ */
+ @Test
+ public void testFindRootIndex_finishing() {
+ final Task task = getTestTask();
+ // Add extra two activities and mark the two on the bottom as finishing.
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.finishing = true;
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ activity1.finishing = true;
+ new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertEquals("The first non-finishing activity in the task must be reported.",
+ task.getChildAt(2), task.getRootActivity(
+ true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
+ }
+
+ /**
+ * Test that root activity index is reported correctly for several activities in the task when
+ * looking for the 'effective root'.
+ */
+ @Test
+ public void testFindRootIndex_effectiveRoot() {
+ final Task task = getTestTask();
+ // Add an extra activity on top of the root one
+ new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertEquals("The root activity in the task must be reported.",
+ task.getChildAt(0), task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
+ }
+
+ /**
+ * Test that root activity index is reported correctly when looking for the 'effective root' in
+ * case when bottom activities are relinquishing task identity or finishing.
+ */
+ @Test
+ public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() {
+ final Task task = getTestTask();
+ // Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
+ // one above as finishing.
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ activity1.finishing = true;
+ new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertEquals("The first non-finishing activity and non-relinquishing task identity "
+ + "must be reported.", task.getChildAt(2), task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
+ }
+
+ /**
+ * Test that root activity index is reported correctly when looking for the 'effective root'
+ * for the case when there is only a single activity that also has relinquishTaskIdentity set.
+ */
+ @Test
+ public void testFindRootIndex_effectiveRoot_relinquishingAndSingleActivity() {
+ final Task task = getTestTask();
+ // Set relinquishTaskIdentity for the only activity in the task
+ task.getBottomMostActivity().info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+
+ assertEquals("The root activity in the task must be reported.",
+ task.getChildAt(0), task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
+ }
+
+ /**
+ * Test that the topmost activity index is reported correctly when looking for the
+ * 'effective root' for the case when all activities have relinquishTaskIdentity set.
+ */
+ @Test
+ public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
+ final Task task = getTestTask();
+ // Set relinquishTaskIdentity for all activities in the task
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+
+ assertEquals("The topmost activity in the task must be reported.",
+ task.getChildAt(task.getChildCount() - 1), task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
+ }
+
+ /** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */
+ @Test
+ public void testGetRootActivity() {
+ final Task task = getTestTask();
+ // Add an extra activity on top of the root one
+ new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertEquals("The root activity in the task must be reported.",
+ task.getBottomMostActivity(), task.getRootActivity());
+ }
+
+ /**
+ * Test that first non-finishing activity is reported in {@link Task#getRootActivity()}.
+ */
+ @Test
+ public void testGetRootActivity_finishing() {
+ final Task task = getTestTask();
+ // Add an extra activity on top of the root one
+ new ActivityBuilder(mAtm).setTask(task).build();
+ // Mark the root as finishing
+ task.getBottomMostActivity().finishing = true;
+
+ assertEquals("The first non-finishing activity in the task must be reported.",
+ task.getChildAt(1), task.getRootActivity());
+ }
+
+ /**
+ * Test that relinquishTaskIdentity flag is ignored in {@link Task#getRootActivity()}.
+ */
+ @Test
+ public void testGetRootActivity_relinquishTaskIdentity() {
+ final Task task = getTestTask();
+ // Mark the bottom-most activity with FLAG_RELINQUISH_TASK_IDENTITY.
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+ // Add an extra activity on top of the root one.
+ new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertEquals("The root activity in the task must be reported.",
+ task.getBottomMostActivity(), task.getRootActivity());
+ }
+
+ /**
+ * Test that no activity is reported in {@link Task#getRootActivity()} when all activities
+ * in the task are finishing.
+ */
+ @Test
+ public void testGetRootActivity_allFinishing() {
+ final Task task = getTestTask();
+ // Mark the bottom-most activity as finishing.
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.finishing = true;
+ // Add an extra activity on top of the root one and mark it as finishing
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ activity1.finishing = true;
+
+ assertNull("No activity must be reported if all are finishing", task.getRootActivity());
+ }
+
+ /**
+ * Test that first non-finishing activity is the root of task.
+ */
+ @Test
+ public void testIsRootActivity() {
+ final Task task = getTestTask();
+ // Mark the bottom-most activity as finishing.
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.finishing = true;
+ // Add an extra activity on top of the root one.
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertFalse("Finishing activity must not be the root of task", activity0.isRootOfTask());
+ assertTrue("Non-finishing activity must be the root of task", activity1.isRootOfTask());
+ }
+
+ /**
+ * Test that if all activities in the task are finishing, then the one on the bottom is the
+ * root of task.
+ */
+ @Test
+ public void testIsRootActivity_allFinishing() {
+ final Task task = getTestTask();
+ // Mark the bottom-most activity as finishing.
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.finishing = true;
+ // Add an extra activity on top of the root one and mark it as finishing
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ activity1.finishing = true;
+
+ assertTrue("Bottom activity must be the root of task", activity0.isRootOfTask());
+ assertFalse("Finishing activity on top must not be the root of task",
+ activity1.isRootOfTask());
+ }
+
+ /**
+ * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)}.
+ */
+ @Test
+ public void testGetTaskForActivity() {
+ final Task task0 = getTestTask();
+ final ActivityRecord activity0 = task0.getBottomMostActivity();
+
+ final Task task1 = getTestTask();
+ final ActivityRecord activity1 = task1.getBottomMostActivity();
+
+ assertEquals(task0.mTaskId,
+ ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
+ assertEquals(task1.mTaskId,
+ ActivityRecord.getTaskForActivityLocked(activity1.appToken, false /* onlyRoot */));
+ }
+
+ /**
+ * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with finishing
+ * activity.
+ */
+ @Test
+ public void testGetTaskForActivity_onlyRoot_finishing() {
+ final Task task = getTestTask();
+ // Make the current root activity finishing
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.finishing = true;
+ // Add an extra activity on top - this will be the new root
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ // Add one more on top
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertEquals(task.mTaskId,
+ ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
+ assertEquals(task.mTaskId,
+ ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
+ assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
+ ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
+ }
+
+ /**
+ * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with activity that
+ * relinquishes task identity.
+ */
+ @Test
+ public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
+ final Task task = getTestTask();
+ // Make the current root activity relinquish task identity
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+ // Add an extra activity on top - this will be the new root
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ // Add one more on top
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertEquals(task.mTaskId,
+ ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
+ assertEquals(task.mTaskId,
+ ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
+ assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
+ ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
+ }
+
+ /**
+ * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} allowing non-root
+ * entries.
+ */
+ @Test
+ public void testGetTaskForActivity_notOnlyRoot() {
+ final Task task = getTestTask();
+ // Mark the bottom-most activity as finishing.
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ activity0.finishing = true;
+
+ // Add an extra activity on top of the root one and make it relinquish task identity
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+
+ // Add one more activity on top
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
+
+ assertEquals(task.mTaskId,
+ ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
+ assertEquals(task.mTaskId,
+ ActivityRecord.getTaskForActivityLocked(activity1.appToken, false /* onlyRoot */));
+ assertEquals(task.mTaskId,
+ ActivityRecord.getTaskForActivityLocked(activity2.appToken, false /* onlyRoot */));
+ }
+
+ /**
+ * Test {@link Task#updateEffectiveIntent()}.
+ */
+ @Test
+ public void testUpdateEffectiveIntent() {
+ // Test simple case with a single activity.
+ final Task task = getTestTask();
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+
+ spyOn(task);
+ task.updateEffectiveIntent();
+ verify(task).setIntent(eq(activity0));
+ }
+
+ /**
+ * Test {@link Task#updateEffectiveIntent()} with root activity marked as finishing. This
+ * should make the task use the second activity when updating the intent.
+ */
+ @Test
+ public void testUpdateEffectiveIntent_rootFinishing() {
+ // Test simple case with a single activity.
+ final Task task = getTestTask();
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ // Mark the bottom-most activity as finishing.
+ activity0.finishing = true;
+ // Add an extra activity on top of the root one
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+
+ spyOn(task);
+ task.updateEffectiveIntent();
+ verify(task).setIntent(eq(activity1));
+ }
+
+ /**
+ * Test {@link Task#updateEffectiveIntent()} when all activities are finishing or
+ * relinquishing task identity. In this case the root activity should still be used when
+ * updating the intent (legacy behavior).
+ */
+ @Test
+ public void testUpdateEffectiveIntent_allFinishing() {
+ // Test simple case with a single activity.
+ final Task task = getTestTask();
+ final ActivityRecord activity0 = task.getBottomMostActivity();
+ // Mark the bottom-most activity as finishing.
+ activity0.finishing = true;
+ // Add an extra activity on top of the root one and make it relinquish task identity
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ activity1.finishing = true;
+
+ // Task must still update the intent using the root activity (preserving legacy behavior).
+ spyOn(task);
+ task.updateEffectiveIntent();
+ verify(task).setIntent(eq(activity0));
+ }
+
+ @Test
+ public void testSaveLaunchingStateWhenConfigurationChanged() {
+ LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
+ spyOn(persister);
+
+ final Task task = getTestTask();
+ task.setHasBeenVisible(false);
+ task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ task.setHasBeenVisible(true);
+ task.onConfigurationChanged(task.getParent().getConfiguration());
+
+ verify(persister).saveTask(task, task.getDisplayContent());
+ }
+
+ @Test
+ public void testSaveLaunchingStateWhenClearingParent() {
+ LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
+ spyOn(persister);
+
+ final Task task = getTestTask();
+ task.setHasBeenVisible(false);
+ task.getDisplayContent().setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+ task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ final DisplayContent oldDisplay = task.getDisplayContent();
+
+ LaunchParamsController.LaunchParams params = new LaunchParamsController.LaunchParams();
+ params.mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ persister.getLaunchParams(task, null, params);
+ assertEquals(WINDOWING_MODE_UNDEFINED, params.mWindowingMode);
+
+ task.setHasBeenVisible(true);
+ task.removeImmediately();
+
+ verify(persister).saveTask(task, oldDisplay);
+
+ persister.getLaunchParams(task, null, params);
+ assertEquals(WINDOWING_MODE_FULLSCREEN, params.mWindowingMode);
+ }
+
+ @Test
+ public void testNotSaveLaunchingStateNonFreeformDisplay() {
+ LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
+ spyOn(persister);
+
+ final Task task = getTestTask();
+ task.setHasBeenVisible(false);
+ task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ task.setHasBeenVisible(true);
+ task.onConfigurationChanged(task.getParent().getConfiguration());
+
+ Mockito.verify(persister, never()).saveTask(same(task), any());
+ }
+
+ @Test
+ public void testNotSaveLaunchingStateWhenNotFullscreenOrFreeformWindow() {
+ LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
+ spyOn(persister);
+
+ final Task task = getTestTask();
+ task.setHasBeenVisible(false);
+ task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.getRootTask().setWindowingMode(WINDOWING_MODE_PINNED);
+
+ task.setHasBeenVisible(true);
+ task.onConfigurationChanged(task.getParent().getConfiguration());
+
+ Mockito.verify(persister, never()).saveTask(same(task), any());
+ }
+
+ @Test
+ public void testNotSaveLaunchingStateForNonLeafTask() {
+ LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
+ spyOn(persister);
+
+ final Task task = getTestTask();
+ task.setHasBeenVisible(false);
+ task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ final Task leafTask = createTaskInRootTask(task, 0 /* userId */);
+
+ leafTask.setHasBeenVisible(true);
+ task.setHasBeenVisible(true);
+ task.onConfigurationChanged(task.getParent().getConfiguration());
+
+ Mockito.verify(persister, never()).saveTask(same(task), any());
+ verify(persister).saveTask(same(leafTask), any());
+ }
+
+ @Test
+ public void testNotSpecifyOrientationByFloatingTask() {
+ final Task task = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).setCreateParentTask(true).build();
+ final ActivityRecord activity = task.getTopMostActivity();
+ final WindowContainer<?> parentContainer = task.getParent();
+ final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
+ activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, parentContainer.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskDisplayArea.getOrientation());
+
+ task.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ // TDA returns the last orientation when child returns UNSET
+ assertEquals(SCREEN_ORIENTATION_UNSET, parentContainer.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskDisplayArea.getOrientation());
+ }
+
+ @Test
+ public void testNotSpecifyOrientation_taskDisplayAreaNotFocused() {
+ final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
+ final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
+ mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea",
+ FEATURE_VENDOR_FIRST);
+ final Task firstRootTask = firstTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final Task secondRootTask = secondTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+ .setTask(firstRootTask).build();
+ final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+ .setTask(secondRootTask).build();
+ firstActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ secondActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+ // Activity on TDA1 is focused
+ mDisplayContent.setFocusedApp(firstActivity);
+
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, firstTaskDisplayArea.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_UNSET, secondTaskDisplayArea.getOrientation());
+
+ // No focused app, TDA1 is still recorded as last focused.
+ mDisplayContent.setFocusedApp(null);
+
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, firstTaskDisplayArea.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_UNSET, secondTaskDisplayArea.getOrientation());
+
+ // Activity on TDA2 is focused
+ mDisplayContent.setFocusedApp(secondActivity);
+
+ assertEquals(SCREEN_ORIENTATION_UNSET, firstTaskDisplayArea.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, secondTaskDisplayArea.getOrientation());
+ }
+
+ @Test
+ public void testNotifyOrientationChangeCausedByConfigurationChange() {
+ final Task task = getTestTask();
+ final ActivityRecord activity = task.getTopMostActivity();
+ final DisplayContent display = task.getDisplayContent();
+ display.setWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
+ verify(display).onDescendantOrientationChanged(same(task));
+ reset(display);
+
+ display.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, task.getOrientation());
+ verify(display).onDescendantOrientationChanged(same(task));
+ }
+
+ private Task getTestTask() {
+ final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
+ return task.getBottomMostTask();
+ }
+
+ private void testRootTaskBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
+ Rect expectedConfigBounds) {
+
+ TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
+ Task rootTask = taskDisplayArea.createRootTask(windowingMode, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+ Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+
+ final Configuration parentConfig = rootTask.getConfiguration();
+ parentConfig.windowConfiguration.setAppBounds(parentBounds);
+ task.setBounds(bounds);
+
+ task.resolveOverrideConfiguration(parentConfig);
+ // Assert that both expected and actual are null or are equal to each other
+ assertEquals(expectedConfigBounds,
+ task.getResolvedOverrideConfiguration().windowConfiguration.getAppBounds());
+ }
+
+ private byte[] serializeToBytes(Task r) throws Exception {
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ final TypedXmlSerializer serializer = Xml.newFastSerializer();
+ serializer.setOutput(os, "UTF-8");
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TASK_TAG);
+ r.saveToXml(serializer);
+ serializer.endTag(null, TASK_TAG);
+ serializer.endDocument();
+
+ os.flush();
+ return os.toByteArray();
+ }
+ }
+
+ private Task restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
+ try (Reader reader = new InputStreamReader(new ByteArrayInputStream(in))) {
+ final TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(reader);
+ assertEquals(XmlPullParser.START_TAG, parser.next());
+ assertEquals(TASK_TAG, parser.getName());
+ return Task.restoreFromXml(parser, mAtm.mTaskSupervisor);
+ }
+ }
+
+ private Task createTask(int taskId) {
+ return new Task.Builder(mAtm)
+ .setTaskId(taskId)
+ .setIntent(new Intent())
+ .setRealActivity(ActivityBuilder.getDefaultComponent())
+ .setEffectiveUid(10050)
+ .buildInner();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 79ef8680dfec..2dfb3a1a84bc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -69,10 +69,8 @@ public class TransitionTests extends WindowTestsBase {
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
- final Task newTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task oldTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task newTask = createTask(mDisplayContent);
+ final Task oldTask = createTask(mDisplayContent);
final ActivityRecord closing = createActivityRecord(oldTask);
final ActivityRecord opening = createActivityRecord(newTask);
// Start states.
@@ -128,12 +126,10 @@ public class TransitionTests extends WindowTestsBase {
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
- final Task newTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task newNestedTask = createTaskInStack(newTask, 0);
- final Task newNestedTask2 = createTaskInStack(newTask, 0);
- final Task oldTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task newTask = createTask(mDisplayContent);
+ final Task newNestedTask = createTaskInRootTask(newTask, 0);
+ final Task newNestedTask2 = createTaskInRootTask(newTask, 0);
+ final Task oldTask = createTask(mDisplayContent);
final ActivityRecord closing = createActivityRecord(oldTask);
final ActivityRecord opening = createActivityRecord(newNestedTask);
final ActivityRecord opening2 = createActivityRecord(newNestedTask2);
@@ -179,11 +175,9 @@ public class TransitionTests extends WindowTestsBase {
final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN);
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
- final Task showTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task showNestedTask = createTaskInStack(showTask, 0);
- final Task showTask2 = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task showTask = createTask(mDisplayContent);
+ final Task showNestedTask = createTaskInRootTask(showTask, 0);
+ final Task showTask2 = createTask(mDisplayContent);
final DisplayArea tda = showTask.getDisplayArea();
final ActivityRecord showing = createActivityRecord(showNestedTask);
final ActivityRecord showing2 = createActivityRecord(showTask2);
@@ -231,12 +225,10 @@ public class TransitionTests extends WindowTestsBase {
public void testCreateInfo_existenceChange() {
final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN);
- final Task openTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task openTask = createTask(mDisplayContent);
final ActivityRecord opening = createActivityRecord(openTask);
opening.mVisibleRequested = false; // starts invisible
- final Task closeTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task closeTask = createTask(mDisplayContent);
final ActivityRecord closing = createActivityRecord(closeTask);
closing.mVisibleRequested = true; // starts visible
@@ -268,8 +260,8 @@ public class TransitionTests extends WindowTestsBase {
final Task[] tasks = new Task[taskCount];
for (int i = 0; i < taskCount; ++i) {
// Each add goes on top, so at the end of this, task[9] should be on top
- tasks[i] = createTaskStackOnDisplay(WINDOWING_MODE_FREEFORM,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ tasks[i] = createTask(mDisplayContent,
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
final ActivityRecord act = createActivityRecord(tasks[i]);
// alternate so that the transition doesn't get promoted to the display area
act.mVisibleRequested = (i % 2) == 0; // starts invisible
@@ -305,8 +297,8 @@ public class TransitionTests extends WindowTestsBase {
final Task[] tasks = new Task[taskCount];
for (int i = 0; i < taskCount; ++i) {
// Each add goes on top, so at the end of this, task[9] should be on top
- tasks[i] = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ tasks[i] = createTask(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final ActivityRecord act = createActivityRecord(tasks[i]);
// alternate so that the transition doesn't get promoted to the display area
act.mVisibleRequested = (i % 2) == 0; // starts invisible
@@ -353,15 +345,13 @@ public class TransitionTests extends WindowTestsBase {
ArraySet<WindowContainer> participants = transition.mParticipants;
ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
- final Task openTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task openInOpenTask = createTaskInStack(openTask, 0);
+ final Task openTask = createTask(mDisplayContent);
+ final Task openInOpenTask = createTaskInRootTask(openTask, 0);
final ActivityRecord openInOpen = createActivityRecord(openInOpenTask);
- final Task changeTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task changeInChangeTask = createTaskInStack(changeTask, 0);
- final Task openInChangeTask = createTaskInStack(changeTask, 0);
+ final Task changeTask = createTask(mDisplayContent);
+ final Task changeInChangeTask = createTaskInRootTask(changeTask, 0);
+ final Task openInChangeTask = createTaskInRootTask(changeTask, 0);
final ActivityRecord changeInChange = createActivityRecord(changeInChangeTask);
final ActivityRecord openInChange = createActivityRecord(openInChangeTask);
// set organizer for everything so that they all get added to transition info
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index b88173d5c1f0..6919c4cf6a7c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -811,18 +811,18 @@ public class WindowContainerTests extends WindowTestsBase {
@Test
public void testOnDisplayChanged() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack, 0 /* userId */);
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
final DisplayContent newDc = createNewDisplay();
- stack.getDisplayArea().removeRootTask(stack);
- newDc.getDefaultTaskDisplayArea().addChild(stack, POSITION_TOP);
+ rootTask.getDisplayArea().removeRootTask(rootTask);
+ newDc.getDefaultTaskDisplayArea().addChild(rootTask, POSITION_TOP);
- verify(stack).onDisplayChanged(newDc);
+ verify(rootTask).onDisplayChanged(newDc);
verify(task).onDisplayChanged(newDc);
verify(activity).onDisplayChanged(newDc);
- assertEquals(newDc, stack.mDisplayContent);
+ assertEquals(newDc, rootTask.mDisplayContent);
assertEquals(newDc, task.mDisplayContent);
assertEquals(newDc, activity.mDisplayContent);
}
@@ -854,21 +854,21 @@ public class WindowContainerTests extends WindowTestsBase {
@Test
public void testTaskCanApplyAnimation() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack, 0 /* userId */);
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
final ActivityRecord activity2 = createActivityRecord(mDisplayContent, task);
final ActivityRecord activity1 = createActivityRecord(mDisplayContent, task);
verifyWindowContainerApplyAnimation(task, activity1, activity2);
}
@Test
- public void testStackCanApplyAnimation() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
+ public void testRootTaskCanApplyAnimation() {
+ final Task rootTask = createTask(mDisplayContent);
final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
- createTaskInStack(stack, 0 /* userId */));
+ createTaskInRootTask(rootTask, 0 /* userId */));
final ActivityRecord activity1 = createActivityRecord(mDisplayContent,
- createTaskInStack(stack, 0 /* userId */));
- verifyWindowContainerApplyAnimation(stack, activity1, activity2);
+ createTaskInRootTask(rootTask, 0 /* userId */));
+ verifyWindowContainerApplyAnimation(rootTask, activity1, activity2);
}
@Test
@@ -878,21 +878,21 @@ public class WindowContainerTests extends WindowTestsBase {
assertNull(windowContainer.getDisplayArea());
- // ActivityStack > WindowContainer
- final Task activityStack = createTaskStackOnDisplay(mDisplayContent);
- activityStack.addChild(windowContainer, 0);
- activityStack.setParent(null);
+ // Task > WindowContainer
+ final Task task = createTask(mDisplayContent);
+ task.addChild(windowContainer, 0);
+ task.setParent(null);
assertNull(windowContainer.getDisplayArea());
- assertNull(activityStack.getDisplayArea());
+ assertNull(task.getDisplayArea());
- // TaskDisplayArea > ActivityStack > WindowContainer
+ // TaskDisplayArea > Task > WindowContainer
final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(
mDisplayContent, mWm, "TaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
- taskDisplayArea.addChild(activityStack, 0);
+ taskDisplayArea.addChild(task, 0);
assertEquals(taskDisplayArea, windowContainer.getDisplayArea());
- assertEquals(taskDisplayArea, activityStack.getDisplayArea());
+ assertEquals(taskDisplayArea, task.getDisplayArea());
assertEquals(taskDisplayArea, taskDisplayArea.getDisplayArea());
// DisplayArea
@@ -986,8 +986,8 @@ public class WindowContainerTests extends WindowTestsBase {
@Test
public void testFreezeInsets() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity = createActivityRecord(mDisplayContent, stack);
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
// Set visibility to false, verify the main window of the task will be set the frozen
@@ -1002,8 +1002,8 @@ public class WindowContainerTests extends WindowTestsBase {
@Test
public void testFreezeInsetsStateWhenAppTransition() {
- final Task stack = createTaskStackOnDisplay(mDisplayContent);
- final Task task = createTaskInStack(stack, 0 /* userId */);
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 6d0e510ba626..baf072dbbc10 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -80,18 +80,18 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
@Test
- public void testTaskFocusChange_stackNotHomeType_focusChanges() throws RemoteException {
+ public void testTaskFocusChange_rootTaskNotHomeType_focusChanges() throws RemoteException {
DisplayContent display = createNewDisplay();
// Current focused window
- Task focusedStack = createTaskStackOnDisplay(
- WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display);
- Task focusedTask = createTaskInStack(focusedStack, 0 /* userId */);
+ Task focusedRootTask = createTask(
+ display, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+ Task focusedTask = createTaskInRootTask(focusedRootTask, 0 /* userId */);
WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window");
mDisplayContent.mCurrentFocus = focusedWindow;
// Tapped task
- Task tappedStack = createTaskStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, display);
- Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
+ Task tappedRootTask = createTask(
+ display, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */);
spyOn(mWm.mAtmService);
mWm.handleTaskFocusChange(tappedTask);
@@ -100,19 +100,19 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
@Test
- public void testTaskFocusChange_stackHomeTypeWithSameTaskDisplayArea_focusDoesNotChange()
+ public void testTaskFocusChange_rootTaskHomeTypeWithSameTaskDisplayArea_focusDoesNotChange()
throws RemoteException {
DisplayContent display = createNewDisplay();
// Current focused window
- Task focusedStack = createTaskStackOnDisplay(
- WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display);
- Task focusedTask = createTaskInStack(focusedStack, 0 /* userId */);
+ Task focusedRootTask = createTask(
+ display, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+ Task focusedTask = createTaskInRootTask(focusedRootTask, 0 /* userId */);
WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window");
mDisplayContent.mCurrentFocus = focusedWindow;
// Tapped home task
- Task tappedStack = createTaskStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, display);
- Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
+ Task tappedRootTask = createTask(
+ display, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */);
spyOn(mWm.mAtmService);
mWm.handleTaskFocusChange(tappedTask);
@@ -121,21 +121,21 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
@Test
- public void testTaskFocusChange_stackHomeTypeWithDifferentTaskDisplayArea_focusChanges()
+ public void testTaskFocusChange_rootTaskHomeTypeWithDifferentTaskDisplayArea_focusChanges()
throws RemoteException {
final DisplayContent display = createNewDisplay();
final TaskDisplayArea secondTda = createTaskDisplayArea(
display, mWm, "Tapped TDA", FEATURE_VENDOR_FIRST);
// Current focused window
- Task focusedStack = createTaskStackOnDisplay(
- WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display);
- Task focusedTask = createTaskInStack(focusedStack, 0 /* userId */);
+ Task focusedRootTask = createTask(
+ display, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+ Task focusedTask = createTaskInRootTask(focusedRootTask, 0 /* userId */);
WindowState focusedWindow = createAppWindow(focusedTask, TYPE_APPLICATION, "App Window");
mDisplayContent.mCurrentFocus = focusedWindow;
// Tapped home task on another task display area
- Task tappedStack = createTaskStackOnTaskDisplayArea(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, secondTda);
- Task tappedTask = createTaskInStack(tappedStack, 0 /* userId */);
+ Task tappedRootTask = createTask(secondTda, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
+ Task tappedTask = createTaskInRootTask(tappedRootTask, 0 /* userId */);
spyOn(mWm.mAtmService);
mWm.handleTaskFocusChange(tappedTask);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 01c503e01326..e2b58bcb4bd5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -125,8 +125,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
return registerMockOrganizer(null);
}
- Task createTask(Task stack, boolean fakeDraw) {
- final Task task = createTaskInStack(stack, 0);
+ Task createTask(Task rootTask, boolean fakeDraw) {
+ final Task task = createTaskInRootTask(rootTask, 0);
if (fakeDraw) {
task.setHasBeenVisible(true);
@@ -134,13 +134,13 @@ public class WindowOrganizerTests extends WindowTestsBase {
return task;
}
- Task createTask(Task stack) {
+ Task createTask(Task rootTask) {
// Fake draw notifications for most of our tests.
- return createTask(stack, true);
+ return createTask(rootTask, true);
}
- Task createStack() {
- return createTaskStackOnDisplay(mDisplayContent);
+ Task createRootTask() {
+ return createTask(mDisplayContent);
}
@Before
@@ -153,14 +153,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testAppearVanish() throws RemoteException {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- stack.removeImmediately();
+ rootTask.removeImmediately();
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskVanished(any());
@@ -169,21 +169,21 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testAppearWaitsForVisibility() throws RemoteException {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack, false);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask, false);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- stack.setHasBeenVisible(true);
+ rootTask.setHasBeenVisible(true);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
- assertTrue(stack.getHasBeenVisible());
+ assertTrue(rootTask.getHasBeenVisible());
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- stack.removeImmediately();
+ rootTask.removeImmediately();
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskVanished(any());
@@ -192,108 +192,108 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testNoVanishedIfNoAppear() throws RemoteException {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack, false /* hasBeenVisible */);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask, false /* hasBeenVisible */);
// In this test we skip making the Task visible, and verify
// that even though a TaskOrganizer is set remove doesn't emit
// a vanish callback, because we never emitted appear.
- stack.setTaskOrganizer(organizer);
+ rootTask.setTaskOrganizer(organizer);
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- stack.removeImmediately();
+ rootTask.removeImmediately();
verify(organizer, never()).onTaskVanished(any());
}
@Test
public void testTaskNoDraw() throws RemoteException {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack, false /* fakeDraw */);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask, false /* fakeDraw */);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- assertTrue(stack.isOrganized());
+ assertTrue(rootTask.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
- assertTaskVanished(organizer, false /* expectVanished */, stack);
- assertFalse(stack.isOrganized());
+ assertTaskVanished(organizer, false /* expectVanished */, rootTask);
+ assertFalse(rootTask.isOrganized());
}
@Test
public void testClearOrganizer() throws RemoteException {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- assertTrue(stack.isOrganized());
+ assertTrue(rootTask.isOrganized());
- stack.setTaskOrganizer(null);
+ rootTask.setTaskOrganizer(null);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskVanished(any());
- assertFalse(stack.isOrganized());
+ assertFalse(rootTask.isOrganized());
}
@Test
public void testUnregisterOrganizer() throws RemoteException {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- assertTrue(stack.isOrganized());
+ assertTrue(rootTask.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
- assertTaskVanished(organizer, true /* expectVanished */, stack);
- assertFalse(stack.isOrganized());
+ assertTaskVanished(organizer, true /* expectVanished */, rootTask);
+ assertFalse(rootTask.isOrganized());
}
@Test
public void testUnregisterOrganizerReturnsRegistrationToPrevious() throws RemoteException {
- final Task stack = createStack();
- final Task task = createTask(stack);
- final Task stack2 = createStack();
- final Task task2 = createTask(stack2);
- final Task stack3 = createStack();
- final Task task3 = createTask(stack3);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
+ final Task rootTask2 = createRootTask();
+ final Task task2 = createTask(rootTask2);
+ final Task rootTask3 = createRootTask();
+ final Task task3 = createTask(rootTask3);
final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
// verify that tasks are returned and taskAppeared is not called
- assertContainsTasks(existingTasks, stack, stack2, stack3);
+ assertContainsTasks(existingTasks, rootTask, rootTask2, rootTask3);
verify(organizer, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
any(SurfaceControl.class));
verify(organizer, times(0)).onTaskVanished(any());
- assertTrue(stack.isOrganized());
+ assertTrue(rootTask.isOrganized());
// Now we replace the registration and verify the new organizer receives existing tasks
final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>();
final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
- assertContainsTasks(existingTasks2, stack, stack2, stack3);
+ assertContainsTasks(existingTasks2, rootTask, rootTask2, rootTask3);
verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
any(SurfaceControl.class));
verify(organizer2, times(0)).onTaskVanished(any());
// Removed tasks from the original organizer
- assertTaskVanished(organizer, true /* expectVanished */, stack, stack2, stack3);
- assertTrue(stack2.isOrganized());
+ assertTaskVanished(organizer, true /* expectVanished */, rootTask, rootTask2, rootTask3);
+ assertTrue(rootTask2.isOrganized());
// Now we unregister the second one, the first one should automatically be reregistered
// so we verify that it's now seeing changes.
@@ -302,18 +302,18 @@ public class WindowOrganizerTests extends WindowTestsBase {
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(3))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- assertTaskVanished(organizer2, true /* expectVanished */, stack, stack2, stack3);
+ assertTaskVanished(organizer2, true /* expectVanished */, rootTask, rootTask2, rootTask3);
}
@Test
public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException {
- final Task stack = createStack();
- final Task task = createTask(stack);
- final Task stack2 = createStack();
- final Task task2 = createTask(stack2);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
+ final Task rootTask2 = createRootTask();
+ final Task task2 = createTask(rootTask2);
ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
- assertContainsTasks(existingTasks, stack, stack2);
+ assertContainsTasks(existingTasks, rootTask, rootTask2);
// Verify we don't get onTaskAppeared if we are returned the tasks
verify(organizer, never())
@@ -323,21 +323,21 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testTaskTransaction() {
removeGlobalMinSizeRestriction();
- final Task stack = new TaskBuilder(mSupervisor)
+ final Task rootTask = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- final Task task = stack.getTopMostTask();
+ final Task task = rootTask.getTopMostTask();
testTransaction(task);
}
@Test
- public void testStackTransaction() {
+ public void testRootTaskTransaction() {
removeGlobalMinSizeRestriction();
- final Task stack = new TaskBuilder(mSupervisor)
+ final Task rootTask = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
RootTaskInfo info =
mWm.mAtmService.getRootTaskInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
- assertEquals(stack.mRemoteToken.toWindowContainerToken(), info.token);
- testTransaction(stack);
+ assertEquals(rootTask.mRemoteToken.toWindowContainerToken(), info.token);
+ testTransaction(rootTask);
}
@Test
@@ -357,9 +357,9 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testSetWindowingMode() {
- final Task stack = new TaskBuilder(mSupervisor)
+ final Task rootTask = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- testSetWindowingMode(stack);
+ testSetWindowingMode(rootTask);
final DisplayArea displayArea = new DisplayArea<>(mWm, ABOVE_TASKS, "DisplayArea");
displayArea.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -376,30 +376,30 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testSetActivityWindowingMode() {
final ActivityRecord record = makePipableActivity();
- final Task stack = record.getRootTask();
+ final Task rootTask = record.getRootTask();
final WindowContainerTransaction t = new WindowContainerTransaction();
- t.setWindowingMode(stack.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_PINNED);
+ t.setWindowingMode(rootTask.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_PINNED);
t.setActivityWindowingMode(
- stack.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_FULLSCREEN);
+ rootTask.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_FULLSCREEN);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertEquals(WINDOWING_MODE_FULLSCREEN, record.getWindowingMode());
- assertEquals(WINDOWING_MODE_PINNED, stack.getWindowingMode());
+ assertEquals(WINDOWING_MODE_PINNED, rootTask.getWindowingMode());
}
@Test
public void testContainerFocusableChanges() {
removeGlobalMinSizeRestriction();
- final Task stack = new TaskBuilder(mSupervisor)
+ final Task rootTask = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- final Task task = stack.getTopMostTask();
+ final Task task = rootTask.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
assertTrue(task.isFocusable());
- t.setFocusable(stack.mRemoteToken.toWindowContainerToken(), false);
+ t.setFocusable(rootTask.mRemoteToken.toWindowContainerToken(), false);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertFalse(task.isFocusable());
- t.setFocusable(stack.mRemoteToken.toWindowContainerToken(), true);
+ t.setFocusable(rootTask.mRemoteToken.toWindowContainerToken(), true);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertTrue(task.isFocusable());
}
@@ -407,25 +407,25 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testContainerHiddenChanges() {
removeGlobalMinSizeRestriction();
- final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true)
+ final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
WindowContainerTransaction t = new WindowContainerTransaction();
- assertTrue(stack.shouldBeVisible(null));
- t.setHidden(stack.mRemoteToken.toWindowContainerToken(), true);
+ assertTrue(rootTask.shouldBeVisible(null));
+ t.setHidden(rootTask.mRemoteToken.toWindowContainerToken(), true);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
- assertFalse(stack.shouldBeVisible(null));
- t.setHidden(stack.mRemoteToken.toWindowContainerToken(), false);
+ assertFalse(rootTask.shouldBeVisible(null));
+ t.setHidden(rootTask.mRemoteToken.toWindowContainerToken(), false);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
- assertTrue(stack.shouldBeVisible(null));
+ assertTrue(rootTask.shouldBeVisible(null));
}
@Test
public void testSetIgnoreOrientationRequest_taskDisplayArea() {
removeGlobalMinSizeRestriction();
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
- final Task stack = taskDisplayArea.createRootTask(
+ final Task rootTask = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build();
taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mDisplayContent.setFocusedApp(activity);
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -461,9 +461,9 @@ public class WindowOrganizerTests extends WindowTestsBase {
public void testSetIgnoreOrientationRequest_displayContent() {
removeGlobalMinSizeRestriction();
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
- final Task stack = taskDisplayArea.createRootTask(
+ final Task rootTask = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build();
mDisplayContent.setFocusedApp(activity);
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -491,21 +491,21 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testOverrideConfigSize() {
removeGlobalMinSizeRestriction();
- final Task stack = new TaskBuilder(mSupervisor)
+ final Task rootTask = new TaskBuilder(mSupervisor)
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- final Task task = stack.getTopMostTask();
+ final Task task = rootTask.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
final int origScreenWDp = task.getConfiguration().screenHeightDp;
final int origScreenHDp = task.getConfiguration().screenHeightDp;
t = new WindowContainerTransaction();
// verify that setting config overrides on parent restricts children.
- t.setScreenSizeDp(stack.mRemoteToken
+ t.setScreenSizeDp(rootTask.mRemoteToken
.toWindowContainerToken(), origScreenWDp, origScreenHDp / 2);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertEquals(origScreenHDp / 2, task.getConfiguration().screenHeightDp);
t = new WindowContainerTransaction();
- t.setScreenSizeDp(stack.mRemoteToken.toWindowContainerToken(), SCREEN_WIDTH_DP_UNDEFINED,
+ t.setScreenSizeDp(rootTask.mRemoteToken.toWindowContainerToken(), SCREEN_WIDTH_DP_UNDEFINED,
SCREEN_HEIGHT_DP_UNDEFINED);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertEquals(origScreenHDp, task.getConfiguration().screenHeightDp);
@@ -572,14 +572,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
RunningTaskInfo info1 = task.getTaskInfo();
- final Task stack = createTaskStackOnDisplay(
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
- assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
+ final Task rootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
+ assertEquals(mDisplayContent.getWindowingMode(), rootTask.getWindowingMode());
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
+ wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertEquals(info1.configuration.windowConfiguration.getWindowingMode(),
- stack.getWindowingMode());
+ rootTask.getWindowingMode());
// Info should reflect new membership
List<Task> infos = getTasksCreatedByOrganizer(mDisplayContent);
@@ -591,14 +591,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask();
Configuration c = new Configuration(task1.getRequestedOverrideConfiguration());
c.windowConfiguration.setBounds(newSize);
- doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any(), any());
+ doNothing().when(rootTask).adjustForMinimalTaskDimensions(any(), any(), any());
task1.onRequestedOverrideConfigurationChanged(c);
- assertEquals(newSize, stack.getBounds());
+ assertEquals(newSize, rootTask.getBounds());
wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
+ wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
- assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
+ assertEquals(mDisplayContent.getWindowingMode(), rootTask.getWindowingMode());
infos = getTasksCreatedByOrganizer(mDisplayContent);
info1 = infos.get(0).getTaskInfo();
assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType);
@@ -644,36 +644,39 @@ public class WindowOrganizerTests extends WindowTestsBase {
lastReportedTiles.clear();
called[0] = false;
- final Task stack = createTaskStackOnDisplay(
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task rootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask();
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
+ wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertTrue(called[0]);
assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType);
lastReportedTiles.clear();
called[0] = false;
- final Task stack2 = createTaskStackOnDisplay(
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent);
+ final Task rootTask2 = createTask(
+ mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
wct = new WindowContainerTransaction();
- wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
+ wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(),
+ info1.token, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertTrue(called[0]);
assertEquals(ACTIVITY_TYPE_HOME, lastReportedTiles.get(0).topActivityType);
lastReportedTiles.clear();
called[0] = false;
- task1.positionChildAt(POSITION_TOP, stack, false /* includingParents */);
+ task1.positionChildAt(POSITION_TOP, rootTask, false /* includingParents */);
assertTrue(called[0]);
assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType);
lastReportedTiles.clear();
called[0] = false;
wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
- wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
+ wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(),
+ null, true /* onTop */);
+ wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(),
+ null, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertTrue(called[0]);
assertEquals(ACTIVITY_TYPE_UNDEFINED, lastReportedTiles.get(0).topActivityType);
@@ -723,10 +726,10 @@ public class WindowOrganizerTests extends WindowTestsBase {
final int initialRootTaskCount = mWm.mAtmService.mTaskOrganizerController.getRootTasks(
mDisplayContent.mDisplayId, null /* activityTypes */).size();
- final Task stack = createTaskStackOnDisplay(
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task stack2 = createTaskStackOnDisplay(
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent);
+ final Task rootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
+ final Task rootTask2 = createTask(
+ mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
// Check getRootTasks works
List<RunningTaskInfo> roots = mWm.mAtmService.mTaskOrganizerController.getRootTasks(
@@ -735,8 +738,10 @@ public class WindowOrganizerTests extends WindowTestsBase {
lastReportedTiles.clear();
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
- wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), info2.token, true /* onTop */);
+ wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(),
+ info1.token, true /* onTop */);
+ wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(),
+ info2.token, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertFalse(lastReportedTiles.isEmpty());
assertEquals(ACTIVITY_TYPE_STANDARD,
@@ -746,7 +751,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
lastReportedTiles.clear();
wct = new WindowContainerTransaction();
- wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), info1.token, false /* onTop */);
+ wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(),
+ info1.token, false /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertFalse(lastReportedTiles.isEmpty());
// Standard should still be on top of tile 1, so no change there
@@ -771,7 +777,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
lastReportedTiles.clear();
wct = new WindowContainerTransaction();
- wct.reorder(stack2.mRemoteToken.toWindowContainerToken(), true /* onTop */);
+ wct.reorder(rootTask2.mRemoteToken.toWindowContainerToken(), true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
// Home should now be on top. No change occurs in second tile, so not reported
assertEquals(1, lastReportedTiles.size());
@@ -780,10 +786,10 @@ public class WindowOrganizerTests extends WindowTestsBase {
// This just needs to not crash (ie. it should be possible to reparent to display twice)
wct = new WindowContainerTransaction();
- wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
+ wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
wct = new WindowContainerTransaction();
- wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
+ wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
}
@@ -799,8 +805,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testBLASTCallbackWithActivityChildren() {
- final Task stackController1 = createStack();
- final Task task = createTask(stackController1);
+ final Task rootTaskController1 = createRootTask();
+ final Task task = createTask(rootTaskController1);
final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window");
w.mActivityRecord.mVisibleRequested = true;
@@ -926,11 +932,11 @@ public class WindowOrganizerTests extends WindowTestsBase {
ChangeSavingOrganizer o = new ChangeSavingOrganizer();
mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o);
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
+ final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task);
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
waitUntilHandlersIdle();
assertEquals("TestDescription", o.mChangedInfo.taskDescription.getLabel());
@@ -939,29 +945,29 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testPreventDuplicateAppear() throws RemoteException {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack, false /* fakeDraw */);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask, false /* fakeDraw */);
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- stack.setTaskOrganizer(organizer);
+ rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ rootTask.setTaskOrganizer(organizer);
// setHasBeenVisible was already called once by the set-up code.
- stack.setHasBeenVisible(true);
+ rootTask.setHasBeenVisible(true);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- stack.setTaskOrganizer(null);
+ rootTask.setTaskOrganizer(null);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(1)).onTaskVanished(any());
- stack.setTaskOrganizer(organizer);
+ rootTask.setTaskOrganizer(organizer);
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(2))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- stack.removeImmediately();
+ rootTask.removeImmediately();
// Ensure events dispatch to organizer.
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
verify(organizer, times(2)).onTaskVanished(any());
@@ -970,15 +976,15 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testInterceptBackPressedOnTaskRoot() throws RemoteException {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord activity = createActivityRecord(stack.mDisplayContent, task);
- final Task stack2 = createStack();
- final Task task2 = createTask(stack2);
- final ActivityRecord activity2 = createActivityRecord(stack.mDisplayContent, task2);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
+ final ActivityRecord activity = createActivityRecord(rootTask.mDisplayContent, task);
+ final Task rootTask2 = createRootTask();
+ final Task task2 = createTask(rootTask2);
+ final ActivityRecord activity2 = createActivityRecord(rootTask.mDisplayContent, task2);
- assertTrue(stack.isOrganized());
- assertTrue(stack2.isOrganized());
+ assertTrue(rootTask.isOrganized());
+ assertTrue(rootTask2.isOrganized());
// Verify a back pressed does not call the organizer
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token,
@@ -989,7 +995,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
// Enable intercepting back
mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(
- stack.mRemoteToken.toWindowContainerToken(), true);
+ rootTask.mRemoteToken.toWindowContainerToken(), true);
// Verify now that the back press does call the organizer
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token,
@@ -1000,7 +1006,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
// Disable intercepting back
mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(
- stack.mRemoteToken.toWindowContainerToken(), false);
+ rootTask.mRemoteToken.toWindowContainerToken(), false);
// Verify now that the back press no longer calls the organizer
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token,
@@ -1012,8 +1018,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testBLASTCallbackWithWindows() throws Exception {
- final Task stackController = createStack();
- final Task task = createTask(stackController);
+ final Task rootTaskController = createRootTask();
+ final Task task = createTask(rootTaskController);
final WindowState w1 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 1");
final WindowState w2 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 2");
makeWindowVisible(w1);
@@ -1077,7 +1083,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
final ITaskOrganizer organizer = registerMockOrganizer();
Task rootTask = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, null);
- final Task task1 = createStack();
+ final Task task1 = createRootTask();
final Task task2 = createTask(rootTask, false /* fakeDraw */);
WindowContainerTransaction wct = new WindowContainerTransaction();
wct.reparent(task1.mRemoteToken.toWindowContainerToken(),
@@ -1090,19 +1096,19 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testAppearDeferThenInfoChange() {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
+ final Task rootTask = createRootTask();
// Assume layout defer
mWm.mWindowPlacerLocked.deferLayout();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+ final Task task = createTask(rootTask);
+ final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task);
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
waitUntilHandlersIdle();
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(rootTask);
assertEquals(1, pendingEvents.size());
assertEquals(PendingTaskEvent.EVENT_APPEARED, pendingEvents.get(0).mEventType);
assertEquals("TestDescription",
@@ -1112,35 +1118,35 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testAppearDeferThenVanish() {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
+ final Task rootTask = createRootTask();
// Assume layout defer
mWm.mWindowPlacerLocked.deferLayout();
- final Task task = createTask(stack);
+ final Task task = createTask(rootTask);
- stack.removeImmediately();
+ rootTask.removeImmediately();
waitUntilHandlersIdle();
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(rootTask);
assertEquals(0, pendingEvents.size());
}
@Test
public void testInfoChangeDeferMultiple() {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
+ final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task);
// Assume layout defer
mWm.mWindowPlacerLocked.deferLayout();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
waitUntilHandlersIdle();
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(rootTask);
assertEquals(1, pendingEvents.size());
assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
assertEquals("TestDescription",
@@ -1149,7 +1155,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription2"));
waitUntilHandlersIdle();
- pendingEvents = getTaskPendingEvent(stack);
+ pendingEvents = getTaskPendingEvent(rootTask);
assertEquals(1, pendingEvents.size());
assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
assertEquals("TestDescription2",
@@ -1159,20 +1165,20 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testInfoChangDeferThenVanish() {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
+ final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task);
// Assume layout defer
mWm.mWindowPlacerLocked.deferLayout();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
- stack.removeImmediately();
+ rootTask.removeImmediately();
waitUntilHandlersIdle();
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(rootTask);
assertEquals(1, pendingEvents.size());
assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
assertEquals("TestDescription",
@@ -1182,18 +1188,18 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testVanishDeferThenInfoChange() {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
+ final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task);
// Assume layout defer
mWm.mWindowPlacerLocked.deferLayout();
- stack.removeImmediately();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ rootTask.removeImmediately();
+ rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
waitUntilHandlersIdle();
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(rootTask);
assertEquals(1, pendingEvents.size());
assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
}
@@ -1201,19 +1207,19 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testVanishDeferThenBackOnRoot() {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task stack = createStack();
- final Task task = createTask(stack);
- final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
+ final Task rootTask = createRootTask();
+ final Task task = createTask(rootTask);
+ final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task);
// Assume layout defer
mWm.mWindowPlacerLocked.deferLayout();
- stack.removeImmediately();
+ rootTask.removeImmediately();
mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(record.token,
new IRequestFinishCallback.Default());
waitUntilHandlersIdle();
- ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
+ ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(rootTask);
assertEquals(1, pendingEvents.size());
assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
}
@@ -1264,7 +1270,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testSizeCompatModeChangedOnFirstOrganizedTask() throws RemoteException {
final ITaskOrganizer organizer = registerMockOrganizer();
- final Task rootTask = createStack();
+ final Task rootTask = createRootTask();
final Task task = createTask(rootTask);
final ActivityRecord activity = createActivityRecord(rootTask.mDisplayContent, task);
final ArgumentCaptor<RunningTaskInfo> infoCaptor =
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 5b5b1da327bd..bfbe203fb65e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -249,21 +249,22 @@ public class WindowStateTests extends WindowTestsBase {
assertFalse(appWindow.canBeImeTarget());
assertFalse(imeWindow.canBeImeTarget());
- // Simulate the window is in split screen primary stack and the current state is
- // minimized and home stack is resizable, so that we should ignore input for the stack.
+ // Simulate the window is in split screen primary root task and the current state is
+ // minimized and home root task is resizable, so that we should ignore input for the
+ // root task.
final DockedTaskDividerController controller =
mDisplayContent.getDockedDividerController();
- final Task stack = createTaskStackOnDisplay(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task rootTask = createTask(mDisplayContent,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
spyOn(appWindow);
spyOn(controller);
- spyOn(stack);
- stack.setFocusable(false);
- doReturn(stack).when(appWindow).getRootTask();
+ spyOn(rootTask);
+ rootTask.setFocusable(false);
+ doReturn(rootTask).when(appWindow).getRootTask();
// Make sure canBeImeTarget is false due to shouldIgnoreInput is true;
assertFalse(appWindow.canBeImeTarget());
- assertTrue(stack.shouldIgnoreInput());
+ assertTrue(rootTask.shouldIgnoreInput());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index b210dfb654ba..e9e0c99c3d93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -429,35 +429,55 @@ class WindowTestsBase extends SystemServiceTestsBase {
return newTaskDisplayArea;
}
- /** Creates a {@link Task} and adds it to the specified {@link DisplayContent}. */
- Task createTaskStackOnDisplay(DisplayContent dc) {
- return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
+ /**
+ * Creates a {@link Task} with a simple {@link ActivityRecord} and adds to the given
+ * {@link TaskDisplayArea}.
+ */
+ Task createTaskWithActivity(TaskDisplayArea taskDisplayArea,
+ int windowingMode, int activityType, boolean onTop, boolean twoLevelTask) {
+ return createTask(taskDisplayArea, windowingMode, activityType,
+ onTop, true /* createActivity */, twoLevelTask);
}
- Task createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
- return new TaskBuilder(dc.mAtmService.mTaskSupervisor)
- .setDisplay(dc)
- .setWindowingMode(windowingMode)
- .setActivityType(activityType)
- .setIntent(new Intent())
- .build();
+ /** Creates a {@link Task} and adds to the given {@link DisplayContent}. */
+ Task createTask(DisplayContent dc) {
+ return createTask(dc.getDefaultTaskDisplayArea(),
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ }
+
+ Task createTask(DisplayContent dc, int windowingMode, int activityType) {
+ return createTask(dc.getDefaultTaskDisplayArea(), windowingMode, activityType);
+ }
+
+ Task createTask(TaskDisplayArea taskDisplayArea, int windowingMode, int activityType) {
+ return createTask(taskDisplayArea, windowingMode, activityType,
+ true /* onTop */, false /* createActivity */, false /* twoLevelTask */);
}
- Task createTaskStackOnTaskDisplayArea(int windowingMode, int activityType,
- TaskDisplayArea tda) {
- return new TaskBuilder(tda.mDisplayContent.mAtmService.mTaskSupervisor)
- .setTaskDisplayArea(tda)
+ /** Creates a {@link Task} and adds to the given {@link TaskDisplayArea}. */
+ Task createTask(TaskDisplayArea taskDisplayArea, int windowingMode, int activityType,
+ boolean onTop, boolean createActivity, boolean twoLevelTask) {
+ final TaskBuilder builder = new TaskBuilder(mSupervisor)
+ .setTaskDisplayArea(taskDisplayArea)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
- .setIntent(new Intent())
- .build();
+ .setOnTop(onTop)
+ .setCreateActivity(createActivity);
+ if (twoLevelTask) {
+ return builder
+ .setCreateParentTask(true)
+ .build()
+ .getRootTask();
+ } else {
+ return builder.build();
+ }
}
- /** Creates a {@link Task} and adds it to the specified {@link Task}. */
- Task createTaskInStack(Task stack, int userId) {
- final Task task = new TaskBuilder(stack.mTaskSupervisor)
+ /** Creates a {@link Task} and adds to the given root {@link Task}. */
+ Task createTaskInRootTask(Task rootTask, int userId) {
+ final Task task = new TaskBuilder(rootTask.mTaskSupervisor)
.setUserId(userId)
- .setParentTask(stack)
+ .setParentTask(rootTask)
.build();
return task;
}
@@ -485,7 +505,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
*/
ActivityRecord createActivityRecord(DisplayContent dc, int windowingMode,
int activityType) {
- final Task task = createTaskStackOnDisplay(windowingMode, activityType, dc);
+ final Task task = createTask(dc, windowingMode, activityType);
return createActivityRecord(dc, task);
}
@@ -517,7 +537,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
*/
ActivityRecord createActivityRecordWithParentTask(DisplayContent dc, int windowingMode,
int activityType) {
- final Task task = createTaskStackOnDisplay(windowingMode, activityType, dc);
+ final Task task = createTask(dc, windowingMode, activityType);
return createActivityRecordWithParentTask(task);
}
@@ -871,7 +891,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
.setParentTask(mParentTask).build();
} else if (mTask == null && mParentTask != null && DisplayContent.alwaysCreateRootTask(
mParentTask.getWindowingMode(), mParentTask.getActivityType())) {
- // The stack can be the task root.
+ // The parent task can be the task root.
mTask = mParentTask;
}
@@ -921,9 +941,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
doReturn(true).when(activity).fillsParent();
mTask.addChild(activity);
if (mOnTop) {
- // Move the task to front after activity added.
- // Or {@link TaskDisplayArea#mPreferredTopFocusableStack} could be other stacks
- // (e.g. home stack).
+ // Move the task to front after activity is added.
+ // Or {@link TaskDisplayArea#mPreferredTopFocusableRootTask} could be other
+ // root tasks (e.g. home root task).
mTask.moveToFront("createActivity");
}
// Make visible by default...
@@ -1127,8 +1147,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
.build();
if (mOnTop) {
// We move the task to front again in order to regain focus after activity
- // added to the stack. Or {@link TaskDisplayArea#mPreferredTopFocusableStack}
- // could be other stacks (e.g. home stack).
+ // is added. Or {@link TaskDisplayArea#mPreferredTopFocusableRootTask} could be
+ // other root tasks (e.g. home root task).
task.moveToFront("createActivityTask");
} else {
task.moveToBack("createActivityTask", null);