diff options
9 files changed, 151 insertions, 100 deletions
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index a72470d90dab..05293b5138a0 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -373,7 +373,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> return getOrCreateStack(windowingMode, activityType, onTop); } - private int getNextStackId() { + @VisibleForTesting + int getNextStackId() { return sNextFreeStackId++; } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 026c5cc3017d..0049e227b269 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -48,6 +48,26 @@ import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM; import static com.android.server.am.ActivityDisplay.POSITION_TOP; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP; +import static com.android.server.am.ActivityStack.ActivityState.DESTROYED; +import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; +import static com.android.server.am.ActivityStack.ActivityState.FINISHING; +import static com.android.server.am.ActivityStack.ActivityState.PAUSED; +import static com.android.server.am.ActivityStack.ActivityState.PAUSING; +import static com.android.server.am.ActivityStack.ActivityState.RESUMED; +import static com.android.server.am.ActivityStack.ActivityState.STOPPED; +import static com.android.server.am.ActivityStack.ActivityState.STOPPING; +import static com.android.server.am.ActivityStackProto.BOUNDS; +import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER; +import static com.android.server.am.ActivityStackProto.DISPLAY_ID; +import static com.android.server.am.ActivityStackProto.FULLSCREEN; +import static com.android.server.am.ActivityStackProto.ID; +import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY; +import static com.android.server.am.ActivityStackProto.TASKS; +import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; +import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; +import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_APP; @@ -66,7 +86,6 @@ import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_USER_LE import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_APP; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP; import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONTAINERS; import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; @@ -81,29 +100,10 @@ import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_USER_ import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG; import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; -import static com.android.server.am.ActivityStack.ActivityState.DESTROYED; -import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.am.ActivityStack.ActivityState.FINISHING; -import static com.android.server.am.ActivityStack.ActivityState.PAUSED; -import static com.android.server.am.ActivityStack.ActivityState.PAUSING; -import static com.android.server.am.ActivityStack.ActivityState.RESUMED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPING; -import static com.android.server.am.ActivityStackProto.BOUNDS; -import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER; -import static com.android.server.am.ActivityStackProto.DISPLAY_ID; -import static com.android.server.am.ActivityStackProto.FULLSCREEN; -import static com.android.server.am.ActivityStackProto.ID; -import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY; -import static com.android.server.am.ActivityStackProto.TASKS; -import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; -import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; -import static com.android.server.am.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG; import static java.lang.Integer.MAX_VALUE; import android.app.Activity; @@ -1807,13 +1807,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } - final ActivityRecord top = topRunningActivityLocked(); - if (top == null && isInStackLocked(starting) == null && !isTopStackOnDisplay()) { - // Shouldn't be visible if you don't have any running activities, not starting one, and - // not the top stack on display. - return false; - } - final ActivityDisplay display = getDisplay(); boolean gotSplitScreenStack = false; boolean gotOpaqueSplitScreenPrimary = false; @@ -1822,9 +1815,16 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final boolean isAssistantType = isActivityTypeAssistant(); for (int i = display.getChildCount() - 1; i >= 0; --i) { final ActivityStack other = display.getChildAt(i); + final boolean hasRunningActivities = other.topRunningActivityLocked() != null; if (other == this) { - // Should be visible if there is no other stack occluding it. - return true; + // Should be visible if there is no other stack occluding it, unless it doesn't + // have any running activities, not starting one and not home stack. + return hasRunningActivities || isInStackLocked(starting) != null + || isActivityTypeHome(); + } + + if (!hasRunningActivities) { + continue; } final int otherWindowingMode = other.getWindowingMode(); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java index 0da574239666..59c40673f105 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java @@ -60,8 +60,7 @@ public class ActivityDisplayTests extends ActivityTestsBase { public void testLastFocusedStackIsUpdatedWhenMovingStack() { // Create a stack at bottom. final ActivityDisplay display = mSupervisor.getDefaultDisplay(); - final ActivityStack stack = display.createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, !ON_TOP); + final ActivityStack stack = new StackBuilder(mSupervisor).setOnTop(!ON_TOP).build(); final ActivityStack prevFocusedStack = display.getFocusedStack(); stack.moveToFront("moveStackToFront"); @@ -140,16 +139,14 @@ public class ActivityDisplayTests extends ActivityTestsBase { */ @Test public void testTopRunningActivity() { - // Create stack to hold focus. final ActivityDisplay display = mSupervisor.getDefaultDisplay(); - final ActivityStack emptyStack = display.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_STANDARD, true /* onTop */); - final KeyguardController keyguard = mSupervisor.getKeyguardController(); - final ActivityStack stack = mSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) - .setStack(stack).build(); + final ActivityStack stack = new StackBuilder(mSupervisor).build(); + final ActivityRecord activity = stack.getTopActivity(); + + // Create empty stack on top. + final ActivityStack emptyStack = + new StackBuilder(mSupervisor).setCreateActivity(false).build(); // Make sure the top running activity is not affected when keyguard is not locked. assertTopRunningActivity(activity, display); @@ -159,8 +156,8 @@ public class ActivityDisplayTests extends ActivityTestsBase { assertEquals(activity, display.topRunningActivity()); assertNull(display.topRunningActivity(true /* considerKeyguardState */)); - // Change focus to stack with activity. - stack.moveToFront("focusChangeToTestStack"); + // Move stack with activity to top. + stack.moveToFront("testStackToFront"); assertEquals(stack, display.getFocusedStack()); assertEquals(activity, display.topRunningActivity()); assertNull(display.topRunningActivity(true /* considerKeyguardState */)); @@ -175,11 +172,10 @@ public class ActivityDisplayTests extends ActivityTestsBase { // Ensure the show when locked activity is returned. assertTopRunningActivity(showWhenLockedActivity, display); - // Change focus back to empty stack. - emptyStack.moveToFront("focusChangeToEmptyStack"); - assertEquals(emptyStack, display.getFocusedStack()); - // If there is no running activity in focused stack, the running activity in next focusable - // stack should be returned. + // 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.getFocusedStack()); assertTopRunningActivity(showWhenLockedActivity, display); } 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 ffc7fa26d9a1..101500812265 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -79,10 +79,9 @@ public class ActivityRecordTests extends ActivityTestsBase { super.setUp(); setupActivityTaskManagerService(); - mStack = mSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - mTask = new TaskBuilder(mSupervisor).setStack(mStack).build(); - mActivity = new ActivityBuilder(mService).setTask(mTask).build(); + mStack = new StackBuilder(mSupervisor).build(); + mTask = mStack.getChildAt(0); + mActivity = mTask.getTopActivity(); } @Test diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index 2c993d32c20c..bdceec79eb29 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -359,15 +359,12 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { public void testFindTaskToMoveToFrontWhenRecentsOnTop() throws Exception { // Create stack/task on default display. final ActivityDisplay display = mSupervisor.getDefaultDisplay(); - final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_STANDARD, false /* onTop */); - final TaskRecord targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build(); + final TestActivityStack targetStack = new StackBuilder(mSupervisor).setOnTop(false).build(); + final TaskRecord targetTask = targetStack.getChildAt(0); // Create Recents on top of the display. - final ActivityStack stack = display.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_RECENTS, true /* onTop */); - final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build(); - new ActivityBuilder(mService).setTask(task).build(); + final ActivityStack stack = + new StackBuilder(mSupervisor).setActivityType(ACTIVITY_TYPE_RECENTS).build(); final String reason = "findTaskToMoveToFront"; mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason, 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 53f67afb629e..ea33de74721e 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -26,8 +26,8 @@ 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 com.android.server.am.ActivityStack.ActivityState.STOPPING; import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.am.ActivityStack.ActivityState.FINISHING; import static com.android.server.am.ActivityStack.ActivityState.PAUSED; import static com.android.server.am.ActivityStack.ActivityState.PAUSING; import static com.android.server.am.ActivityStack.ActivityState.RESUMED; @@ -361,14 +361,12 @@ public class ActivityStackTests extends ActivityTestsBase { 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 stack should be visible even there are no running activities. + assertTrue(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 */)); + // The translucent stack shouldn't be visible since its activity marked as finishing. + assertFalse(translucentStack.shouldBeVisible(null /* starting */)); } @Test @@ -672,9 +670,10 @@ public class ActivityStackTests extends ActivityTestsBase { // There is still an activity1 in stack1 so the activity2 should be added to finishing list // that will be destroyed until idle. + stack2.getTopActivity().visible = true; final ActivityRecord activity2 = finishCurrentActivity(stack2); - assertEquals(FINISHING, activity2.getState()); - assertTrue(mSupervisor.mFinishingActivities.contains(activity2)); + assertEquals(STOPPING, activity2.getState()); + assertTrue(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. 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 094241e98a8d..adf861b8d936 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -39,14 +39,6 @@ import static org.mockito.Mockito.spy; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; -import android.content.pm.PackageManagerInternal; -import com.android.server.uri.UriGrantsManagerInternal; -import com.android.server.wm.ActivityTaskManagerInternal; -import com.android.server.wm.DisplayWindowController; - -import org.junit.Rule; -import org.mockito.invocation.InvocationOnMock; - import android.app.IApplicationThread; import android.content.ComponentName; import android.content.Context; @@ -54,6 +46,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; +import android.content.pm.PackageManagerInternal; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.display.DisplayManager; @@ -73,7 +66,10 @@ import com.android.internal.app.IVoiceInteractor; import com.android.server.AppOpsService; import com.android.server.AttributeCache; import com.android.server.ServiceThread; +import com.android.server.uri.UriGrantsManagerInternal; +import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.AppWindowContainerController; +import com.android.server.wm.DisplayWindowController; import com.android.server.wm.PinnedStackWindowController; import com.android.server.wm.RootWindowContainerController; import com.android.server.wm.StackWindowController; @@ -83,7 +79,9 @@ import com.android.server.wm.WindowTestUtils; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; import java.io.File; import java.util.List; @@ -608,23 +606,9 @@ public class ActivityTestsBase { @Override <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop) { - if (windowingMode == WINDOWING_MODE_PINNED) { - return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop) { - @Override - Rect getDefaultPictureInPictureBounds(float aspectRatio) { - return new Rect(50, 50, 100, 100); - } - - @Override - PinnedStackWindowController createStackWindowController(int displayId, - boolean onTop, Rect outBounds) { - return mock(PinnedStackWindowController.class); - } - }; - } else { - return (T) new TestActivityStack( - this, stackId, mSupervisor, windowingMode, activityType, onTop); - } + return new StackBuilder(mSupervisor).setDisplay(this) + .setWindowingMode(windowingMode).setActivityType(activityType) + .setStackId(stackId).setOnTop(onTop).setCreateActivity(false).build(); } @Override @@ -677,8 +661,19 @@ public class ActivityTestsBase { private int mSupportsSplitScreen = SUPPORTS_SPLIT_SCREEN_UNSET; TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor, - int windowingMode, int activityType, boolean onTop) { + int windowingMode, int activityType, boolean onTop, boolean createActivity) { super(display, stackId, supervisor, windowingMode, activityType, onTop); + if (createActivity) { + new ActivityBuilder(mService).setCreateTask(true).setStack(this).build(); + if (onTop) { + // We move the task to front again in order to regain focus after activity + // added to the stack. Or {@link ActivityDisplay#mPreferredTopFocusableStack} + // could be other stacks (e.g. home stack). + moveToFront("createActivityStack"); + } else { + moveToBack("createActivityStack", null); + } + } } @Override @@ -750,4 +745,71 @@ public class ActivityTestsBase { ActivityOptions options) { } } + + protected static class StackBuilder { + private final ActivityStackSupervisor mSupervisor; + private ActivityDisplay mDisplay; + private int mStackId = -1; + private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; + private int mActivityType = ACTIVITY_TYPE_STANDARD; + private boolean mOnTop = true; + private boolean mCreateActivity = true; + + StackBuilder(ActivityStackSupervisor supervisor) { + mSupervisor = supervisor; + mDisplay = mSupervisor.getDefaultDisplay(); + } + + StackBuilder setWindowingMode(int windowingMode) { + mWindowingMode = windowingMode; + return this; + } + + StackBuilder setActivityType(int activityType) { + mActivityType = activityType; + return this; + } + + StackBuilder setStackId(int stackId) { + mStackId = stackId; + return this; + } + + StackBuilder setDisplay(ActivityDisplay display) { + mDisplay = display; + return this; + } + + StackBuilder setOnTop(boolean onTop) { + mOnTop = onTop; + return this; + } + + StackBuilder setCreateActivity(boolean createActivity) { + mCreateActivity = createActivity; + return this; + } + + <T extends ActivityStack> T build() { + final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId(); + if (mWindowingMode == WINDOWING_MODE_PINNED) { + return (T) new PinnedActivityStack(mDisplay, stackId, mSupervisor, mOnTop) { + @Override + Rect getDefaultPictureInPictureBounds(float aspectRatio) { + return new Rect(50, 50, 100, 100); + } + + @Override + PinnedStackWindowController createStackWindowController(int displayId, + boolean onTop, Rect outBounds) { + return mock(PinnedStackWindowController.class); + } + }; + } else { + return (T) new TestActivityStack(mDisplay, stackId, mSupervisor, mWindowingMode, + mActivityType, mOnTop, mCreateActivity); + } + } + + } } diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java index 27e8c632c1bd..129b835f588c 100644 --- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java +++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java @@ -883,7 +883,7 @@ public class RecentTasksTest extends ActivityTestsBase { MyTestActivityStack(ActivityDisplay display, ActivityStackSupervisor supervisor) { super(display, LAST_STACK_ID++, supervisor, WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_STANDARD, true); + ACTIVITY_TYPE_STANDARD, true /* onTop */, false /* createActivity */); mDisplay = display; } diff --git a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java index aa3046fb694c..849a41183672 100644 --- a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java +++ b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java @@ -16,9 +16,7 @@ package com.android.server.am; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; @@ -30,7 +28,6 @@ import android.app.ActivityManager.RunningTaskInfo; import android.content.ComponentName; import android.content.Context; import android.platform.test.annotations.Presubmit; -import android.util.SparseArray; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; @@ -72,8 +69,8 @@ public class RunningTasksTest extends ActivityTestsBase { final int numStacks = 2; for (int stackIndex = 0; stackIndex < numStacks; stackIndex++) { - final ActivityStack stack = new TestActivityStack(display, stackIndex, mSupervisor, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true); + final ActivityStack stack = + new StackBuilder(mSupervisor).setCreateActivity(false).build(); display.addChild(stack, POSITION_BOTTOM); } |