2/n Move task management logic to TaskContainers
Still no changes in logic, just moving the code around.
Bug: 152116619
Test: WM CTS and unit tests
Change-Id: I083b751c20fe110f120ae6c7626d3f2e974605ab
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 29f7d52..78d6e27 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2504,7 +2504,7 @@
final DisplayContent display = stack.getDisplay();
next = display.topRunningActivity();
if (next != null) {
- display.positionStackAtTop(next.getRootTask(),
+ display.mTaskContainers.positionStackAtTop(next.getRootTask(),
false /* includingParents */, "finish-display-top");
}
}
@@ -2679,7 +2679,7 @@
final ActivityRecord next = display.topRunningActivity();
final boolean isLastStackOverEmptyHome =
next == null && stack.isFocusedStackOnDisplay()
- && display.getOrCreateRootHomeTask() != null;
+ && display.mTaskContainers.getOrCreateRootHomeTask() != null;
if (isLastStackOverEmptyHome) {
// Don't destroy activity immediately if this is the last activity on the display and
// the display contains home stack. Although there is no next activity at the moment,
@@ -4477,7 +4477,7 @@
// case where this is the top activity in a pinned stack.
final boolean isTop = this == stack.getTopNonFinishingActivity();
final boolean isTopNotPinnedStack = stack.isAttached()
- && stack.getDisplay().isTopNotPinnedStack(stack);
+ && stack.getDisplay().mTaskContainers.isTopNotPinnedStack(stack);
final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
@@ -7389,7 +7389,7 @@
*/
boolean isResumedActivityOnDisplay() {
final DisplayContent display = getDisplay();
- return display != null && this == display.getResumedActivity();
+ return display != null && this == display.mTaskContainers.getResumedActivity();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 9089859..64c14cf 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -670,7 +670,7 @@
// Since always on top is only on when the stack is freeform or pinned, the state
// can be toggled when the windowing mode changes. We must make sure the stack is
// placed properly when always on top state changes.
- display.positionStackAtTop(this, false /* includingParents */);
+ display.mTaskContainers.positionStackAtTop(this, false /* includingParents */);
}
}
@@ -742,7 +742,7 @@
// Need to make sure windowing mode is supported. If we in the process of creating the stack
// no need to resolve the windowing mode again as it is already resolved to the right mode.
if (!creating) {
- windowingMode = display.validateWindowingMode(windowingMode,
+ windowingMode = display.mTaskContainers.validateWindowingMode(windowingMode,
null /* ActivityRecord */, topTask, getActivityType());
}
if (display.getRootSplitScreenPrimaryTask() == this
@@ -752,7 +752,8 @@
windowingMode = mRestoreOverrideWindowingMode;
}
- final boolean alreadyInSplitScreenMode = display.isSplitScreenModeActivated();
+ final boolean alreadyInSplitScreenMode = display.mTaskContainers
+ .isSplitScreenModeActivated();
// Don't send non-resizeable notifications if the windowing mode changed was a side effect
// of us entering split-screen mode.
@@ -769,7 +770,7 @@
// warning toast about it.
mAtmService.getTaskChangeNotificationController()
.notifyActivityDismissingDockedStack();
- display.onSplitScreenModeDismissed();
+ display.mTaskContainers.onSplitScreenModeDismissed();
}
}
@@ -861,7 +862,7 @@
// TODO (b/78247419): Fix the rotation animation from fullscreen to minimized mode
final boolean isRecentsComponentHome =
mAtmService.getRecentTasks().isRecentsComponentHomeActivity(mCurrentUser);
- final ActivityStack recentStack = display.getOrCreateStack(
+ final ActivityStack recentStack = display.mTaskContainers.getOrCreateStack(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
isRecentsComponentHome ? ACTIVITY_TYPE_HOME : ACTIVITY_TYPE_RECENTS,
true /* onTop */);
@@ -1058,7 +1059,7 @@
// cutting between them.
// TODO(b/70677280): This is a workaround until we can fix as part of b/70677280.
final ActivityStack topFullScreenStack =
- display.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ display.mTaskContainers.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
if (topFullScreenStack != null) {
final ActivityStack primarySplitScreenStack = display.getRootSplitScreenPrimaryTask();
if (primarySplitScreenStack != null && display.getIndexOf(topFullScreenStack)
@@ -1071,11 +1072,11 @@
if (!isActivityTypeHome() && returnsToHomeStack()) {
// Make sure the home stack is behind this stack since that is where we should return to
// when this stack is no longer visible.
- display.moveHomeStackToFront(reason + " returnToHome");
+ display.mTaskContainers.moveHomeStackToFront(reason + " returnToHome");
}
if (isRootTask()) {
- display.positionStackAtTop(this, false /* includingParents */, reason);
+ display.mTaskContainers.positionStackAtTop(this, false /* includingParents */, reason);
}
if (task == null) {
task = this;
@@ -1092,7 +1093,7 @@
return;
}
- getDisplay().positionStackAtBottom(this, reason);
+ getDisplay().mTaskContainers.positionStackAtBottom(this, reason);
if (task != null && task != this) {
positionChildAtBottom(task);
}
@@ -1460,7 +1461,7 @@
boolean isTopStackOnDisplay() {
final DisplayContent display = getDisplay();
- return display != null && display.isTopStack(this);
+ return display != null && display.mTaskContainers.isTopStack(this);
}
/**
@@ -1667,7 +1668,8 @@
*/
boolean isTopSplitScreenStack() {
return inSplitScreenWindowingMode()
- && this == getDisplay().getTopStackInWindowingMode(getWindowingMode());
+ && this == getDisplay().mTaskContainers
+ .getTopStackInWindowingMode(getWindowingMode());
}
/** @return True if the resizing of the primary-split-screen stack affects this stack size. */
@@ -1900,7 +1902,7 @@
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.isState(RESUMED)
- && display.allResumedActivitiesComplete()) {
+ && display.mTaskContainers.allResumedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
@@ -1979,7 +1981,7 @@
mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
ActivityRecord lastResumed = null;
- final ActivityStack lastFocusedStack = display.getLastFocusedStack();
+ final ActivityStack lastFocusedStack = display.mTaskContainers.getLastFocusedStack();
if (lastFocusedStack != null && lastFocusedStack != this) {
// So, why aren't we using prev here??? See the param comment on the method. prev doesn't
// represent the last resumed activity. However, the last focus stack does if it isn't null.
@@ -1993,7 +1995,7 @@
}
}
- boolean pausing = display.pauseBackStacks(userLeaving, next);
+ boolean pausing = display.mTaskContainers.pauseBackStacks(userLeaving, next);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
@@ -2022,7 +2024,7 @@
}
return true;
} else if (mResumedActivity == next && next.isState(RESUMED)
- && display.allResumedActivitiesComplete()) {
+ && display.mTaskContainers.allResumedActivitiesComplete()) {
// It is possible for the activity to be resumed when we paused back stacks above if the
// next activity doesn't have to wait for pause to complete.
// So, nothing else to-do except:
@@ -2542,7 +2544,7 @@
if (stack.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) {
// If we will be focusing on the home stack next and its current top activity isn't
// visible, then use the move the home stack task to top to make the activity visible.
- stack.getDisplay().moveHomeActivityToTop(reason);
+ stack.getDisplay().mTaskContainers.moveHomeActivityToTop(reason);
return stack;
}
@@ -3304,7 +3306,7 @@
final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
boolean toTop = position >= getChildCount();
- boolean includingParents = toTop || getDisplay().getNextFocusableStack(this,
+ boolean includingParents = toTop || getDisplay().mTaskContainers.getNextFocusableStack(this,
true /* ignoreCurrent */) == null;
if (WindowManagerDebugConfig.DEBUG_STACK) {
Slog.i(TAG_WM, "positionChildAt: positioning task=" + task + " at " + position);
@@ -3348,7 +3350,7 @@
// always on top windows. Since the position the stack should be inserted into is calculated
// properly in {@link DisplayContent#getTopInsertPosition()} in both cases, we can just
// request that the stack is put at top here.
- display.positionStackAtTop(this, false /* includingParents */);
+ display.mTaskContainers.positionStackAtTop(this, false /* includingParents */);
}
/** NOTE: Should only be called from {@link Task#reparent}. */
@@ -3399,7 +3401,7 @@
final Task task = getBottomMostTask();
setWindowingMode(WINDOWING_MODE_UNDEFINED);
- getDisplay().positionStackAtTop(this, false /* includingParents */);
+ getDisplay().mTaskContainers.positionStackAtTop(this, false /* includingParents */);
mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
MetricsLoggerWrapper.logPictureInPictureFullScreen(mAtmService.mContext,
@@ -3519,7 +3521,7 @@
// If there are other focusable stacks on the display, the z-order of the display should not
// be changed just because a task was placed at the bottom. E.g. if it is moving the topmost
// task to bottom, the next focusable stack on the same display should be focused.
- final ActivityStack nextFocusableStack = getDisplay().getNextFocusableStack(
+ final ActivityStack nextFocusableStack = getDisplay().mTaskContainers.getNextFocusableStack(
child.getStack(), true /* ignoreCurrent */);
positionChildAtBottom(child, nextFocusableStack == null /* includingParents */);
child.updateTaskMovement(true);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 4652f49..3f8fd73 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -414,14 +414,15 @@
if (mToDisplay.getDisplayId() != stack.getDisplayId()) {
mToDisplay.moveStackToDisplay(stack, mOnTop);
} else if (mOnTop) {
- mToDisplay.positionStackAtTop(stack, false /* includingParents */);
+ mToDisplay.mTaskContainers.positionStackAtTop(stack,
+ false /* includingParents */);
} else {
- mToDisplay.positionStackAtBottom(stack);
+ mToDisplay.mTaskContainers.positionStackAtBottom(stack);
}
return;
}
- final ActivityStack toStack = mToDisplay.getOrCreateStack(
+ final ActivityStack toStack = mToDisplay.mTaskContainers.getOrCreateStack(
null, mTmpOptions, task, task.getActivityType(), mOnTop);
if (task == toStack) {
// The task was reused as the root task.
@@ -1458,7 +1459,7 @@
|| (focusedStack != null && focusedStack.isActivityTypeRecents())) {
// We move home stack to front when we are on a fullscreen display and caller has
// requested the home activity to move with it. Or the previous stack is recents.
- display.moveHomeStackToFront(reason);
+ display.mTaskContainers.moveHomeStackToFront(reason);
}
}
@@ -1877,7 +1878,7 @@
mStoppingActivities.remove(r);
final ActivityStack stack = r.getRootTask();
- if (stack.getDisplay().allResumedActivitiesComplete()) {
+ if (stack.getDisplay().mTaskContainers.allResumedActivitiesComplete()) {
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
// Make sure activity & window visibility should be identical
// for all displays in this stage.
@@ -2241,7 +2242,7 @@
final boolean isSecondaryDisplayPreferred =
(preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
final boolean inSplitScreenMode = actualStack != null
- && actualStack.getDisplay().isSplitScreenModeActivated();
+ && actualStack.getDisplay().mTaskContainers.isSplitScreenModeActivated();
if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
&& !isSecondaryDisplayPreferred) || !task.isActivityTypeStandardOrUndefined()) {
return;
@@ -2289,12 +2290,12 @@
// Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
// we need to move it to top of fullscreen stack, otherwise it will be covered.
final DisplayContent display = task.getStack().getDisplay();
- if (display.isSplitScreenModeActivated()) {
+ if (display.mTaskContainers.isSplitScreenModeActivated()) {
// Display a warning toast that we tried to put an app that doesn't support
// split-screen in split-screen.
mService.getTaskChangeNotificationController()
.notifyActivityDismissingDockedStack();
- display.onSplitScreenModeDismissed();
+ display.mTaskContainers.onSplitScreenModeDismissed();
display.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
true /* notifyClients */);
}
@@ -2612,7 +2613,7 @@
// from whatever is started from the recents activity, so move the home stack
// forward.
// TODO (b/115289124): Multi-display supports for recents.
- mRootWindowContainer.getDefaultDisplay().moveHomeStackToFront(
+ mRootWindowContainer.getDefaultDisplay().mTaskContainers.moveHomeStackToFront(
"startActivityFromRecents");
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 881dc81..0a0049d 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -190,8 +190,8 @@
final ActivityStack homeStack;
try {
// Make sure home stack exist on display.
- homeStack = display.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME,
- ON_TOP);
+ homeStack = display.mTaskContainers.getOrCreateStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_HOME, ON_TOP);
} finally {
mSupervisor.endDeferResume();
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ce885ab..6921816 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2357,7 +2357,7 @@
}
// Convert some windowing-mode changes into root-task reparents for split-screen.
if (stack.inSplitScreenWindowingMode()) {
- stack.getDisplay().onSplitScreenModeDismissed();
+ stack.getDisplay().mTaskContainers.onSplitScreenModeDismissed();
} else {
stack.setWindowingMode(windowingMode);
@@ -2775,7 +2775,8 @@
}
if (toTop) {
- display.positionStackAt(POSITION_TOP, primarySplitTask, false /* includingParents */);
+ display.mTaskContainers.positionStackAt(POSITION_TOP, primarySplitTask,
+ false /* includingParents */);
}
WindowContainerTransaction wct = new WindowContainerTransaction();
wct.reparent(task.getStack().mRemoteToken, primarySplitTask.mRemoteToken, toTop);
@@ -3244,8 +3245,8 @@
}
final ActivityStack stack = r.getRootTask();
- final Task task = stack.getDisplay().createStack(stack.getWindowingMode(),
- stack.getActivityType(), !ON_TOP, ainfo, intent,
+ final Task task = stack.getDisplay().mTaskContainers.createStack(
+ stack.getWindowingMode(), stack.getActivityType(), !ON_TOP, ainfo, intent,
false /* createdByOrganizer */);
if (!mRecentTasks.addToBottom(task)) {
@@ -3308,10 +3309,10 @@
throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
}
if (bounds == null && stack.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
- stack = stack.getDisplay().getOrCreateStack(
+ stack = stack.getDisplay().mTaskContainers.getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP);
} else if (bounds != null && stack.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
- stack = stack.getDisplay().getOrCreateStack(
+ stack = stack.getDisplay().mTaskContainers.getOrCreateStack(
WINDOWING_MODE_FREEFORM, stack.getActivityType(), ON_TOP);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5900ae8..4a7edee 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -21,17 +21,12 @@
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.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
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_MULTI_WINDOW;
-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.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -83,10 +78,6 @@
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
@@ -111,7 +102,6 @@
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
-import static com.android.server.wm.RootWindowContainer.TAG_STATES;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.DISPLAY_CONTENT;
@@ -151,13 +141,9 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityOptions;
-import android.app.WindowConfiguration;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.ScreenOrientation;
-import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -212,7 +198,6 @@
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
-import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -285,7 +270,7 @@
/** The containers below are the only child containers {@link #mWindowContainers} can have. */
// Contains all window containers that are related to apps (Activities)
- private final TaskContainers mTaskContainers = new TaskContainers(this, mWmService);
+ final TaskContainers mTaskContainers = new TaskContainers(this, mWmService);
// Contains all IME window containers. Note that the z-ordering of the IME windows will depend
// on the IME target. We mainly have this container grouping so we can keep track of all the IME
@@ -452,8 +437,6 @@
private final Configuration mTmpConfiguration = new Configuration();
- private ArrayList<Task> mTmpTasks = new ArrayList<>();
-
/** Remove this display when animation on it has completed. */
private boolean mDeferredRemoval;
@@ -616,7 +599,7 @@
private boolean mRemoved;
/** The display can only contain one task. */
- private boolean mSingleTaskInstance;
+ boolean mSingleTaskInstance;
/**
* Non-null if the last size compatibility mode activity is using non-native screen
@@ -632,13 +615,6 @@
*/
private ActivityStack mPreferredTopFocusableStack;
- /**
- * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
- * stack has been resumed. If stacks are changing position this will hold the old stack until
- * the new stack becomes resumed after which it will be set to current focused stack.
- */
- private ActivityStack mLastFocusedStack;
-
// Used in updating the display size
private Point mTmpDisplaySize = new Point();
@@ -2095,30 +2071,11 @@
return mTaskContainers.getRootHomeTask();
}
- /**
- * Returns the existing home stack or creates and returns a new one if it should exist for the
- * display.
- */
- @Nullable
- ActivityStack getOrCreateRootHomeTask() {
- ActivityStack homeTask = getRootHomeTask();
- if (homeTask == null && supportsSystemDecorations() && !isUntrustedVirtualDisplay()) {
- homeTask = createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME,
- false /* onTop */);
- }
- return homeTask;
- }
-
/** @return The primary split-screen task, and {@code null} otherwise. */
@Nullable ActivityStack getRootSplitScreenPrimaryTask() {
return mTaskContainers.getRootSplitScreenPrimaryTask();
}
- boolean isSplitScreenModeActivated() {
- Task task = getRootSplitScreenPrimaryTask();
- return task != null && task.hasChild();
- }
-
ActivityStack getRootPinnedTask() {
return mTaskContainers.getRootPinnedTask();
}
@@ -2128,14 +2085,6 @@
}
/**
- * Returns the topmost stack on the display that is compatible with the input windowing mode.
- * Null is no compatible stack on the display.
- */
- ActivityStack getTopStackInWindowingMode(int windowingMode) {
- return getStack(windowingMode, ACTIVITY_TYPE_UNDEFINED);
- }
-
- /**
* Returns the topmost stack on the display that is compatible with the input windowing mode and
* activity type. Null is no compatible stack on the display.
*/
@@ -2511,11 +2460,6 @@
positionDisplayAt(position, includingParents);
}
- void positionStackAt(int position, ActivityStack child, boolean includingParents) {
- mTaskContainers.positionChildAt(position, child, includingParents);
- layoutAndAssignWindowLayersIfNeeded();
- }
-
/**
* Returns true if the input point is within an app window.
*/
@@ -2583,7 +2527,7 @@
}
amendWindowTapExcludeRegion(mTouchExcludeRegion);
// TODO(multi-display): Support docked stacks on secondary displays.
- if (mDisplayId == DEFAULT_DISPLAY && isSplitScreenModeActivated()) {
+ if (mDisplayId == DEFAULT_DISPLAY && mTaskContainers.isSplitScreenModeActivated()) {
mDividerControllerLocked.getTouchRegion(mTmpRect);
mTmpRegion.set(mTmpRect);
mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
@@ -2847,7 +2791,8 @@
final ActivityStack focusedStack = getFocusedStack();
if (focusedStack != null) {
proto.write(FOCUSED_ROOT_TASK_ID, focusedStack.getRootTaskId());
- final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
+ final ActivityRecord focusedActivity = focusedStack.getDisplay().mTaskContainers
+ .getResumedActivity();
if (focusedActivity != null) {
focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
}
@@ -2908,8 +2853,8 @@
if (mPreferredTopFocusableStack != null) {
pw.println(prefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
}
- if (mLastFocusedStack != null) {
- pw.println(prefix + "mLastFocusedStack=" + mLastFocusedStack);
+ if (mTaskContainers.mLastFocusedStack != null) {
+ pw.println(prefix + "mLastFocusedStack=" + mTaskContainers.mLastFocusedStack);
}
if (mLosingFocus.size() > 0) {
pw.println();
@@ -3025,7 +2970,7 @@
/** Returns true if the stack in the windowing mode is visible. */
boolean isStackVisible(int windowingMode) {
- final ActivityStack stack = getTopStackInWindowingMode(windowingMode);
+ final ActivityStack stack = mTaskContainers.getTopStackInWindowingMode(windowingMode);
return stack != null && stack.isVisible();
}
@@ -4430,7 +4375,8 @@
private boolean skipImeWindowsDuringTraversal(DisplayContent dc) {
// We skip IME windows so they're processed just above their target, except
// in split-screen mode where we process the IME containers above the docked divider.
- return dc.mInputMethodTarget != null && !dc.isSplitScreenModeActivated();
+ return dc.mInputMethodTarget != null
+ && !dc.mTaskContainers.isSplitScreenModeActivated();
}
/** Like {@link #forAllWindows}, but ignores {@link #skipImeWindowsDuringTraversal} */
@@ -5098,111 +5044,6 @@
mWmService.requestTraversal();
}
- void addStack(ActivityStack stack, int position) {
- setStackOnDisplay(stack, position);
- positionStackAt(stack, position);
- }
-
- void addStackReferenceIfNeeded(ActivityStack stack) {
- mTaskContainers.addStackReferenceIfNeeded(stack);
- }
-
- void removeStackReferenceIfNeeded(ActivityStack stack) {
- mTaskContainers.removeStackReferenceIfNeeded(stack);
- }
-
- void onStackRemoved(ActivityStack stack) {
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
- Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId=" + mDisplayId);
- }
- if (mPreferredTopFocusableStack == stack) {
- mPreferredTopFocusableStack = null;
- }
- releaseSelfIfNeeded();
- onStackOrderChanged(stack);
- }
-
- void positionStackAtTop(ActivityStack stack, boolean includingParents) {
- positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
- }
-
- void positionStackAtTop(ActivityStack stack, boolean includingParents,
- String updateLastFocusedStackReason) {
- positionStackAt(stack, getStackCount(), includingParents, updateLastFocusedStackReason);
- }
-
- void positionStackAtBottom(ActivityStack stack) {
- positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
- }
-
- void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
- positionStackAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason);
- }
-
- private void positionStackAt(ActivityStack stack, int position) {
- positionStackAt(stack, position, false /* includingParents */,
- null /* updateLastFocusedStackReason */);
- }
-
- private void positionStackAt(ActivityStack stack, int position, boolean includingParents,
- String updateLastFocusedStackReason) {
- // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
- // the position internally, also update the logic here
- final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
- ? getFocusedStack() : null;
- final boolean wasContained = getIndexOf(stack) >= 0;
- if (mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
- throw new IllegalStateException(
- "positionStackAt: Can only have one task on display=" + this);
- }
-
- final boolean movingToTop = wasContained && position >= getStackCount() - 1;
- // Reset mPreferredTopFocusableStack before positioning to top or {@link
- // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
- // resumed activity.
- if (movingToTop && stack.isFocusable()) {
- mPreferredTopFocusableStack = null;
- }
-
- // Since positionChildAt() is called during the creation process of pinned stacks,
- // ActivityStack#getStack() can be null.
- positionStackAt(position, stack, includingParents);
-
- // The insert position may be adjusted to non-top when there is always-on-top stack. Since
- // the original position is preferred to be top, the stack should have higher priority when
- // we are looking for top focusable stack. The condition {@code wasContained} restricts the
- // preferred stack is set only when moving an existing stack to top instead of adding a new
- // stack that may be too early (e.g. in the middle of launching or reparenting).
- if (movingToTop && stack.isFocusableAndVisible()) {
- mPreferredTopFocusableStack = stack;
- } else if (mPreferredTopFocusableStack == stack) {
- mPreferredTopFocusableStack = null;
- }
-
- if (updateLastFocusedStackReason != null) {
- final ActivityStack currentFocusedStack = getFocusedStack();
- if (currentFocusedStack != prevFocusedStack) {
- mLastFocusedStack = prevFocusedStack;
- EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser, mDisplayId,
- currentFocusedStack == null ? -1 : currentFocusedStack.getRootTaskId(),
- mLastFocusedStack == null ? -1 : mLastFocusedStack.getRootTaskId(),
- updateLastFocusedStackReason);
- }
- }
-
- onStackOrderChanged(stack);
- }
-
- ActivityStack getStack(int rootTaskId) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- if (stack.getRootTaskId() == rootTaskId) {
- return stack;
- }
- }
- return null;
- }
-
static boolean alwaysCreateStack(int windowingMode, int activityType) {
// Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
// modes so that we can manage visual ordering and return types correctly.
@@ -5213,358 +5054,13 @@
|| windowingMode == WINDOWING_MODE_MULTI_WINDOW);
}
- /**
- * Returns an existing stack compatible with the windowing mode and activity type or creates one
- * if a compatible stack doesn't exist.
- * @see #getOrCreateStack(int, int, boolean, Intent, Task, boolean)
- */
- ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop) {
- return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
- null /* candidateTask */, false /* createdByOrganizer */);
- }
-
- /**
- * When two level tasks are required for given windowing mode and activity type, returns an
- * existing compatible root task or creates a new one.
- * For one level task, the candidate task would be reused to also be the root task or create
- * a new root task if no candidate task.
- * @see #getStack(int, int)
- * @see #createStack(int, int, boolean)
- */
- ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop,
- Intent intent, Task candidateTask, boolean createdByOrganizer) {
- if (!alwaysCreateStack(windowingMode, activityType)) {
- ActivityStack stack = getStack(windowingMode, activityType);
- if (stack != null) {
- return stack;
- }
- } else if (candidateTask != null) {
- final ActivityStack stack = (ActivityStack) candidateTask;
- final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
- if (isSplitScreenModeActivated()) {
- final Task splitRootSecondary = getTask(t -> t.mCreatedByOrganizer && t.isRootTask()
- && t.inSplitScreenSecondaryWindowingMode());
- if (stack.getParent() == null) {
- splitRootSecondary.addChild(stack, position);
- } else if (stack.getParent() != splitRootSecondary) {
- stack.reparent(splitRootSecondary, position);
- }
- } else if (stack.getDisplay() != this || !stack.isRootTask()) {
- if (stack.getParent() == null) {
- addStack(stack, position);
- } else {
- stack.reparent(this, onTop);
- }
- }
- // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
- if (candidateTask.getWindowingMode() != windowingMode) {
- candidateTask.setWindowingMode(windowingMode);
- }
- return stack;
- }
- return createStack(windowingMode, activityType, onTop, null /*info*/, intent,
- createdByOrganizer);
- }
-
- /**
- * Returns an existing stack compatible with the input params or creates one
- * if a compatible stack doesn't exist.
- * @see #getOrCreateStack(int, int, boolean)
- */
- ActivityStack getOrCreateStack(@Nullable ActivityRecord r,
- @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
- boolean onTop) {
- // First preference is the windowing mode in the activity options if set.
- int windowingMode = (options != null)
- ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
- // Validate that our desired windowingMode will work under the current conditions.
- // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
- // it's display's windowing mode.
- windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
- return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
- candidateTask, false /* createdByOrganizer */);
- }
-
- @VisibleForTesting
- int getNextStackId() {
- return mAtmService.mStackSupervisor.getNextTaskIdForUser();
- }
-
ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
- return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */,
- false /* createdByOrganizer */);
+ return mTaskContainers.createStack(windowingMode, activityType, onTop, null /* info */,
+ null /* intent */, false /* createdByOrganizer */);
}
- /**
- * Creates a stack matching the input windowing mode and activity type on this display.
- * @param windowingMode The windowing mode the stack should be created in. If
- * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
- * inherit its parent's windowing mode.
- * @param activityType The activityType the stack should be created in. If
- * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
- * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
- * @param onTop If true the stack will be created at the top of the display, else at the bottom.
- * @param info The started activity info.
- * @param intent The intent that started this task.
- * @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
- * otherwise.
- * @return The newly created stack.
- */
- ActivityStack createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
- Intent intent, boolean createdByOrganizer) {
- if (mSingleTaskInstance && getStackCount() > 0) {
- // Create stack on default display instead since this display can only contain 1 stack.
- // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
- // this goes away once ActivityView is no longer using virtual displays.
- return mRootWindowContainer.getDefaultDisplay().createStack(
- windowingMode, activityType, onTop, info, intent, createdByOrganizer);
- }
-
- if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) {
- // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
- // anything else should be passing it in anyways...except for the task organizer.
- activityType = ACTIVITY_TYPE_STANDARD;
- }
-
- if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) {
- // For now there can be only one stack of a particular non-standard activity type on a
- // display. So, get that ignoring whatever windowing mode it is currently in.
- ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
- if (stack != null) {
- throw new IllegalArgumentException("Stack=" + stack + " of activityType="
- + activityType + " already on display=" + this + ". Can't have multiple.");
- }
- }
-
- if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
- mAtmService.mSupportsSplitScreenMultiWindow,
- mAtmService.mSupportsFreeformWindowManagement,
- mAtmService.mSupportsPictureInPicture, activityType)) {
- throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
- + windowingMode);
- }
-
- final int stackId = getNextStackId();
- return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
- createdByOrganizer);
- }
-
- /** @return the root task to create the next task in. */
- private Task updateLaunchRootTask(int windowingMode) {
- if (!isSplitScreenWindowingMode(windowingMode)) {
- // Only split-screen windowing modes can do this currently...
- return null;
- }
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final Task t = getStackAt(i);
- if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) {
- continue;
- }
- // If not already set, pick a launch root which is not the one we are launching into.
- if (mLaunchRootTask == null) {
- for (int j = 0, n = getStackCount(); j < n; ++j) {
- final Task tt = getStackAt(j);
- if (tt.mCreatedByOrganizer && tt != t) {
- mLaunchRootTask = tt;
- break;
- }
- }
- }
- return t;
- }
- return mLaunchRootTask;
- }
-
- @VisibleForTesting
- ActivityStack createStackUnchecked(int windowingMode, int activityType, int stackId,
- boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) {
- if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
- throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
- + "activity type.");
- }
- if (info == null) {
- info = new ActivityInfo();
- info.applicationInfo = new ApplicationInfo();
- }
-
- // Task created by organizer are added as root.
- Task launchRootTask = createdByOrganizer ? null : updateLaunchRootTask(windowingMode);
- if (launchRootTask != null) {
- // Since this stack will be put into a root task, its windowingMode will be inherited.
- windowingMode = WINDOWING_MODE_UNDEFINED;
- }
-
- final ActivityStack stack = (ActivityStack) Task.create(mAtmService, stackId, activityType,
- info, intent, createdByOrganizer);
- if (launchRootTask != null) {
- launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
- if (onTop) {
- positionStackAtTop((ActivityStack) launchRootTask, false /* includingParents */);
- }
- } else {
- addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
- stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
- false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
- true /* creating */);
- }
- return stack;
- }
-
- /**
- * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
- * focusable and visible stack from the top of stacks in this display.
- */
ActivityStack getFocusedStack() {
- if (mPreferredTopFocusableStack != null) {
- return mPreferredTopFocusableStack;
- }
-
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- if (stack.isFocusableAndVisible()) {
- return stack;
- }
- }
-
- return null;
- }
-
- ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
- final int currentWindowingMode = currentFocus != null
- ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
-
- ActivityStack candidate = null;
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- if (ignoreCurrent && stack == currentFocus) {
- continue;
- }
- if (!stack.isFocusableAndVisible()) {
- continue;
- }
-
- if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
- // If the currently focused stack is in split-screen secondary we save off the
- // top primary split-screen stack as a candidate for focus because we might
- // prefer focus to move to an other stack to avoid primary split-screen stack
- // overlapping with a fullscreen stack when a fullscreen stack is higher in z
- // than the next split-screen stack. Assistant stack, I am looking at you...
- // We only move the focus to the primary-split screen stack if there isn't a
- // better alternative.
- candidate = stack;
- continue;
- }
- if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
- // Use the candidate stack since we are now at the secondary split-screen.
- return candidate;
- }
- return stack;
- }
- return candidate;
- }
-
- ActivityRecord getResumedActivity() {
- final ActivityStack focusedStack = getFocusedStack();
- if (focusedStack == null) {
- return null;
- }
- // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
- // Check if the focused stack has the resumed activity
- ActivityRecord resumedActivity = focusedStack.getResumedActivity();
- if (resumedActivity == null || resumedActivity.app == null) {
- // If there is no registered resumed activity in the stack or it is not running -
- // try to use previously resumed one.
- resumedActivity = focusedStack.mPausingActivity;
- if (resumedActivity == null || resumedActivity.app == null) {
- // If previously resumed activity doesn't work either - find the topmost running
- // activity that can be focused.
- resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
- }
- }
- return resumedActivity;
- }
-
- ActivityStack getLastFocusedStack() {
- return mLastFocusedStack;
- }
-
- boolean allResumedActivitiesComplete() {
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
- if (r != null && !r.isState(RESUMED)) {
- return false;
- }
- }
- final ActivityStack currentFocusedStack = getFocusedStack();
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
- Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
- + mLastFocusedStack + " to=" + currentFocusedStack);
- }
- mLastFocusedStack = currentFocusedStack;
- return true;
- }
-
- /**
- * Pause all activities in either all of the stacks or just the back stacks. This is done before
- * resuming a new activity and to make sure that previously active activities are
- * paused in stacks that are no longer visible or in pinned windowing mode. This does not
- * pause activities in visible stacks, so if an activity is launched within the same stack/task,
- * then we should explicitly pause that stack's top activity.
- * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
- * @param resuming The resuming activity.
- * @return {@code true} if any activity was paused as a result of this call.
- */
- boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
- boolean someActivityPaused = false;
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = getStackAt(stackNdx);
- final ActivityRecord resumedActivity = stack.getResumedActivity();
- if (resumedActivity != null
- && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
- || !stack.isTopActivityFocusable())) {
- if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack
- + " mResumedActivity=" + resumedActivity);
- someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
- resuming);
- }
- }
- return someActivityPaused;
- }
-
- /**
- * Find task for putting the Activity in.
- */
- void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
- RootWindowContainer.FindTaskResult result) {
- mTmpFindTaskResult.clear();
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = getStackAt(stackNdx);
- if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
- if (DEBUG_TASKS) {
- Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
- }
- continue;
- }
-
- mTmpFindTaskResult.process(r, stack);
- // It is possible to have tasks in multiple stacks with the same root affinity, so
- // we should keep looking after finding an affinity match to see if there is a
- // better match in another stack. Also, task affinity isn't a good enough reason
- // to target a display which isn't the source of the intent, so skip any affinity
- // matches not on the specified display.
- if (mTmpFindTaskResult.mRecord != null) {
- if (mTmpFindTaskResult.mIdealMatch) {
- result.setTo(mTmpFindTaskResult);
- return;
- } else if (isPreferredDisplay) {
- // Note: since the traversing through the stacks is top down, the floating
- // tasks should always have lower priority than any affinity-matching tasks
- // in the fullscreen stacks
- result.setTo(mTmpFindTaskResult);
- }
- }
- }
+ return mTaskContainers.getFocusedStack();
}
/**
@@ -5572,249 +5068,11 @@
* ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
*/
void removeStacksInWindowingModes(int... windowingModes) {
- if (windowingModes == null || windowingModes.length == 0) {
- return;
- }
-
- // Collect the stacks that are necessary to be removed instead of performing the removal
- // by looping mStacks, so that we don't miss any stacks after the stack size changed or
- // stacks reordered.
- final ArrayList<ActivityStack> stacks = new ArrayList<>();
- for (int j = windowingModes.length - 1; j >= 0; --j) {
- final int windowingMode = windowingModes[j];
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- if (!stack.isActivityTypeStandardOrUndefined()) {
- continue;
- }
- if (stack.getWindowingMode() != windowingMode) {
- continue;
- }
- stacks.add(stack);
- }
- }
-
- for (int i = stacks.size() - 1; i >= 0; --i) {
- mRootWindowContainer.mStackSupervisor.removeStack(stacks.get(i));
- }
+ mTaskContainers.removeStacksInWindowingModes(windowingModes);
}
void removeStacksWithActivityTypes(int... activityTypes) {
- if (activityTypes == null || activityTypes.length == 0) {
- return;
- }
-
- // Collect the stacks that are necessary to be removed instead of performing the removal
- // by looping mStacks, so that we don't miss any stacks after the stack size changed or
- // stacks reordered.
- final ArrayList<ActivityStack> stacks = new ArrayList<>();
- for (int j = activityTypes.length - 1; j >= 0; --j) {
- final int activityType = activityTypes[j];
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- // Collect the root tasks that are currently being organized.
- if (stack.isOrganized()) {
- for (int k = stack.getChildCount() - 1; k >= 0; --k) {
- final ActivityStack childStack = (ActivityStack) stack.getChildAt(k);
- if (childStack.getActivityType() == activityType) {
- stacks.add(childStack);
- }
- }
- } else if (stack.getActivityType() == activityType) {
- stacks.add(stack);
- }
- }
- }
-
- for (int i = stacks.size() - 1; i >= 0; --i) {
- mRootWindowContainer.mStackSupervisor.removeStack(stacks.get(i));
- }
- }
-
- void onSplitScreenModeDismissed() {
- mAtmService.deferWindowLayout();
- try {
- mLaunchRootTask = null;
- moveSplitScreenTasksToFullScreen();
- } finally {
- final ActivityStack topFullscreenStack =
- getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
- final ActivityStack homeStack = getOrCreateRootHomeTask();
- if (topFullscreenStack != null && homeStack != null && !isTopStack(homeStack)) {
- // Whenever split-screen is dismissed we want the home stack directly behind the
- // current top fullscreen stack so it shows up when the top stack is finished.
- // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
- // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
- // once we have that.
- homeStack.moveToFront("onSplitScreenModeDismissed");
- topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
- }
- mAtmService.continueWindowLayout();
- }
- }
-
- private void moveSplitScreenTasksToFullScreen() {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- mTmpTasks.clear();
- forAllTasks(task -> {
- if (task.mCreatedByOrganizer && task.inSplitScreenWindowingMode() && task.hasChild()) {
- mTmpTasks.add(task);
- }
- });
-
- for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
- final Task root = mTmpTasks.get(i);
- for (int j = 0; j < root.getChildCount(); j++) {
- wct.reparent(root.getChildAt(j).mRemoteToken, null, true /* toTop */);
- }
- }
- mAtmService.mWindowOrganizerController.applyTransaction(wct);
- }
-
- /**
- * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
- * @param windowingMode The windowing mode we are checking support for.
- * @param supportsMultiWindow If we should consider support for multi-window mode in general.
- * @param supportsSplitScreen If we should consider support for split-screen multi-window.
- * @param supportsFreeform If we should consider support for freeform multi-window.
- * @param supportsPip If we should consider support for picture-in-picture mutli-window.
- * @param activityType The activity type under consideration.
- * @return true if the windowing mode is supported.
- */
- private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
- boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
- int activityType) {
-
- if (windowingMode == WINDOWING_MODE_UNDEFINED
- || windowingMode == WINDOWING_MODE_FULLSCREEN) {
- return true;
- }
- if (!supportsMultiWindow) {
- return false;
- }
-
- if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
- return true;
- }
-
- final int displayWindowingMode = getWindowingMode();
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- return supportsSplitScreen
- && WindowConfiguration.supportSplitScreenWindowingMode(activityType)
- // Freeform windows and split-screen windows don't mix well, so prevent
- // split windowing modes on freeform displays.
- && displayWindowingMode != WINDOWING_MODE_FREEFORM;
- }
-
- if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
- return false;
- }
-
- if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
- return false;
- }
- return true;
- }
-
- /**
- * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
- * display with the provided parameters.
- *
- * @param r The ActivityRecord in question.
- * @param options Options to start with.
- * @param task The task within-which the activity would start.
- * @param activityType The type of activity to start.
- * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
- */
- int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
- @Nullable Task task, int activityType) {
-
- // First preference if the windowing mode in the activity options if set.
- int windowingMode = (options != null)
- ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
-
- // If windowing mode is unset, then next preference is the candidate task, then the
- // activity record.
- if (windowingMode == WINDOWING_MODE_UNDEFINED) {
- if (task != null) {
- windowingMode = task.getWindowingMode();
- }
- if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
- windowingMode = r.getWindowingMode();
- }
- if (windowingMode == WINDOWING_MODE_UNDEFINED) {
- // Use the display's windowing mode.
- windowingMode = getWindowingMode();
- }
- }
- windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
- return windowingMode != WINDOWING_MODE_UNDEFINED
- ? windowingMode : WINDOWING_MODE_FULLSCREEN;
- }
-
- /**
- * Check that the requested windowing-mode is appropriate for the specified task and/or activity
- * on this display.
- *
- * @param windowingMode The windowing-mode to validate.
- * @param r The {@link ActivityRecord} to check against.
- * @param task The {@link Task} to check against.
- * @param activityType An activity type.
- * @return The provided windowingMode or the closest valid mode which is appropriate.
- */
- int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
- int activityType) {
- // Make sure the windowing mode we are trying to use makes sense for what is supported.
- boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
- boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
- boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
- boolean supportsPip = mAtmService.mSupportsPictureInPicture;
- if (supportsMultiWindow) {
- if (task != null) {
- supportsMultiWindow = task.isResizeable();
- supportsSplitScreen = task.supportsSplitScreenWindowingMode();
- // TODO: Do we need to check for freeform and Pip support here?
- } else if (r != null) {
- supportsMultiWindow = r.isResizeable();
- supportsSplitScreen = r.supportsSplitScreenWindowingMode();
- supportsFreeform = r.supportsFreeform();
- supportsPip = r.supportsPictureInPicture();
- }
- }
-
- final boolean inSplitScreenMode = isSplitScreenModeActivated();
- if (!inSplitScreenMode
- && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
- // Switch to the display's windowing mode if we are not in split-screen mode and we are
- // trying to launch in split-screen secondary.
- windowingMode = WINDOWING_MODE_UNDEFINED;
- } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
- || windowingMode == WINDOWING_MODE_UNDEFINED)
- && supportsSplitScreen) {
- windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- }
-
- if (windowingMode != WINDOWING_MODE_UNDEFINED
- && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
- supportsFreeform, supportsPip, activityType)) {
- return windowingMode;
- }
- return WINDOWING_MODE_UNDEFINED;
- }
-
- boolean isTopStack(ActivityStack stack) {
- return stack == getTopStack();
- }
-
- boolean isTopNotPinnedStack(ActivityStack stack) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack current = getStackAt(i);
- if (!current.inPinnedWindowingMode()) {
- return current == stack;
- }
- }
- return false;
+ mTaskContainers.removeStacksWithActivityTypes(activityTypes);
}
ActivityRecord topRunningActivity() {
@@ -5831,37 +5089,7 @@
* @return The top running activity. {@code null} if none is available.
*/
ActivityRecord topRunningActivity(boolean considerKeyguardState) {
- ActivityRecord topRunning = null;
- final ActivityStack focusedStack = getFocusedStack();
- if (focusedStack != null) {
- topRunning = focusedStack.topRunningActivity();
- }
-
- // Look in other focusable stacks.
- if (topRunning == null) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getStackAt(i);
- // Only consider focusable stacks other than the current focused one.
- if (stack == focusedStack || !stack.isTopActivityFocusable()) {
- continue;
- }
- topRunning = stack.topRunningActivity();
- if (topRunning != null) {
- break;
- }
- }
- }
-
- // This activity can be considered the top running activity if we are not considering
- // the locked state, the keyguard isn't locked, or we can show when locked.
- if (topRunning != null && considerKeyguardState
- && mRootWindowContainer.mStackSupervisor.getKeyguardController()
- .isKeyguardLocked()
- && !topRunning.canShowWhenLocked()) {
- return null;
- }
-
- return topRunning;
+ return mTaskContainers.topRunningActivity(considerKeyguardState);
}
boolean updateDisplayOverrideConfigurationLocked() {
@@ -6034,7 +5262,7 @@
// If default display is in split-window mode, set windowing mode of the stack
// to split-screen secondary. Otherwise, set the windowing mode to undefined by
// default to let stack inherited the windowing mode from the new display.
- final int windowingMode = toDisplay.isSplitScreenModeActivated()
+ final int windowingMode = toDisplay.mTaskContainers.isSplitScreenModeActivated()
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_UNDEFINED;
stack.reparent(toDisplay, true /* onTop */);
@@ -6066,7 +5294,7 @@
}
}
- private void releaseSelfIfNeeded() {
+ void releaseSelfIfNeeded() {
if (!mRemoved) {
return;
}
@@ -6143,80 +5371,6 @@
return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null;
}
- /**
- * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
- * Generally used in conjunction with {@link #moveStackBehindStack}.
- */
- // TODO(b/151575894): Remove special stack movement methods.
- void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
- if (stack.shouldBeVisible(null)) {
- // Skip if the stack is already visible
- return;
- }
-
- final boolean isRootTask = stack.isRootTask();
- if (isRootTask) {
- // Move the stack to the bottom to not affect the following visibility checks
- positionStackAtBottom(stack);
- } else {
- stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */);
- }
-
- // Find the next position where the stack should be placed
- final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount();
- for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final ActivityStack s = isRootTask ? getStackAt(stackNdx)
- : (ActivityStack) stack.getParent().getChildAt(stackNdx);
- if (s == stack) {
- continue;
- }
- final int winMode = s.getWindowingMode();
- final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
- || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- if (s.shouldBeVisible(null) && isValidWindowingMode) {
- // Move the provided stack to behind this stack
- final int position = Math.max(0, stackNdx - 1);
- if (isRootTask) {
- positionStackAt(stack, position);
- } else {
- stack.getParent().positionChildAt(position, stack, false /*includingParents */);
- }
- break;
- }
- }
- }
-
- /**
- * Moves the {@param stack} behind the given {@param behindStack} if possible. If
- * {@param behindStack} is not currently in the display, then then the stack is moved to the
- * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
- */
- void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
- if (behindStack == null || behindStack == stack) {
- return;
- }
-
- final WindowContainer parent = stack.getParent();
- if (parent == null || parent != behindStack.getParent()) {
- return;
- }
-
- // Note that positionChildAt will first remove the given stack before inserting into the
- // list, so we need to adjust the insertion index to account for the removed index
- // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
- // position internally
- final int stackIndex = parent.mChildren.indexOf(stack);
- final int behindStackIndex = parent.mChildren.indexOf(behindStack);
- final int insertIndex = stackIndex <= behindStackIndex
- ? behindStackIndex - 1 : behindStackIndex;
- final int position = Math.max(0, insertIndex);
- if (stack.isRootTask()) {
- positionStackAt(stack, position);
- } else {
- parent.positionChildAt(position, stack, false /* includingParents */);
- }
- }
-
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
@@ -6226,50 +5380,6 @@
}
}
- void moveHomeStackToFront(String reason) {
- final ActivityStack homeStack = getOrCreateRootHomeTask();
- if (homeStack != null) {
- homeStack.moveToFront(reason);
- }
- }
-
- /**
- * Moves the focusable home activity to top. If there is no such activity, the home stack will
- * still move to top.
- */
- void moveHomeActivityToTop(String reason) {
- final ActivityRecord top = getHomeActivity();
- if (top == null) {
- moveHomeStackToFront(reason);
- return;
- }
- top.moveFocusableActivityToTop(reason);
- }
-
- @Nullable
- ActivityRecord getHomeActivity() {
- return getHomeActivityForUser(mRootWindowContainer.mCurrentUser);
- }
-
- @Nullable
- ActivityRecord getHomeActivityForUser(int userId) {
- final ActivityStack homeStack = getRootHomeTask();
- if (homeStack == null) {
- return null;
- }
-
- final PooledPredicate p = PooledLambda.obtainPredicate(
- DisplayContent::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
- userId);
- final ActivityRecord r = homeStack.getActivity(p);
- p.recycle();
- return r;
- }
-
- private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
- return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
- }
-
boolean isSleeping() {
return mSleeping;
}
@@ -6300,7 +5410,7 @@
* Notifies of a stack order change
* @param stack The stack which triggered the order change
*/
- private void onStackOrderChanged(ActivityStack stack) {
+ void onStackOrderChanged(ActivityStack stack) {
for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 6b39fd2..c10b8a5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -407,10 +407,10 @@
// stack since it will be complicated/risky to try to put the activity on top
// of the lock screen in the right fullscreen configuration.
final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- if (!display.isSplitScreenModeActivated()) {
+ if (!display.mTaskContainers.isSplitScreenModeActivated()) {
return;
}
- display.onSplitScreenModeDismissed();
+ display.mTaskContainers.onSplitScreenModeDismissed();
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 057592c..26b263e 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -208,7 +208,7 @@
try {
if (hasExistingActivity) {
// Move the recents activity into place for the animation if it is not top most
- mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack);
+ mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(targetStack);
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
targetStack, mDefaultDisplay.getStackAbove(targetStack));
@@ -227,7 +227,7 @@
targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
mTargetActivityType);
targetActivity = getTargetActivity(targetStack);
- mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack);
+ mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(targetStack);
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
targetStack, mDefaultDisplay.getStackAbove(targetStack));
@@ -352,7 +352,8 @@
} else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){
// Restore the target stack to its previous position
final DisplayContent display = targetActivity.getDisplay();
- display.moveStackBehindStack(targetStack, mRestoreTargetBehindStack);
+ display.mTaskContainers.moveStackBehindStack(targetStack,
+ mRestoreTargetBehindStack);
if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) {
final ActivityStack aboveTargetStack =
mDefaultDisplay.getStackAbove(targetStack);
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 420997a..770c088 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -257,8 +257,8 @@
}
if (targetTask == null) {
if (alwaysCreateTask) {
- targetTask = display.getOrCreateStack(windowingMode, activityType,
- false /* onTop */);
+ targetTask = display.mTaskContainers.getOrCreateStack(windowingMode,
+ activityType, false /* onTop */);
} else {
targetTask = mTargetStack.reuseOrCreateTask(r.info, null /*intent*/,
false /*toTop*/);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 76c16d4..3427035 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1371,7 +1371,8 @@
final DisplayContent defaultDisplay = getDefaultDisplay();
- defaultDisplay.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ defaultDisplay.mTaskContainers.getOrCreateStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_HOME, ON_TOP);
positionChildAt(POSITION_TOP, defaultDisplay, false /* includingParents */);
}
@@ -1440,7 +1441,7 @@
}
ActivityRecord getDefaultDisplayHomeActivityForUser(int userId) {
- return getDisplayContent(DEFAULT_DISPLAY).getHomeActivityForUser(userId);
+ return getDisplayContent(DEFAULT_DISPLAY).mTaskContainers.getHomeActivityForUser(userId);
}
boolean startHomeOnAllDisplays(int userId, String reason) {
@@ -1636,7 +1637,7 @@
displayId = DEFAULT_DISPLAY;
}
- final ActivityRecord r = getDisplayContent(displayId).getHomeActivity();
+ final ActivityRecord r = getDisplayContent(displayId).mTaskContainers.getHomeActivity();
final String myReason = reason + " resumeHomeActivity";
// Only resume home activity if isn't finishing.
@@ -1837,7 +1838,8 @@
// focus order.
for (int i = getChildCount() - 1; i >= 0; --i) {
final DisplayContent display = getChildAt(i);
- final ActivityRecord resumedActivityOnDisplay = display.getResumedActivity();
+ final ActivityRecord resumedActivityOnDisplay = display.mTaskContainers
+ .getResumedActivity();
if (resumedActivityOnDisplay != null) {
return resumedActivityOnDisplay;
}
@@ -1970,8 +1972,8 @@
final int focusStackId = topFocusedStack != null
? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
// We dismiss the docked stack whenever we switch users.
- if (getDefaultDisplay().isSplitScreenModeActivated()) {
- getDefaultDisplay().onSplitScreenModeDismissed();
+ if (getDefaultDisplay().mTaskContainers.isSplitScreenModeActivated()) {
+ getDefaultDisplay().mTaskContainers.onSplitScreenModeDismissed();
}
// Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will
// also cause all tasks to be moved to the fullscreen stack at a position that is
@@ -1993,7 +1995,7 @@
final int restoreStackId = mUserStackInFront.get(userId);
ActivityStack stack = getStack(restoreStackId);
if (stack == null) {
- stack = getDefaultDisplay().getOrCreateRootHomeTask();
+ stack = getDefaultDisplay().mTaskContainers.getOrCreateRootHomeTask();
}
final boolean homeInFront = stack.isActivityTypeHome();
if (stack.isOnHomeDisplay()) {
@@ -2016,7 +2018,7 @@
void updateUserStack(int userId, ActivityStack stack) {
if (userId != mCurrentUser) {
if (stack == null) {
- stack = getDefaultDisplay().getOrCreateRootHomeTask();
+ stack = getDefaultDisplay().mTaskContainers.getOrCreateRootHomeTask();
}
mUserStackInFront.put(userId, stack.getRootTaskId());
@@ -2113,8 +2115,9 @@
} else {
// In the case of multiple activities, we will create a new task for it and then
// move the PIP activity into the task.
- stack = display.createStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP,
- r.info, r.intent, false /* createdByOrganizer */);
+ stack = display.mTaskContainers.createStack(WINDOWING_MODE_PINNED,
+ r.getActivityType(), ON_TOP, r.info, r.intent,
+ false /* createdByOrganizer */);
// There are multiple activities in the task and moving the top activity should
// reveal/leave the other activities in their original task.
@@ -2153,7 +2156,8 @@
// Looking up task on preferred display first
final DisplayContent preferredDisplay = getDisplayContent(preferredDisplayId);
if (preferredDisplay != null) {
- preferredDisplay.findTaskLocked(r, true /* isPreferredDisplay */, mTmpFindTaskResult);
+ preferredDisplay.mTaskContainers.findTaskLocked(r, true /* isPreferredDisplay */,
+ mTmpFindTaskResult);
if (mTmpFindTaskResult.mIdealMatch) {
return mTmpFindTaskResult.mRecord;
}
@@ -2165,7 +2169,8 @@
continue;
}
- display.findTaskLocked(r, false /* isPreferredDisplay */, mTmpFindTaskResult);
+ display.mTaskContainers.findTaskLocked(r, false /* isPreferredDisplay */,
+ mTmpFindTaskResult);
if (mTmpFindTaskResult.mIdealMatch) {
return mTmpFindTaskResult.mRecord;
}
@@ -2232,7 +2237,8 @@
resumedOnDisplay |= result;
continue;
}
- if (display.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
+ if (display.mTaskContainers.isTopStack(stack)
+ && topRunningActivity.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation,
// but only consider the top task and stack on that display.
stack.executeAppTransition(targetOptions);
@@ -2307,7 +2313,7 @@
protected ActivityStack getStack(int stackId) {
for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getChildAt(i).getStack(stackId);
+ final ActivityStack stack = getChildAt(i).mTaskContainers.getStack(stackId);
if (stack != null) {
return stack;
}
@@ -2783,7 +2789,8 @@
}
final DisplayContent display = getDisplayContentOrCreate(displayId);
if (display != null) {
- stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
+ stack = display.mTaskContainers.getOrCreateStack(r, options, candidateTask,
+ activityType, onTop);
if (stack != null) {
return stack;
}
@@ -2805,8 +2812,8 @@
display = stack.getDisplay();
if (display != null && canLaunchOnDisplay(r, display.mDisplayId)) {
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- windowingMode = display.resolveWindowingMode(r, options, candidateTask,
- activityType);
+ windowingMode = display.mTaskContainers.resolveWindowingMode(r, options,
+ candidateTask, activityType);
}
// Always allow organized tasks that created by organizer since the activity type
// of an organized task is decided by the activity type of its top child, which
@@ -2830,12 +2837,13 @@
if (display == null || !canLaunchOnDisplay(r, display.mDisplayId)) {
display = getDefaultDisplay();
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- windowingMode = display.resolveWindowingMode(r, options, candidateTask,
- activityType);
+ windowingMode = display.mTaskContainers.resolveWindowingMode(r, options,
+ candidateTask, activityType);
}
}
- return display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
+ return display.mTaskContainers.getOrCreateStack(r, options, candidateTask, activityType,
+ onTop);
}
/** @return true if activity record is null or can be launched on provided display. */
@@ -2895,8 +2903,8 @@
windowingMode = options != null ? options.getLaunchWindowingMode()
: r.getWindowingMode();
}
- windowingMode = displayContent.validateWindowingMode(windowingMode, r, candidateTask,
- r.getActivityType());
+ windowingMode = displayContent.mTaskContainers.validateWindowingMode(windowingMode, r,
+ candidateTask, r.getActivityType());
// Return the topmost valid stack on the display.
for (int i = displayContent.getStackCount() - 1; i >= 0; --i) {
@@ -2984,8 +2992,8 @@
// was on.
preferredDisplay = getDisplayContent(currentFocus.mPrevDisplayId);
}
- final ActivityStack preferredFocusableStack = preferredDisplay.getNextFocusableStack(
- currentFocus, ignoreCurrent);
+ final ActivityStack preferredFocusableStack = preferredDisplay.mTaskContainers
+ .getNextFocusableStack(currentFocus, ignoreCurrent);
if (preferredFocusableStack != null) {
return preferredFocusableStack;
}
@@ -3003,8 +3011,8 @@
// We've already checked this one
continue;
}
- final ActivityStack nextFocusableStack = display.getNextFocusableStack(currentFocus,
- ignoreCurrent);
+ final ActivityStack nextFocusableStack = display.mTaskContainers
+ .getNextFocusableStack(currentFocus, ignoreCurrent);
if (nextFocusableStack != null) {
return nextFocusableStack;
}
@@ -3416,7 +3424,8 @@
boolean allFocusedProcessesDiffer = true;
for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) {
final DisplayContent displayContent = getChildAt(displayNdx);
- final ActivityRecord resumedActivity = displayContent.getResumedActivity();
+ final ActivityRecord resumedActivity = displayContent.mTaskContainers
+ .getResumedActivity();
final WindowProcessController resumedActivityProcess =
resumedActivity == null ? null : resumedActivity.app;
@@ -3517,8 +3526,8 @@
printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
needSep = printed;
}
- printThisActivity(pw, displayContent.getResumedActivity(), dumpPackage, needSep,
- " ResumedActivity:");
+ printThisActivity(pw, displayContent.mTaskContainers.getResumedActivity(), dumpPackage,
+ needSep, " ResumedActivity:");
}
printed |= dumpHistoryList(fd, pw, mStackSupervisor.mFinishingActivities, " ",
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 91b4ec9..10be11a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1386,7 +1386,7 @@
// A rootable task that is now being added to be the child of an organized task. Making
// sure the stack references is keep updated.
if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
- mDisplayContent.addStackReferenceIfNeeded((ActivityStack) child);
+ mDisplayContent.mTaskContainers.addStackReferenceIfNeeded((ActivityStack) child);
}
// Make sure the list of display UID whitelists is updated
@@ -1432,7 +1432,7 @@
// A rootable child task that is now being removed from an organized task. Making sure
// the stack references is keep updated.
if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
- mDisplayContent.removeStackReferenceIfNeeded((ActivityStack) child);
+ mDisplayContent.mTaskContainers.removeStackReferenceIfNeeded((ActivityStack) child);
}
removeChild(child, "removeChild");
}
diff --git a/services/core/java/com/android/server/wm/TaskContainers.java b/services/core/java/com/android/server/wm/TaskContainers.java
index a959942..540bc9b 100644
--- a/services/core/java/com/android/server/wm/TaskContainers.java
+++ b/services/core/java/com/android/server/wm/TaskContainers.java
@@ -17,23 +17,49 @@
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.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+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_MULTI_WINDOW;
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.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.window.WindowOrganizer.DisplayAreaOrganizer.FEATURE_TASK_CONTAINER;
+import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
+import static com.android.server.wm.DisplayContent.alwaysCreateStack;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.RootWindowContainer.TAG_STATES;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.os.UserHandle;
import android.util.Slog;
import android.view.SurfaceControl;
+import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.protolog.common.ProtoLog;
import java.util.ArrayList;
@@ -76,9 +102,37 @@
private final ArrayList<ActivityStack> mTmpNormalStacks = new ArrayList<>();
private final ArrayList<ActivityStack> mTmpHomeStacks = new ArrayList<>();
+ private ArrayList<Task> mTmpTasks = new ArrayList<>();
+
+ private ActivityTaskManagerService mAtmService;
+
+ private RootWindowContainer mRootWindowContainer;
+
+ // When non-null, new tasks get put into this root task.
+ private Task mLaunchRootTask = null;
+
+ /**
+ * A focusable stack that is purposely to be positioned at the top. Although the stack may not
+ * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
+ * target stack properly when there are other focusable always-on-top stacks.
+ */
+ private ActivityStack mPreferredTopFocusableStack;
+
+ private final RootWindowContainer.FindTaskResult
+ mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
+
+ /**
+ * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
+ * stack has been resumed. If stacks are changing position this will hold the old stack until
+ * the new stack becomes resumed after which it will be set to current focused stack.
+ */
+ ActivityStack mLastFocusedStack;
+
TaskContainers(DisplayContent displayContent, WindowManagerService service) {
super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER);
mDisplayContent = displayContent;
+ mRootWindowContainer = service.mRoot;
+ mAtmService = service.mAtmService;
}
/**
@@ -201,7 +255,7 @@
position = findPositionForStack(position, stack, true /* adding */);
super.addChild(stack, position);
- mDisplayContent.mAtmService.updateSleepIfNeededLocked();
+ mAtmService.updateSleepIfNeededLocked();
// The reparenting case is handled in WindowContainer.
if (!stack.mReparenting) {
@@ -212,8 +266,8 @@
@Override
protected void removeChild(ActivityStack stack) {
super.removeChild(stack);
- mDisplayContent.onStackRemoved(stack);
- mDisplayContent.mAtmService.updateSleepIfNeededLocked();
+ onStackRemoved(stack);
+ mAtmService.updateSleepIfNeededLocked();
removeStackReferenceIfNeeded(stack);
}
@@ -567,4 +621,913 @@
mSplitScreenDividerAnchor = null;
}
}
+
+ void addStack(ActivityStack stack, int position) {
+ mDisplayContent.setStackOnDisplay(stack, position);
+ positionStackAt(stack, position);
+ }
+
+ void onStackRemoved(ActivityStack stack) {
+ if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
+ Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId="
+ + mDisplayContent.mDisplayId);
+ }
+ if (mPreferredTopFocusableStack == stack) {
+ mPreferredTopFocusableStack = null;
+ }
+ mDisplayContent.releaseSelfIfNeeded();
+ mDisplayContent.onStackOrderChanged(stack);
+ }
+
+ void positionStackAt(int position, ActivityStack child, boolean includingParents) {
+ positionChildAt(position, child, includingParents);
+ mDisplayContent.layoutAndAssignWindowLayersIfNeeded();
+ }
+
+ void positionStackAtTop(ActivityStack stack, boolean includingParents) {
+ positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
+ }
+
+ void positionStackAtTop(ActivityStack stack, boolean includingParents,
+ String updateLastFocusedStackReason) {
+ positionStackAt(stack, getStackCount(), includingParents,
+ updateLastFocusedStackReason);
+ }
+
+ void positionStackAtBottom(ActivityStack stack) {
+ positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
+ }
+
+ void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
+ positionStackAt(stack, 0, false /* includingParents */,
+ updateLastFocusedStackReason);
+ }
+
+ void positionStackAt(ActivityStack stack, int position) {
+ positionStackAt(stack, position, false /* includingParents */,
+ null /* updateLastFocusedStackReason */);
+ }
+
+ void positionStackAt(ActivityStack stack, int position, boolean includingParents,
+ String updateLastFocusedStackReason) {
+ // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
+ // the position internally, also update the logic here
+ final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
+ ? getFocusedStack() : null;
+ final boolean wasContained = getIndexOf(stack) >= 0;
+ if (mDisplayContent.mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
+ throw new IllegalStateException(
+ "positionStackAt: Can only have one task on display=" + this);
+ }
+
+ final boolean movingToTop = wasContained && position >= getStackCount() - 1;
+ // Reset mPreferredTopFocusableStack before positioning to top or {@link
+ // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
+ // resumed activity.
+ if (movingToTop && stack.isFocusable()) {
+ mPreferredTopFocusableStack = null;
+ }
+
+ // Since positionChildAt() is called during the creation process of pinned stacks,
+ // ActivityStack#getStack() can be null.
+ positionStackAt(position, stack, includingParents);
+
+ // The insert position may be adjusted to non-top when there is always-on-top stack. Since
+ // the original position is preferred to be top, the stack should have higher priority when
+ // we are looking for top focusable stack. The condition {@code wasContained} restricts the
+ // preferred stack is set only when moving an existing stack to top instead of adding a new
+ // stack that may be too early (e.g. in the middle of launching or reparenting).
+ if (movingToTop && stack.isFocusableAndVisible()) {
+ mPreferredTopFocusableStack = stack;
+ } else if (mPreferredTopFocusableStack == stack) {
+ mPreferredTopFocusableStack = null;
+ }
+
+ if (updateLastFocusedStackReason != null) {
+ final ActivityStack currentFocusedStack = getFocusedStack();
+ if (currentFocusedStack != prevFocusedStack) {
+ mLastFocusedStack = prevFocusedStack;
+ EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser,
+ mDisplayContent.mDisplayId,
+ currentFocusedStack == null ? -1 : currentFocusedStack.getRootTaskId(),
+ mLastFocusedStack == null ? -1 : mLastFocusedStack.getRootTaskId(),
+ updateLastFocusedStackReason);
+ }
+ }
+
+ mDisplayContent.onStackOrderChanged(stack);
+ }
+
+ ActivityStack getStack(int rootTaskId) {
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ if (stack.getRootTaskId() == rootTaskId) {
+ return stack;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns an existing stack compatible with the windowing mode and activity type or creates one
+ * if a compatible stack doesn't exist.
+ * @see #getOrCreateStack(int, int, boolean, Intent, Task, boolean)
+ */
+ ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop) {
+ return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
+ null /* candidateTask */, false /* createdByOrganizer */);
+ }
+
+ /**
+ * When two level tasks are required for given windowing mode and activity type, returns an
+ * existing compatible root task or creates a new one.
+ * For one level task, the candidate task would be reused to also be the root task or create
+ * a new root task if no candidate task.
+ * @see #getStack(int, int)
+ * @see #createStack(int, int, boolean)
+ */
+ ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop,
+ Intent intent, Task candidateTask, boolean createdByOrganizer) {
+ if (!alwaysCreateStack(windowingMode, activityType)) {
+ ActivityStack stack = getStack(windowingMode, activityType);
+ if (stack != null) {
+ return stack;
+ }
+ } else if (candidateTask != null) {
+ final ActivityStack stack = (ActivityStack) candidateTask;
+ final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
+ if (isSplitScreenModeActivated()) {
+ final Task splitRootSecondary = getTask(t -> t.mCreatedByOrganizer && t.isRootTask()
+ && t.inSplitScreenSecondaryWindowingMode());
+ if (stack.getParent() == null) {
+ splitRootSecondary.addChild(stack, position);
+ } else if (stack.getParent() != splitRootSecondary) {
+ stack.reparent(splitRootSecondary, position);
+ }
+ } else if (stack.getDisplay() != mDisplayContent || !stack.isRootTask()) {
+ if (stack.getParent() == null) {
+ addStack(stack, position);
+ } else {
+ stack.reparent(mDisplayContent, onTop);
+ }
+ }
+ // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
+ if (candidateTask.getWindowingMode() != windowingMode) {
+ candidateTask.setWindowingMode(windowingMode);
+ }
+ return stack;
+ }
+ return createStack(windowingMode, activityType, onTop, null /*info*/, intent,
+ createdByOrganizer);
+ }
+
+ /**
+ * Returns an existing stack compatible with the input params or creates one
+ * if a compatible stack doesn't exist.
+ * @see #getOrCreateStack(int, int, boolean)
+ */
+ ActivityStack getOrCreateStack(@Nullable ActivityRecord r,
+ @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
+ boolean onTop) {
+ // First preference is the windowing mode in the activity options if set.
+ int windowingMode = (options != null)
+ ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+ // Validate that our desired windowingMode will work under the current conditions.
+ // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
+ // it's display's windowing mode.
+ windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
+ return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
+ candidateTask, false /* createdByOrganizer */);
+ }
+
+ @VisibleForTesting
+ int getNextStackId() {
+ return mAtmService.mStackSupervisor.getNextTaskIdForUser();
+ }
+
+ ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
+ return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */,
+ false /* createdByOrganizer */);
+ }
+
+ /**
+ * Creates a stack matching the input windowing mode and activity type on this display.
+ * @param windowingMode The windowing mode the stack should be created in. If
+ * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
+ * inherit its parent's windowing mode.
+ * @param activityType The activityType the stack should be created in. If
+ * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
+ * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+ * @param onTop If true the stack will be created at the top of the display, else at the bottom.
+ * @param info The started activity info.
+ * @param intent The intent that started this task.
+ * @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
+ * otherwise.
+ * @return The newly created stack.
+ */
+ ActivityStack createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
+ Intent intent, boolean createdByOrganizer) {
+ if (mDisplayContent.mSingleTaskInstance && getStackCount() > 0) {
+ // Create stack on default display instead since this display can only contain 1 stack.
+ // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
+ // this goes away once ActivityView is no longer using virtual displays.
+ return mRootWindowContainer.getDefaultDisplay().mTaskContainers.createStack(
+ windowingMode, activityType, onTop, info, intent, createdByOrganizer);
+ }
+
+ if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) {
+ // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
+ // anything else should be passing it in anyways...except for the task organizer.
+ activityType = ACTIVITY_TYPE_STANDARD;
+ }
+
+ if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) {
+ // For now there can be only one stack of a particular non-standard activity type on a
+ // display. So, get that ignoring whatever windowing mode it is currently in.
+ ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
+ if (stack != null) {
+ throw new IllegalArgumentException("Stack=" + stack + " of activityType="
+ + activityType + " already on display=" + this + ". Can't have multiple.");
+ }
+ }
+
+ if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
+ mAtmService.mSupportsSplitScreenMultiWindow,
+ mAtmService.mSupportsFreeformWindowManagement,
+ mAtmService.mSupportsPictureInPicture, activityType)) {
+ throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
+ + windowingMode);
+ }
+
+ final int stackId = getNextStackId();
+ return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
+ createdByOrganizer);
+ }
+
+ /** @return the root task to create the next task in. */
+ private Task updateLaunchRootTask(int windowingMode) {
+ if (!isSplitScreenWindowingMode(windowingMode)) {
+ // Only split-screen windowing modes can do this currently...
+ return null;
+ }
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final Task t = getStackAt(i);
+ if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) {
+ continue;
+ }
+ // If not already set, pick a launch root which is not the one we are launching into.
+ if (mLaunchRootTask == null) {
+ for (int j = 0, n = getStackCount(); j < n; ++j) {
+ final Task tt = getStackAt(j);
+ if (tt.mCreatedByOrganizer && tt != t) {
+ mLaunchRootTask = tt;
+ break;
+ }
+ }
+ }
+ return t;
+ }
+ return mLaunchRootTask;
+ }
+
+ @VisibleForTesting
+ ActivityStack createStackUnchecked(int windowingMode, int activityType, int stackId,
+ boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) {
+ if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
+ throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
+ + "activity type.");
+ }
+ if (info == null) {
+ info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ }
+
+ // Task created by organizer are added as root.
+ Task launchRootTask = createdByOrganizer ? null : updateLaunchRootTask(windowingMode);
+ if (launchRootTask != null) {
+ // Since this stack will be put into a root task, its windowingMode will be inherited.
+ windowingMode = WINDOWING_MODE_UNDEFINED;
+ }
+
+ final ActivityStack stack = (ActivityStack) Task.create(mAtmService, stackId, activityType,
+ info, intent, createdByOrganizer);
+ if (launchRootTask != null) {
+ launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
+ if (onTop) {
+ positionStackAtTop((ActivityStack) launchRootTask, false /* includingParents */);
+ }
+ } else {
+ addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
+ stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
+ false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
+ true /* creating */);
+ }
+ return stack;
+ }
+
+ /**
+ * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
+ * focusable and visible stack from the top of stacks in this display.
+ */
+ ActivityStack getFocusedStack() {
+ if (mPreferredTopFocusableStack != null) {
+ return mPreferredTopFocusableStack;
+ }
+
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ if (stack.isFocusableAndVisible()) {
+ return stack;
+ }
+ }
+
+ return null;
+ }
+
+ ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
+ final int currentWindowingMode = currentFocus != null
+ ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
+
+ ActivityStack candidate = null;
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ if (ignoreCurrent && stack == currentFocus) {
+ continue;
+ }
+ if (!stack.isFocusableAndVisible()) {
+ continue;
+ }
+
+ if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
+ // If the currently focused stack is in split-screen secondary we save off the
+ // top primary split-screen stack as a candidate for focus because we might
+ // prefer focus to move to an other stack to avoid primary split-screen stack
+ // overlapping with a fullscreen stack when a fullscreen stack is higher in z
+ // than the next split-screen stack. Assistant stack, I am looking at you...
+ // We only move the focus to the primary-split screen stack if there isn't a
+ // better alternative.
+ candidate = stack;
+ continue;
+ }
+ if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
+ // Use the candidate stack since we are now at the secondary split-screen.
+ return candidate;
+ }
+ return stack;
+ }
+ return candidate;
+ }
+
+ ActivityRecord getResumedActivity() {
+ final ActivityStack focusedStack = getFocusedStack();
+ if (focusedStack == null) {
+ return null;
+ }
+ // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
+ // Check if the focused stack has the resumed activity
+ ActivityRecord resumedActivity = focusedStack.getResumedActivity();
+ if (resumedActivity == null || resumedActivity.app == null) {
+ // If there is no registered resumed activity in the stack or it is not running -
+ // try to use previously resumed one.
+ resumedActivity = focusedStack.mPausingActivity;
+ if (resumedActivity == null || resumedActivity.app == null) {
+ // If previously resumed activity doesn't work either - find the topmost running
+ // activity that can be focused.
+ resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
+ }
+ }
+ return resumedActivity;
+ }
+
+ ActivityStack getLastFocusedStack() {
+ return mLastFocusedStack;
+ }
+
+ boolean allResumedActivitiesComplete() {
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
+ if (r != null && !r.isState(RESUMED)) {
+ return false;
+ }
+ }
+ final ActivityStack currentFocusedStack = getFocusedStack();
+ if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
+ Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
+ + mLastFocusedStack + " to=" + currentFocusedStack);
+ }
+ mLastFocusedStack = currentFocusedStack;
+ return true;
+ }
+
+ /**
+ * Pause all activities in either all of the stacks or just the back stacks. This is done before
+ * resuming a new activity and to make sure that previously active activities are
+ * paused in stacks that are no longer visible or in pinned windowing mode. This does not
+ * pause activities in visible stacks, so if an activity is launched within the same stack/task,
+ * then we should explicitly pause that stack's top activity.
+ * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
+ * @param resuming The resuming activity.
+ * @return {@code true} if any activity was paused as a result of this call.
+ */
+ boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
+ boolean someActivityPaused = false;
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ final ActivityRecord resumedActivity = stack.getResumedActivity();
+ if (resumedActivity != null
+ && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
+ || !stack.isTopActivityFocusable())) {
+ if (DEBUG_STATES) {
+ Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack
+ + " mResumedActivity=" + resumedActivity);
+ }
+ someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
+ resuming);
+ }
+ }
+ return someActivityPaused;
+ }
+
+ /**
+ * Find task for putting the Activity in.
+ */
+ void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
+ RootWindowContainer.FindTaskResult result) {
+ mTmpFindTaskResult.clear();
+ for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getStackAt(stackNdx);
+ if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
+ if (DEBUG_TASKS) {
+ Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
+ }
+ continue;
+ }
+
+ mTmpFindTaskResult.process(r, stack);
+ // It is possible to have tasks in multiple stacks with the same root affinity, so
+ // we should keep looking after finding an affinity match to see if there is a
+ // better match in another stack. Also, task affinity isn't a good enough reason
+ // to target a display which isn't the source of the intent, so skip any affinity
+ // matches not on the specified display.
+ if (mTmpFindTaskResult.mRecord != null) {
+ if (mTmpFindTaskResult.mIdealMatch) {
+ result.setTo(mTmpFindTaskResult);
+ return;
+ } else if (isPreferredDisplay) {
+ // Note: since the traversing through the stacks is top down, the floating
+ // tasks should always have lower priority than any affinity-matching tasks
+ // in the fullscreen stacks
+ result.setTo(mTmpFindTaskResult);
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes stacks in the input windowing modes from the system if they are of activity type
+ * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
+ */
+ void removeStacksInWindowingModes(int... windowingModes) {
+ if (windowingModes == null || windowingModes.length == 0) {
+ return;
+ }
+
+ // Collect the stacks that are necessary to be removed instead of performing the removal
+ // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+ // stacks reordered.
+ final ArrayList<ActivityStack> stacks = new ArrayList<>();
+ for (int j = windowingModes.length - 1; j >= 0; --j) {
+ final int windowingMode = windowingModes[j];
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ continue;
+ }
+ if (stack.getWindowingMode() != windowingMode) {
+ continue;
+ }
+ stacks.add(stack);
+ }
+ }
+
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ mRootWindowContainer.mStackSupervisor.removeStack(stacks.get(i));
+ }
+ }
+
+ void removeStacksWithActivityTypes(int... activityTypes) {
+ if (activityTypes == null || activityTypes.length == 0) {
+ return;
+ }
+
+ // Collect the stacks that are necessary to be removed instead of performing the removal
+ // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+ // stacks reordered.
+ final ArrayList<ActivityStack> stacks = new ArrayList<>();
+ for (int j = activityTypes.length - 1; j >= 0; --j) {
+ final int activityType = activityTypes[j];
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ // Collect the root tasks that are currently being organized.
+ if (stack.isOrganized()) {
+ for (int k = stack.getChildCount() - 1; k >= 0; --k) {
+ final ActivityStack childStack = (ActivityStack) stack.getChildAt(k);
+ if (childStack.getActivityType() == activityType) {
+ stacks.add(childStack);
+ }
+ }
+ } else if (stack.getActivityType() == activityType) {
+ stacks.add(stack);
+ }
+ }
+ }
+
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ mRootWindowContainer.mStackSupervisor.removeStack(stacks.get(i));
+ }
+ }
+
+ void onSplitScreenModeDismissed() {
+ mAtmService.deferWindowLayout();
+ try {
+ mLaunchRootTask = null;
+ moveSplitScreenTasksToFullScreen();
+ } finally {
+ final ActivityStack topFullscreenStack =
+ getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ final ActivityStack homeStack = getOrCreateRootHomeTask();
+ if (topFullscreenStack != null && homeStack != null && !isTopStack(homeStack)) {
+ // Whenever split-screen is dismissed we want the home stack directly behind the
+ // current top fullscreen stack so it shows up when the top stack is finished.
+ // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
+ // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
+ // once we have that.
+ homeStack.moveToFront("onSplitScreenModeDismissed");
+ topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
+ }
+ mAtmService.continueWindowLayout();
+ }
+ }
+
+ private void moveSplitScreenTasksToFullScreen() {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTmpTasks.clear();
+ forAllTasks(task -> {
+ if (task.mCreatedByOrganizer && task.inSplitScreenWindowingMode() && task.hasChild()) {
+ mTmpTasks.add(task);
+ }
+ });
+
+ for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
+ final Task root = mTmpTasks.get(i);
+ for (int j = 0; j < root.getChildCount(); j++) {
+ wct.reparent(root.getChildAt(j).mRemoteToken, null, true /* toTop */);
+ }
+ }
+ mAtmService.mWindowOrganizerController.applyTransaction(wct);
+ }
+
+ /**
+ * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
+ * @param windowingMode The windowing mode we are checking support for.
+ * @param supportsMultiWindow If we should consider support for multi-window mode in general.
+ * @param supportsSplitScreen If we should consider support for split-screen multi-window.
+ * @param supportsFreeform If we should consider support for freeform multi-window.
+ * @param supportsPip If we should consider support for picture-in-picture mutli-window.
+ * @param activityType The activity type under consideration.
+ * @return true if the windowing mode is supported.
+ */
+ private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
+ boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
+ int activityType) {
+
+ if (windowingMode == WINDOWING_MODE_UNDEFINED
+ || windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ return true;
+ }
+ if (!supportsMultiWindow) {
+ return false;
+ }
+
+ if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
+ return true;
+ }
+
+ final int displayWindowingMode = getWindowingMode();
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+ return supportsSplitScreen
+ && WindowConfiguration.supportSplitScreenWindowingMode(activityType)
+ // Freeform windows and split-screen windows don't mix well, so prevent
+ // split windowing modes on freeform displays.
+ && displayWindowingMode != WINDOWING_MODE_FREEFORM;
+ }
+
+ if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
+ return false;
+ }
+
+ if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
+ * display with the provided parameters.
+ *
+ * @param r The ActivityRecord in question.
+ * @param options Options to start with.
+ * @param task The task within-which the activity would start.
+ * @param activityType The type of activity to start.
+ * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
+ */
+ int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ @Nullable Task task, int activityType) {
+
+ // First preference if the windowing mode in the activity options if set.
+ int windowingMode = (options != null)
+ ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+
+ // If windowing mode is unset, then next preference is the candidate task, then the
+ // activity record.
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ if (task != null) {
+ windowingMode = task.getWindowingMode();
+ }
+ if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
+ windowingMode = r.getWindowingMode();
+ }
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ // Use the display's windowing mode.
+ windowingMode = getWindowingMode();
+ }
+ }
+ windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
+ return windowingMode != WINDOWING_MODE_UNDEFINED
+ ? windowingMode : WINDOWING_MODE_FULLSCREEN;
+ }
+
+ /**
+ * Check that the requested windowing-mode is appropriate for the specified task and/or activity
+ * on this display.
+ *
+ * @param windowingMode The windowing-mode to validate.
+ * @param r The {@link ActivityRecord} to check against.
+ * @param task The {@link Task} to check against.
+ * @param activityType An activity type.
+ * @return The provided windowingMode or the closest valid mode which is appropriate.
+ */
+ int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
+ int activityType) {
+ // Make sure the windowing mode we are trying to use makes sense for what is supported.
+ boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
+ boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
+ boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
+ boolean supportsPip = mAtmService.mSupportsPictureInPicture;
+ if (supportsMultiWindow) {
+ if (task != null) {
+ supportsMultiWindow = task.isResizeable();
+ supportsSplitScreen = task.supportsSplitScreenWindowingMode();
+ // TODO: Do we need to check for freeform and Pip support here?
+ } else if (r != null) {
+ supportsMultiWindow = r.isResizeable();
+ supportsSplitScreen = r.supportsSplitScreenWindowingMode();
+ supportsFreeform = r.supportsFreeform();
+ supportsPip = r.supportsPictureInPicture();
+ }
+ }
+
+ final boolean inSplitScreenMode = isSplitScreenModeActivated();
+ if (!inSplitScreenMode
+ && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
+ // Switch to the display's windowing mode if we are not in split-screen mode and we are
+ // trying to launch in split-screen secondary.
+ windowingMode = WINDOWING_MODE_UNDEFINED;
+ } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_UNDEFINED)
+ && supportsSplitScreen) {
+ windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ }
+
+ if (windowingMode != WINDOWING_MODE_UNDEFINED
+ && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
+ supportsFreeform, supportsPip, activityType)) {
+ return windowingMode;
+ }
+ return WINDOWING_MODE_UNDEFINED;
+ }
+
+ boolean isTopStack(ActivityStack stack) {
+ return stack == getTopStack();
+ }
+
+ boolean isTopNotPinnedStack(ActivityStack stack) {
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack current = getStackAt(i);
+ if (!current.inPinnedWindowingMode()) {
+ return current == stack;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the top running activity in the focused stack. In the case the focused stack has no
+ * such activity, the next focusable stack on this display is returned.
+ *
+ * @param considerKeyguardState Indicates whether the locked state should be considered. if
+ * {@code true} and the keyguard is locked, only activities that
+ * can be shown on top of the keyguard will be considered.
+ * @return The top running activity. {@code null} if none is available.
+ */
+ ActivityRecord topRunningActivity(boolean considerKeyguardState) {
+ ActivityRecord topRunning = null;
+ final ActivityStack focusedStack = getFocusedStack();
+ if (focusedStack != null) {
+ topRunning = focusedStack.topRunningActivity();
+ }
+
+ // Look in other focusable stacks.
+ if (topRunning == null) {
+ for (int i = getStackCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = getStackAt(i);
+ // Only consider focusable stacks other than the current focused one.
+ if (stack == focusedStack || !stack.isTopActivityFocusable()) {
+ continue;
+ }
+ topRunning = stack.topRunningActivity();
+ if (topRunning != null) {
+ break;
+ }
+ }
+ }
+
+ // This activity can be considered the top running activity if we are not considering
+ // the locked state, the keyguard isn't locked, or we can show when locked.
+ if (topRunning != null && considerKeyguardState
+ && mRootWindowContainer.mStackSupervisor.getKeyguardController()
+ .isKeyguardLocked()
+ && !topRunning.canShowWhenLocked()) {
+ return null;
+ }
+
+ return topRunning;
+ }
+
+ protected int getStackCount() {
+ return mChildren.size();
+ }
+
+ protected ActivityStack getStackAt(int index) {
+ return mChildren.get(index);
+ }
+
+ /**
+ * Returns the existing home stack or creates and returns a new one if it should exist for the
+ * display.
+ */
+ @Nullable
+ ActivityStack getOrCreateRootHomeTask() {
+ ActivityStack homeTask = getRootHomeTask();
+ if (homeTask == null && mDisplayContent.supportsSystemDecorations()
+ && !mDisplayContent.isUntrustedVirtualDisplay()) {
+ homeTask = createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME,
+ false /* onTop */);
+ }
+ return homeTask;
+ }
+
+ boolean isSplitScreenModeActivated() {
+ Task task = getRootSplitScreenPrimaryTask();
+ return task != null && task.hasChild();
+ }
+
+ /**
+ * Returns the topmost stack on the display that is compatible with the input windowing mode.
+ * Null is no compatible stack on the display.
+ */
+ ActivityStack getTopStackInWindowingMode(int windowingMode) {
+ return getStack(windowingMode, ACTIVITY_TYPE_UNDEFINED);
+ }
+
+ void moveHomeStackToFront(String reason) {
+ final ActivityStack homeStack = getOrCreateRootHomeTask();
+ if (homeStack != null) {
+ homeStack.moveToFront(reason);
+ }
+ }
+
+ /**
+ * Moves the focusable home activity to top. If there is no such activity, the home stack will
+ * still move to top.
+ */
+ void moveHomeActivityToTop(String reason) {
+ final ActivityRecord top = getHomeActivity();
+ if (top == null) {
+ moveHomeStackToFront(reason);
+ return;
+ }
+ top.moveFocusableActivityToTop(reason);
+ }
+
+ @Nullable
+ ActivityRecord getHomeActivity() {
+ return getHomeActivityForUser(mRootWindowContainer.mCurrentUser);
+ }
+
+ @Nullable
+ ActivityRecord getHomeActivityForUser(int userId) {
+ final ActivityStack homeStack = getRootHomeTask();
+ if (homeStack == null) {
+ return null;
+ }
+
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ TaskContainers::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
+ userId);
+ final ActivityRecord r = homeStack.getActivity(p);
+ p.recycle();
+ return r;
+ }
+
+ private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
+ return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
+ }
+
+ /**
+ * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
+ * Generally used in conjunction with {@link #moveStackBehindStack}.
+ */
+ // TODO(b/151575894): Remove special stack movement methods.
+ void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
+ if (stack.shouldBeVisible(null)) {
+ // Skip if the stack is already visible
+ return;
+ }
+
+ final boolean isRootTask = stack.isRootTask();
+ if (isRootTask) {
+ // Move the stack to the bottom to not affect the following visibility checks
+ positionStackAtBottom(stack);
+ } else {
+ stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */);
+ }
+
+ // Find the next position where the stack should be placed
+ final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount();
+ for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+ final ActivityStack s = isRootTask ? getStackAt(stackNdx)
+ : (ActivityStack) stack.getParent().getChildAt(stackNdx);
+ if (s == stack) {
+ continue;
+ }
+ final int winMode = s.getWindowingMode();
+ final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
+ || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ if (s.shouldBeVisible(null) && isValidWindowingMode) {
+ // Move the provided stack to behind this stack
+ final int position = Math.max(0, stackNdx - 1);
+ if (isRootTask) {
+ positionStackAt(stack, position);
+ } else {
+ stack.getParent().positionChildAt(position, stack, false /*includingParents */);
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Moves the {@param stack} behind the given {@param behindStack} if possible. If
+ * {@param behindStack} is not currently in the display, then then the stack is moved to the
+ * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
+ */
+ void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
+ if (behindStack == null || behindStack == stack) {
+ return;
+ }
+
+ final WindowContainer parent = stack.getParent();
+ if (parent == null || parent != behindStack.getParent()) {
+ return;
+ }
+
+ // Note that positionChildAt will first remove the given stack before inserting into the
+ // list, so we need to adjust the insertion index to account for the removed index
+ // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
+ // position internally
+ final int stackIndex = parent.mChildren.indexOf(stack);
+ final int behindStackIndex = parent.mChildren.indexOf(behindStack);
+ final int insertIndex = stackIndex <= behindStackIndex
+ ? behindStackIndex - 1 : behindStackIndex;
+ final int position = Math.max(0, insertIndex);
+ if (stack.isRootTask()) {
+ positionStackAt(stack, position);
+ } else {
+ parent.positionChildAt(position, stack, false /* includingParents */);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8a896f5..15b483c 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -255,9 +255,9 @@
return null;
}
- final Task task = display.getOrCreateStack(windowingMode, ACTIVITY_TYPE_UNDEFINED,
- false /* onTop */, new Intent(), null /* candidateTask */,
- true /* createdByOrganizer */);
+ final Task task = display.mTaskContainers.getOrCreateStack(windowingMode,
+ ACTIVITY_TYPE_UNDEFINED, false /* onTop */, new Intent(),
+ null /* candidateTask */, true /* createdByOrganizer */);
RunningTaskInfo out = task.getTaskInfo();
mLastSentTaskInfos.put(task, out);
return out;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 5f21e17..7eccf08 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -252,9 +252,10 @@
final ActivityStack rootTask =
(ActivityStack) (newParent != null ? newParent : task.getRootTask());
if (hop.getToTop()) {
- as.getDisplay().positionStackAtTop(rootTask, false /* includingParents */);
+ as.getDisplay().mTaskContainers.positionStackAtTop(rootTask,
+ false /* includingParents */);
} else {
- as.getDisplay().positionStackAtBottom(rootTask);
+ as.getDisplay().mTaskContainers.positionStackAtBottom(rootTask);
}
}
} else {
@@ -264,9 +265,9 @@
// Ugh, of course ActivityStack has its own special reorder logic...
if (task.isRootTask()) {
if (hop.getToTop()) {
- dc.positionStackAtTop(as, false /* includingParents */);
+ dc.mTaskContainers.positionStackAtTop(as, false /* includingParents */);
} else {
- dc.positionStackAtBottom(as);
+ dc.mTaskContainers.positionStackAtBottom(as);
}
} else {
task.getParent().positionChildAt(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 4f84ee1..05604b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -69,11 +69,11 @@
stack.moveToFront("moveStackToFront");
// After moving the stack to front, the previous focused should be the last focused.
assertTrue(stack.isFocusedStackOnDisplay());
- assertEquals(prevFocusedStack, display.getLastFocusedStack());
+ assertEquals(prevFocusedStack, display.mTaskContainers.getLastFocusedStack());
stack.moveToBack("moveStackToBack", null /* task */);
// After moving the stack to back, the stack should be the last focused.
- assertEquals(stack, display.getLastFocusedStack());
+ assertEquals(stack, display.mTaskContainers.getLastFocusedStack());
}
/**
@@ -225,7 +225,7 @@
final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
.setStack(alwaysOnTopStack).build();
alwaysOnTopStack.setAlwaysOnTop(true);
- display.positionStackAtTop(alwaysOnTopStack, false /* includingParents */);
+ display.mTaskContainers.positionStackAtTop(alwaysOnTopStack, false /* includingParents */);
assertTrue(alwaysOnTopStack.isAlwaysOnTop());
// Ensure always on top state is synced to the children of the stack.
assertTrue(alwaysOnTopStack.getTopNonFinishingActivity().isAlwaysOnTop());
@@ -239,7 +239,8 @@
final ActivityStack anotherAlwaysOnTopStack = display.createStack(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
anotherAlwaysOnTopStack.setAlwaysOnTop(true);
- display.positionStackAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
+ display.mTaskContainers.positionStackAtTop(anotherAlwaysOnTopStack,
+ false /* includingParents */);
assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
int topPosition = display.getStackCount() - 1;
// Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
@@ -255,7 +256,8 @@
assertEquals(nonAlwaysOnTopStack, display.getStackAt(topPosition - 3));
anotherAlwaysOnTopStack.setAlwaysOnTop(false);
- display.positionStackAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
+ display.mTaskContainers.positionStackAtTop(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.
@@ -300,7 +302,7 @@
// Reordering stacks while removing stacks.
doAnswer(invocation -> {
- display.positionStackAtTop(stack3, false);
+ display.mTaskContainers.positionStackAtTop(stack3, false);
return true;
}).when(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 12934ee..71ca878 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -613,7 +613,7 @@
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
assertEquals(fullscreenStack, mDefaultDisplay.getStackAbove(homeStack));
- mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack);
+ mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack));
}
@@ -632,7 +632,7 @@
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
assertEquals(fullscreenStack, mDefaultDisplay.getStackAbove(homeStack));
- mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack);
+ mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack));
}
@@ -651,7 +651,7 @@
// Ensure we don't move the home stack if it is already on top
int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
assertNull(mDefaultDisplay.getStackAbove(homeStack));
- mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack);
+ mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack));
}
@@ -677,7 +677,7 @@
// Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the
// pinned stack
assertEquals(fullscreenStack1, mDefaultDisplay.getStackAbove(homeStack));
- mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack);
+ mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
assertEquals(fullscreenStack2, mDefaultDisplay.getStackAbove(homeStack));
}
@@ -702,7 +702,7 @@
// Ensure that we move the home stack behind the bottom most non-translucent fullscreen
// stack
assertEquals(fullscreenStack1, mDefaultDisplay.getStackAbove(homeStack));
- mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack);
+ mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
assertEquals(fullscreenStack1, mDefaultDisplay.getStackAbove(homeStack));
}
@@ -725,7 +725,7 @@
// Ensure we don't move the home stack behind itself
int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
- mDefaultDisplay.moveStackBehindStack(homeStack, homeStack);
+ mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, homeStack);
assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack));
}
@@ -748,13 +748,13 @@
final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack1);
+ mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, fullscreenStack1);
assertEquals(fullscreenStack1, mDefaultDisplay.getStackAbove(homeStack));
- mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack2);
+ mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, fullscreenStack2);
assertEquals(fullscreenStack2, mDefaultDisplay.getStackAbove(homeStack));
- mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack4);
+ mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, fullscreenStack4);
assertEquals(fullscreenStack4, mDefaultDisplay.getStackAbove(homeStack));
- mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack2);
+ mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, fullscreenStack2);
assertEquals(fullscreenStack2, mDefaultDisplay.getStackAbove(homeStack));
}
@@ -845,9 +845,10 @@
// Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
stack = mDefaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
if (onTop) {
- mDefaultDisplay.positionStackAtTop(stack, false /* includingParents */);
+ mDefaultDisplay.mTaskContainers.positionStackAtTop(stack,
+ false /* includingParents */);
} else {
- mDefaultDisplay.positionStackAtBottom(stack);
+ mDefaultDisplay.mTaskContainers.positionStackAtBottom(stack);
}
} else {
stack = new StackBuilder(mRootWindowContainer)
@@ -1090,7 +1091,7 @@
mDefaultDisplay.registerStackOrderChangedListener(listener);
try {
mStack.mReparenting = true;
- mDefaultDisplay.addStack(mStack, 0);
+ mDefaultDisplay.mTaskContainers.addStack(mStack, 0);
} finally {
mDefaultDisplay.unregisterStackOrderChangedListener(listener);
}
@@ -1105,7 +1106,7 @@
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
mDefaultDisplay.registerStackOrderChangedListener(listener);
- mDefaultDisplay.positionStackAtBottom(fullscreenStack1);
+ mDefaultDisplay.mTaskContainers.positionStackAtBottom(fullscreenStack1);
} finally {
mDefaultDisplay.unregisterStackOrderChangedListener(listener);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 716369d..9240b22 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -462,9 +462,11 @@
}
ActivityStack build() {
- final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId();
- final ActivityStack stack = mDisplay.createStackUnchecked(mWindowingMode,
- mActivityType, stackId, mOnTop, mInfo, mIntent, false /* createdByOrganizer */);
+ final int stackId = mStackId >= 0 ? mStackId
+ : mDisplay.mTaskContainers.getNextStackId();
+ final ActivityStack stack = mDisplay.mTaskContainers.createStackUnchecked(
+ mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent,
+ false /* createdByOrganizer */);
final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor;
if (mCreateActivity) {
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 218c816..5b96c43 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1088,7 +1088,7 @@
}
assertNull(defaultDisplay.getRootHomeTask());
- assertNotNull(defaultDisplay.getOrCreateRootHomeTask());
+ assertNotNull(defaultDisplay.mTaskContainers.getOrCreateRootHomeTask());
}
@Test
@@ -1104,7 +1104,7 @@
}
assertNull(display.getRootHomeTask());
- assertNotNull(display.getOrCreateRootHomeTask());
+ assertNotNull(display.mTaskContainers.getOrCreateRootHomeTask());
}
@Test
@@ -1113,7 +1113,7 @@
doReturn(false).when(display).supportsSystemDecorations();
assertNull(display.getRootHomeTask());
- assertNull(display.getOrCreateRootHomeTask());
+ assertNull(display.mTaskContainers.getOrCreateRootHomeTask());
}
@Test
@@ -1122,7 +1122,7 @@
doReturn(true).when(display).isUntrustedVirtualDisplay();
assertNull(display.getRootHomeTask());
- assertNull(display.getOrCreateRootHomeTask());
+ assertNull(display.mTaskContainers.getOrCreateRootHomeTask());
}
private boolean isOptionsPanelAtRight(int displayId) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index b3a25302..cfb5bc7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -119,7 +119,7 @@
final DisplayContent defaultDisplay = mRootWindowContainer.getDefaultDisplay();
final ActivityStack homeStack =
defaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
- defaultDisplay.positionStackAtTop(homeStack, false /* includingParents */);
+ defaultDisplay.mTaskContainers.positionStackAtTop(homeStack, false /* includingParents */);
ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
if (topRunningHomeActivity == null) {
topRunningHomeActivity = new ActivityBuilder(mService)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index e841e43..dc354a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -325,7 +325,8 @@
mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
false);
- verify(display).moveHomeStackToFront(contains(reason));
+ final TaskContainers taskContainers = display.mTaskContainers;
+ verify(taskContainers).moveHomeStackToFront(contains(reason));
}
/**
@@ -352,7 +353,8 @@
mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
false);
- verify(display, never()).moveHomeStackToFront(contains(reason));
+ final TaskContainers taskContainers = display.mTaskContainers;
+ verify(taskContainers, never()).moveHomeStackToFront(contains(reason));
}
/**
@@ -367,7 +369,7 @@
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
- display.positionStackAtBottom(targetStack);
+ display.mTaskContainers.positionStackAtBottom(targetStack);
// Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it
// is the current top focused stack.
@@ -470,7 +472,7 @@
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
activity.setState(ActivityState.RESUMED, "test");
- display.positionStackAtBottom(targetStack);
+ display.mTaskContainers.positionStackAtBottom(targetStack);
// Assume the stack is at the topmost position
assertFalse(targetStack.isTopStackOnDisplay());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 091f493..8c8d3f1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -316,7 +316,9 @@
// that the default display is in fullscreen mode.
display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN);
spyOn(display);
- final ActivityStack homeStack = display.getStack(
+ final TaskContainers taskContainer = display.mTaskContainers;
+ spyOn(taskContainer);
+ final ActivityStack homeStack = taskContainer.getStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
spyOn(homeStack);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index fc8cc96..18737c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -43,6 +43,7 @@
// hard-code to FULLSCREEN for tests.
setWindowingMode(WINDOWING_MODE_FULLSCREEN);
spyOn(this);
+ spyOn(mTaskContainers);
final DisplayRotation displayRotation = getDisplayRotation();
spyOn(displayRotation);