Simplified ActivityStack.shouldBeVisible()
The method can now be simplified since we have a stack per task so
if a stack should be visible is now a question of if it is occluded
by another stack.
Also,
- Fixed an issue where the windowing mode of the primary split-screen
stack was changing to split-screen-secondary instead of fullscreen
when we are exiting split-screen mode because we are not allowed to
to create fullscreen stack when there is a primary split-screen stack. We
now clear the reference to the primary split-screen stack when exiting
split-screen mode.
- Re-worked windowing mode resolution to be inside ActivityDisplay
object since the determination of the windowing mode is dependant on the
display.
Test: bit FrameworksServicesTests:com.android.server.am.ActivityStackTests
Test: Existing tests pass.
Test: go/wm-smoke
Bug: 64146578
Fixes: 67914671
Change-Id: I7e8cfe49fbf6a5836ded022bb11adcde58ae689c
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 679be1d..9e4a9e9 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -57,7 +57,7 @@
ComponentName.unflattenFromString("com.foo/.BarActivity2");
private ActivityManagerService mService;
- private ActivityStack mStack;
+ private TestActivityStack mStack;
private TaskRecord mTask;
private ActivityRecord mActivity;
@@ -76,13 +76,13 @@
@Test
public void testStackCleanupOnClearingTask() throws Exception {
mActivity.setTask(null);
- assertEquals(getActivityRemovedFromStackCount(), 1);
+ assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
}
@Test
public void testStackCleanupOnActivityRemoval() throws Exception {
mTask.removeActivity(mActivity);
- assertEquals(getActivityRemovedFromStackCount(), 1);
+ assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
}
@Test
@@ -97,7 +97,7 @@
final TaskRecord newTask =
createTask(mService.mStackSupervisor, testActivityComponent, mStack);
mActivity.reparent(newTask, 0, null /*reason*/);
- assertEquals(getActivityRemovedFromStackCount(), 0);
+ assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0);
}
@Test
@@ -129,15 +129,6 @@
assertEquals(expectedActivityBounds, mActivity.getBounds());
}
- private int getActivityRemovedFromStackCount() {
- if (mStack instanceof ActivityStackReporter) {
- return ((ActivityStackReporter) mStack).onActivityRemovedFromStackInvocationCount();
- }
-
- return -1;
- }
-
-
@Test
public void testCanBeLaunchedOnDisplay() throws Exception {
testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 4ee1f47..e17e51b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -16,13 +16,19 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+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 com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
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.assertTrue;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
@@ -45,7 +51,6 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStackTests extends ActivityTestsBase {
- private static final int TEST_STACK_ID = 100;
private static final ComponentName testActivityComponent =
ComponentName.unflattenFromString("com.foo/.BarActivity");
private static final ComponentName testOverlayComponent =
@@ -127,4 +132,122 @@
assertEquals(mTask.getTopActivity(true /* includeOverlays */), taskOverlay);
assertNotNull(result.r);
}
+
+ @Test
+ public void testShouldBeVisible_Fullscreen() throws Exception {
+ final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay();
+ final TestActivityStack homeStack = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+ final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+ assertTrue(homeStack.shouldBeVisible(null /* starting */));
+ assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
+
+ final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(display,
+ 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.
+ fullscreenStack.setIsTranslucent(false);
+ assertFalse(homeStack.shouldBeVisible(null /* starting */));
+ assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
+ assertTrue(fullscreenStack.shouldBeVisible(null /* starting */));
+
+ // Home stack should be visible behind a translucent fullscreen stack.
+ fullscreenStack.setIsTranslucent(true);
+ assertTrue(homeStack.shouldBeVisible(null /* starting */));
+ assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
+ }
+
+ @Test
+ public void testShouldBeVisible_SplitScreen() throws Exception {
+ final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay();
+ final TestActivityStack homeStack = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+ final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final TestActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+ // Home stack shouldn't be visible if both halves of split-screen are opaque.
+ splitScreenPrimary.setIsTranslucent(false);
+ splitScreenSecondary.setIsTranslucent(false);
+ assertFalse(homeStack.shouldBeVisible(null /* starting */));
+ assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
+ assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+
+ // Home stack should be visible if one of the halves of split-screen is translucent.
+ splitScreenPrimary.setIsTranslucent(true);
+ assertTrue(homeStack.shouldBeVisible(null /* starting */));
+ assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
+ assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+
+ final TestActivityStack splitScreenSecondary2 = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ // First split-screen secondary shouldn't be visible behind another opaque split-split
+ // secondary.
+ splitScreenSecondary2.setIsTranslucent(false);
+ assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
+ assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+
+ // First split-screen secondary should be visible behind another translucent split-split
+ // secondary.
+ splitScreenSecondary2.setIsTranslucent(true);
+ assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+ assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+
+ final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
+
+ // Split-screen stacks shouldn't be visible behind an opaque fullscreen stack.
+ assistantStack.setIsTranslucent(false);
+ assertTrue(assistantStack.shouldBeVisible(null /* starting */));
+ assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
+ assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
+ assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+
+ // Split-screen stacks should be visible behind a translucent fullscreen stack.
+ assistantStack.setIsTranslucent(true);
+ assertTrue(assistantStack.shouldBeVisible(null /* starting */));
+ assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
+ assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+ assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+ }
+
+ @Test
+ public void testShouldBeVisible_Finishing() throws Exception {
+ final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay();
+ final TestActivityStack homeStack = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+ final TestActivityStack translucentStack = createStackForShouldBeVisibleTest(display,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ translucentStack.setIsTranslucent(true);
+
+ assertTrue(homeStack.shouldBeVisible(null /* starting */));
+ assertTrue(translucentStack.shouldBeVisible(null /* starting */));
+
+ final ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
+ topRunningHomeActivity.finishing = true;
+ final ActivityRecord topRunningTranslucentActivity =
+ translucentStack.topRunningActivityLocked();
+ topRunningTranslucentActivity.finishing = true;
+
+ // Home shouldn't be visible since its activity is marked as finishing and it isn't the top
+ // of the stack list.
+ assertFalse(homeStack.shouldBeVisible(null /* starting */));
+ // Home should be visible if we are starting an activity within it.
+ assertTrue(homeStack.shouldBeVisible(topRunningHomeActivity /* starting */));
+ // The translucent stack should be visible since it is the top of the stack list even though
+ // it has its activity marked as finishing.
+ assertTrue(translucentStack.shouldBeVisible(null /* starting */));
+ }
+
+ private <T extends ActivityStack> T createStackForShouldBeVisibleTest(
+ ActivityDisplay display, int windowingMode, int activityType, boolean onTop) {
+ final T stack = display.createStack(windowingMode, activityType, onTop);
+ // Create a task and activity in the stack so that it has a top running activity.
+ final TaskRecord task = createTask(mSupervisor, testActivityComponent, stack);
+ final ActivityRecord r = createActivity(mService, testActivityComponent, task, 0);
+ return stack;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index d36f9d3..f5cdf21 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -276,20 +276,21 @@
return service;
}
- protected interface ActivityStackReporter {
- int onActivityRemovedFromStackInvocationCount();
- }
-
/**
* Overrided of {@link ActivityStack} that tracks test metrics, such as the number of times a
* method is called. Note that its functionality depends on the implementations of the
* construction arguments.
*/
protected static class TestActivityStack<T extends StackWindowController>
- extends ActivityStack<T> implements ActivityStackReporter {
+ extends ActivityStack<T> {
private int mOnActivityRemovedFromStackCount = 0;
private T mContainerController;
+ static final int IS_TRANSLUCENT_UNSET = 0;
+ static final int IS_TRANSLUCENT_FALSE = 1;
+ static final int IS_TRANSLUCENT_TRUE = 2;
+ private int mIsTranslucent = IS_TRANSLUCENT_UNSET;
+
TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
int windowingMode, int activityType, boolean onTop) {
super(display, stackId, supervisor, windowingMode, activityType, onTop);
@@ -302,8 +303,7 @@
}
// Returns the number of times {@link #onActivityRemovedFromStack} has been called
- @Override
- public int onActivityRemovedFromStackInvocationCount() {
+ int onActivityRemovedFromStackInvocationCount() {
return mOnActivityRemovedFromStackCount;
}
@@ -317,5 +317,22 @@
T getWindowContainerController() {
return mContainerController;
}
+
+ void setIsTranslucent(boolean isTranslucent) {
+ mIsTranslucent = isTranslucent ? IS_TRANSLUCENT_TRUE : IS_TRANSLUCENT_FALSE;
+ }
+
+ @Override
+ boolean isStackTranslucent(ActivityRecord starting, ActivityStack stackBehind) {
+ switch (mIsTranslucent) {
+ case IS_TRANSLUCENT_TRUE:
+ return true;
+ case IS_TRANSLUCENT_FALSE:
+ return false;
+ case IS_TRANSLUCENT_UNSET:
+ default:
+ return super.isStackTranslucent(starting, stackBehind);
+ }
+ }
}
}