diff options
15 files changed, 337 insertions, 396 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index 751ae0db67d6..ed366453028e 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -267,6 +267,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> mWindowContainerController.positionChildAt(stack.getWindowContainerController(), insertPosition, includingParents); } + if (!wasContained) { + stack.setParent(this); + } onStackOrderChanged(); } @@ -692,7 +695,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> } otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED, false /* animate */, false /* showRecents */, false /* enteringSplitScreenMode */, - true /* deferEnsuringVisibility */); + true /* deferEnsuringVisibility */, false /* creating */); } } finally { final ActivityStack topFullscreenStack = @@ -722,7 +725,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> } otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, false /* animate */, false /* showRecents */, - true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */); + true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */, + false /* creating */); } } finally { mSupervisor.mWindowManager.continueSurfaceLayout(); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 7fcee3db3e78..8d467c808e55 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -233,13 +233,40 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } @Override - protected ConfigurationContainer getParent() { + protected ActivityDisplay getParent() { return getDisplay(); } + void setParent(ActivityDisplay parent) { + ActivityDisplay current = getParent(); + if (current != parent) { + mDisplayId = parent.mDisplayId; + onParentChanged(); + } + } + @Override protected void onParentChanged() { + ActivityDisplay display = getParent(); + if (display != null) { + // Rotations are relative to the display. This means if there are 2 displays rotated + // differently (eg. 2 monitors with one landscape and one portrait), moving a stack + // from one to the other could look like a rotation change. To prevent this + // apparent rotation change (and corresponding bounds rotation), pretend like our + // current rotation is already the same as the new display. + // Note, if ActivityStack or related logic ever gets nested, this logic will need + // to move to onConfigurationChanged. + getConfiguration().windowConfiguration.setRotation( + display.getWindowConfiguration().getRotation()); + } super.onParentChanged(); + if (display != null && inSplitScreenPrimaryWindowingMode()) { + // If we created a docked stack we want to resize it so it resizes all other stacks + // in the system. + getStackDockedModeBounds(null, null, mTmpRect2, mTmpRect3); + mStackSupervisor.resizeDockedStackLocked( + getOverrideBounds(), mTmpRect2, mTmpRect2, null, null, PRESERVE_WINDOWS); + } mStackSupervisor.updateUIDsPresentOnDisplay(); } @@ -353,7 +380,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai private final SparseArray<Rect> mTmpBounds = new SparseArray<>(); private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>(); + private final Rect mTmpRect = new Rect(); private final Rect mTmpRect2 = new Rect(); + private final Rect mTmpRect3 = new Rect(); private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic(); /** List for processing through a set of activities */ @@ -469,10 +498,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // stacks on a wrong display. mDisplayId = display.mDisplayId; setActivityType(activityType); - setWindowingMode(windowingMode); mWindowContainerController = createStackWindowController(display.mDisplayId, onTop, mTmpRect2); - postAddToDisplay(display, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop); + setWindowingMode(windowingMode, false /* animate */, false /* showRecents */, + false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */, + true /* creating */); + display.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM); } T createStackWindowController(int displayId, boolean onTop, Rect outBounds) { @@ -514,21 +545,85 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final int prevWindowingMode = getWindowingMode(); final boolean prevIsAlwaysOnTop = isAlwaysOnTop(); final ActivityDisplay display = getDisplay(); + final int prevRotation = getWindowConfiguration().getRotation(); + final int prevDensity = getConfiguration().densityDpi; + final int prevScreenW = getConfiguration().screenWidthDp; + final int prevScreenH = getConfiguration().screenHeightDp; - getBounds(mTmpRect2); - final boolean hasNewBounds = display != null && getWindowContainerController() != null - && getWindowContainerController().updateBoundsForConfigChange( - newParentConfig, getConfiguration(), mTmpRect2); + getBounds(mTmpRect); // previous bounds super.onConfigurationChanged(newParentConfig); if (display == null) { - return; + return; + } + + // Update bounds if applicable + boolean hasNewOverrideBounds = false; + // Use override windowing mode to prevent extra bounds changes if inheriting the mode. + if (getOverrideWindowingMode() == WINDOWING_MODE_PINNED) { + // Pinned calculation already includes rotation + mTmpRect2.set(mTmpRect); + hasNewOverrideBounds = getWindowContainerController().mContainer + .calculatePinnedBoundsForConfigChange(mTmpRect2); + } else { + final int newRotation = getWindowConfiguration().getRotation(); + if (!matchParentBounds()) { + // If the parent (display) has rotated, rotate our bounds to best-fit where their + // bounds were on the pre-rotated display. + if (prevRotation != newRotation) { + mTmpRect2.set(mTmpRect); + getDisplay().getWindowContainerController().mContainer + .rotateBounds(newParentConfig.windowConfiguration.getBounds(), + prevRotation, newRotation, mTmpRect2); + hasNewOverrideBounds = true; + } + + // If entering split screen or if something about the available split area changes, + // recalculate the split windows to match the new configuration. + if (prevRotation != newRotation + || prevDensity != getConfiguration().densityDpi + || prevWindowingMode != getWindowingMode() + || prevScreenW != getConfiguration().screenWidthDp + || prevScreenH != getConfiguration().screenHeightDp) { + // Use override windowing mode to prevent extra bounds changes if inheriting + // the mode. + if (getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + || getOverrideWindowingMode() + == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { + mTmpRect2.set(mTmpRect); + getWindowContainerController().mContainer + .calculateDockedBoundsForConfigChange(newParentConfig, mTmpRect2); + hasNewOverrideBounds = true; + } + } + } + } + if (getWindowingMode() != prevWindowingMode) { + // Use override windowing mode to prevent extra bounds changes if inheriting the mode. + if (getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + getStackDockedModeBounds(null, null, mTmpRect2, mTmpRect3); + // immediately resize so docked bounds are available in onSplitScreenModeActivated + resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */); + } else if (getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { + Rect dockedBounds = display.getSplitScreenPrimaryStack().getBounds(); + final boolean isMinimizedDock = getDisplay().getWindowContainerController() + .mContainer.getDockedDividerController().isMinimizedDock(); + if (isMinimizedDock) { + TaskRecord topTask = display.getSplitScreenPrimaryStack().topTask(); + if (topTask != null) { + dockedBounds = topTask.getBounds(); + } + } + getStackDockedModeBounds(dockedBounds, null, mTmpRect2, mTmpRect3); + hasNewOverrideBounds = true; + } } if (prevWindowingMode != getWindowingMode()) { display.onStackWindowingModeChanged(this); } - if (hasNewBounds) { - resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */); + if (hasNewOverrideBounds) { + mStackSupervisor.resizeStackLocked(this, mTmpRect2, null, null, PRESERVE_WINDOWS, + true /* allowResizeInDockedMode */, true /* deferResume */); } if (prevIsAlwaysOnTop != isAlwaysOnTop()) { // Since always on top is only on when the stack is freeform or pinned, the state @@ -541,7 +636,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai @Override public void setWindowingMode(int windowingMode) { setWindowingMode(windowingMode, false /* animate */, false /* showRecents */, - false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */); + false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */, + false /* creating */); } /** @@ -569,10 +665,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai * @param enteringSplitScreenMode {@code true} if entering split mode. * @param deferEnsuringVisibility Whether visibility updates are deferred. This is set when * many operations (which can effect visibility) are being performed in bulk. + * @param creating {@code true} if this is being run during ActivityStack construction. */ void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents, - boolean enteringSplitScreenMode, boolean deferEnsuringVisibility) { - final boolean creating = mWindowContainerController == null; + boolean enteringSplitScreenMode, boolean deferEnsuringVisibility, boolean creating) { final int currentMode = getWindowingMode(); final int currentOverrideMode = getOverrideWindowingMode(); final ActivityDisplay display = getDisplay(); @@ -615,9 +711,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // doesn't support split-screen mode, go ahead an dismiss split-screen and display a // warning toast about it. mService.getTaskChangeNotificationController().notifyActivityDismissingDockedStack(); - display.getSplitScreenPrimaryStack().setWindowingMode(WINDOWING_MODE_UNDEFINED, + final ActivityStack primarySplitStack = display.getSplitScreenPrimaryStack(); + primarySplitStack.setWindowingMode(WINDOWING_MODE_UNDEFINED, false /* animate */, false /* showRecents */, - false /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */); + false /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */, + primarySplitStack == this ? creating : false); } } @@ -746,7 +844,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // the new display below mTmpRect2.setEmpty(); mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop); - postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop); + setBounds(mTmpRect2.isEmpty() ? null : mTmpRect2); + activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM); if (!displayRemoved) { postReparent(); } @@ -763,31 +862,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } /** - * Updates internal state after adding to new display. - * @param activityDisplay New display to which this stack was attached. - * @param bounds Updated bounds. - */ - private void postAddToDisplay(ActivityDisplay activityDisplay, Rect bounds, boolean onTop) { - if (mDisplayId != activityDisplay.mDisplayId) { - // rotations are relative to the display, so pretend like our current rotation is - // the same as the new display so we don't try to rotate bounds. - getConfiguration().windowConfiguration.setRotation( - activityDisplay.getWindowConfiguration().getRotation()); - } - mDisplayId = activityDisplay.mDisplayId; - setBounds(bounds); - onParentChanged(); - - activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM); - if (inSplitScreenPrimaryWindowingMode()) { - // If we created a docked stack we want to resize it so it resizes all other stacks - // in the system. - mStackSupervisor.resizeDockedStackLocked( - getOverrideBounds(), null, null, null, null, PRESERVE_WINDOWS); - } - } - - /** * Updates the inner state of the stack to remove it from its current parent, so it can be * either destroyed completely or re-parented. */ @@ -812,12 +886,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } /** - * @see #getStackDockedModeBounds(Rect, Rect, Rect, boolean) + * @see #getStackDockedModeBounds(Rect, Rect, Rect, Rect) */ - void getStackDockedModeBounds(Rect currentTempTaskBounds, Rect outStackBounds, - Rect outTempTaskBounds, boolean ignoreVisibility) { - mWindowContainerController.getStackDockedModeBounds(currentTempTaskBounds, - outStackBounds, outTempTaskBounds, ignoreVisibility); + void getStackDockedModeBounds(Rect dockedBounds, Rect currentTempTaskBounds, + Rect outStackBounds, Rect outTempTaskBounds) { + mWindowContainerController.getStackDockedModeBounds(getParent().getConfiguration(), + dockedBounds, currentTempTaskBounds, + outStackBounds, outTempTaskBounds); } void prepareFreezingTaskBounds() { diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 082f5213cb5d..694e9d1d6917 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -2921,7 +2921,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final Rect otherTaskRect = new Rect(); for (int i = display.getChildCount() - 1; i >= 0; --i) { final ActivityStack current = display.getChildAt(i); - if (current.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + if (!current.inSplitScreenSecondaryWindowingMode()) { continue; } if (!current.affectedBySplitScreenResize()) { @@ -2932,12 +2932,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // interaction. continue; } - // Need to set windowing mode here before we try to get the dock bounds. - current.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - current.getStackDockedModeBounds( + current.getStackDockedModeBounds(dockedBounds, tempOtherTaskBounds /* currentTempTaskBounds */, tempRect /* outStackBounds */, - otherTaskRect /* outTempTaskBounds */, true /* ignoreVisibility */); + otherTaskRect /* outTempTaskBounds */); resizeStackLocked(current, !tempRect.isEmpty() ? tempRect : null, !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds, diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 1d0007545d78..4f01d699d248 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2430,7 +2430,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task); } stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate, showRecents, - false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */); + false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */, + false /* creating */); return windowingMode != task.getWindowingMode(); } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 4b939862904c..ab7d2597614c 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1893,12 +1893,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (mPinnedStackControllerLocked != null && !hasPinnedStack()) { mPinnedStackControllerLocked.onDisplayInfoChanged(getDisplayInfo()); } - - // The display size information is heavily dependent on the resources in the current - // configuration, so we need to reconfigure it every time the configuration changes. - // See {@link #configureDisplayPolicy}...sigh... - mService.reconfigureDisplayLocked(this); - } /** diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 6daf2f5ab59d..c37707291aed 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -227,32 +227,30 @@ public class DockedStackDividerController { return DOCKED_INVALID; } - void getHomeStackBoundsInDockedMode(Rect outBounds) { - final DisplayInfo di = mDisplayContent.getDisplayInfo(); - mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, - di.displayCutout, mTmpRect); + void getHomeStackBoundsInDockedMode(Configuration parentConfig, int dockSide, Rect outBounds) { + final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout; + final int displayWidth = parentConfig.windowConfiguration.getBounds().width(); + final int displayHeight = parentConfig.windowConfiguration.getBounds().height(); + mService.mPolicy.getStableInsetsLw(parentConfig.windowConfiguration.getRotation(), + displayWidth, displayHeight, displayCutout, mTmpRect); int dividerSize = mDividerWindowWidth - 2 * mDividerInsets; - Configuration configuration = mDisplayContent.getConfiguration(); // The offset in the left (landscape)/top (portrait) is calculated with the minimized // offset value with the divider size and any system insets in that direction. - if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { + if (parentConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top, - di.logicalWidth, di.logicalHeight); + displayWidth, displayHeight); } else { // In landscape also inset the left/right side with the statusbar height to match the // minimized size height in portrait mode. - final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility(); final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top; int left = mTmpRect.left; - int right = di.logicalWidth - mTmpRect.right; - if (stack != null) { - if (stack.getDockSide() == DOCKED_LEFT) { - left += primaryTaskWidth; - } else if (stack.getDockSide() == DOCKED_RIGHT) { - right -= primaryTaskWidth; - } + int right = displayWidth - mTmpRect.right; + if (dockSide == DOCKED_LEFT) { + left += primaryTaskWidth; + } else if (dockSide == DOCKED_RIGHT) { + right -= primaryTaskWidth; } - outBounds.set(left, 0, right, di.logicalHeight); + outBounds.set(left, 0, right, displayHeight); } } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 6627c2dc5cc3..b6609e467e85 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -21,7 +21,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.RemoteAnimationTarget.MODE_OPENING; +import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; + import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM; import static com.android.server.wm.AnimationAdapterProto.REMOTE; @@ -43,18 +45,21 @@ import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; -import android.view.InputWindowHandle; import android.view.IRecentsAnimationController; import android.view.IRecentsAnimationRunner; +import android.view.InputWindowHandle; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; + import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.InsetUtils; + import com.google.android.collect.Sets; + import java.io.PrintWriter; import java.util.ArrayList; @@ -320,7 +325,11 @@ public class RecentsAnimationController implements DeathRecipient { } // Save the minimized home height - dc.getDockedDividerController().getHomeStackBoundsInDockedMode(mMinimizedHomeBounds); + final TaskStack dockedStack = dc.getSplitScreenPrimaryStackIgnoringVisibility(); + dc.getDockedDividerController().getHomeStackBoundsInDockedMode( + dc.getConfiguration(), + dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(), + mMinimizedHomeBounds); mService.mWindowPlacerLocked.performSurfacePlacement(); } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 1baca321d01d..239971653d12 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -249,6 +249,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { dc.configureDisplayPolicy(); } + mService.reconfigureDisplayLocked(dc); + return dc; } diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java index d8e1ebfbb1b1..baeedbc1d28e 100644 --- a/services/core/java/com/android/server/wm/StackWindowController.java +++ b/services/core/java/com/android/server/wm/StackWindowController.java @@ -200,14 +200,15 @@ public class StackWindowController } /** - * @see TaskStack.getStackDockedModeBoundsLocked(Rect, Rect, Rect, boolean) + * @see TaskStack.getStackDockedModeBoundsLocked(ConfigurationContainer, Rect, Rect, Rect) */ - public void getStackDockedModeBounds(Rect currentTempTaskBounds, Rect outStackBounds, - Rect outTempTaskBounds, boolean ignoreVisibility) { + public void getStackDockedModeBounds(Configuration parentConfig, Rect dockedBounds, + Rect currentTempTaskBounds, + Rect outStackBounds, Rect outTempTaskBounds) { synchronized (mGlobalLock) { if (mContainer != null) { - mContainer.getStackDockedModeBoundsLocked(currentTempTaskBounds, outStackBounds, - outTempTaskBounds, ignoreVisibility); + mContainer.getStackDockedModeBoundsLocked(parentConfig, dockedBounds, + currentTempTaskBounds, outStackBounds, outTempTaskBounds); return; } outStackBounds.setEmpty(); @@ -372,14 +373,6 @@ public class StackWindowController mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget(); } - /** @see TaskStack.updateBoundsForConfigChange(Configuration, Configuration, Rect) */ - public boolean updateBoundsForConfigChange( - Configuration parentConfig, Configuration prevConfig, Rect outBounds) { - synchronized (mGlobalLock) { - return mContainer.updateBoundsForConfigChange(parentConfig, prevConfig, outBounds); - } - } - @Override public String toString() { return "{StackWindowController stackId=" + mStackId + "}"; diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index bd6689fae3ec..eec10aba5df2 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -452,13 +452,13 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont void removeWindowContainer() { mService.getLockTaskController().clearLockedTask(this); mWindowContainerController.removeContainer(); + mWindowContainerController = null; if (!getWindowConfiguration().persistTaskBounds()) { // Reset current bounds for task whose bounds shouldn't be persisted so it uses // default configuration the next time it launches. updateOverrideConfiguration(null); } mService.getTaskChangeNotificationController().notifyTaskRemoved(taskId); - mWindowContainerController = null; } @Override @@ -1265,7 +1265,6 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont } // Sync. with window manager - updateOverrideConfigurationFromLaunchBounds(); final AppWindowContainerController appController = r.getWindowContainerController(); if (appController != null) { // Only attempt to move in WM if the child has a controller. It is possible we haven't diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 912cb7fe449a..15de1ecec970 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -23,11 +23,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; -import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.DOCKED_BOTTOM; @@ -66,7 +63,6 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import android.view.DisplayCutout; import android.view.DisplayInfo; -import android.view.Surface; import android.view.SurfaceControl; import com.android.internal.policy.DividerSnapAlgorithm; @@ -106,12 +102,6 @@ public class TaskStack extends WindowContainer<Task> implements */ private final Rect mFullyAdjustedImeBounds = new Rect(); - // Display rotation as of the last time {@link #mBounds} was set. - private int mRotation; - - /** Density as of last time {@link #mBounds} was set. */ - private int mDensity; - private SurfaceControl mAnimationBackgroundSurface; private boolean mAnimationBackgroundSurfaceIsShown = false; @@ -291,28 +281,16 @@ public class TaskStack extends WindowContainer<Task> implements } private int setBounds(Rect existing, Rect bounds) { - int rotation = Surface.ROTATION_0; - int density = DENSITY_DPI_UNDEFINED; - WindowContainer parent = getParent(); - if (parent != null) { - parent.getBounds(mTmpRect); - rotation = mDisplayContent.getDisplayInfo().rotation; - density = mDisplayContent.getDisplayInfo().logicalDensityDpi; - } - - if (equivalentBounds(existing, bounds) && mRotation == rotation) { + if (equivalentBounds(existing, bounds)) { return BOUNDS_CHANGE_NONE; } final int result = super.setBounds(bounds); - if (mDisplayContent != null) { + if (getParent() != null) { updateAnimationBackgroundBounds(); } - mRotation = rotation; - mDensity = density; - updateAdjustedBounds(); updateSurfaceBounds(); @@ -420,78 +398,66 @@ public class TaskStack extends WindowContainer<Task> implements } /** - * Updates the passed-in {@code inOutBounds} based on how it would change when this container's - * override configuration is applied to the specified {@code parentConfig} and - * {@code prevConfig}. This gets run *after* the override configuration is updated, so it's - * safe to rely on wm hierarchy state in here (though eventually this dependence should be - * removed). + * Updates the passed-in {@code inOutBounds} based on the current state of the + * pinned controller. This gets run *after* the override configuration is updated, so it's + * safe to rely on the controller's state in here (though eventually this dependence should + * be removed). * * This does NOT modify this TaskStack's configuration. However, it does, for the time-being, - * update various controller state (pinned/docked). + * update pinned controller state. * - * @param parentConfig a parent configuration to compute relative to. - * @param prevConfig the full configuration used to produce the incoming {@code inOutBounds}. * @param inOutBounds the bounds to update (both input and output). - * @return true if bounds were updated to some non-empty value. */ - boolean updateBoundsForConfigChange( - Configuration parentConfig, Configuration prevConfig, Rect inOutBounds) { - if (getOverrideWindowingMode() == WINDOWING_MODE_PINNED) { - if ((mBoundsAnimatingRequested || mBoundsAnimating) - && !mBoundsAnimationTarget.isEmpty()) { - getFinalAnimationBounds(mTmpRect2); - } else { - mTmpRect2.set(prevConfig.windowConfiguration.getBounds()); - } - boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged( - mTmpRect2, mTmpRect3); - if (updated) { - inOutBounds.set(mTmpRect3); - - // Once we've set the bounds based on the rotation of the old bounds in the new - // orientation, clear the animation target bounds since they are obsolete, and - // cancel any currently running animations - mBoundsAnimationTarget.setEmpty(); - mBoundsAnimationSourceHintBounds.setEmpty(); - mCancelCurrentBoundsAnimation = true; - } - return updated; - } - - final int newRotation = parentConfig.windowConfiguration.getRotation(); - final int newDensity = parentConfig.densityDpi; - - if (prevConfig.windowConfiguration.getRotation() == newRotation - && prevConfig.densityDpi == newDensity) { - return false; + * @return true if bounds were updated to some non-empty value. + */ + boolean calculatePinnedBoundsForConfigChange(Rect inOutBounds) { + if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) { + getFinalAnimationBounds(mTmpRect2); + } else { + mTmpRect2.set(inOutBounds); } + boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged( + mTmpRect2, mTmpRect3); + if (updated) { + inOutBounds.set(mTmpRect3); - if (matchParentBounds()) { - return false; + // Once we've set the bounds based on the rotation of the old bounds in the new + // orientation, clear the animation target bounds since they are obsolete, and + // cancel any currently running animations + mBoundsAnimationTarget.setEmpty(); + mBoundsAnimationSourceHintBounds.setEmpty(); + mCancelCurrentBoundsAnimation = true; } + return updated; + } - mDisplayContent.rotateBounds(parentConfig.windowConfiguration.getBounds(), - prevConfig.windowConfiguration.getRotation(), newRotation, inOutBounds); - if (getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY - || getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { - boolean primary = getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; - repositionSplitScreenStackAfterRotation(parentConfig, primary, inOutBounds); - final DisplayCutout cutout = mDisplayContent.getDisplayInfo().displayCutout; - snapDockedStackAfterRotation(parentConfig, cutout, inOutBounds); - if (primary) { - final int newDockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds); - - // Update the dock create mode and clear the dock create bounds, these - // might change after a rotation and the original values will be invalid. - mService.setDockedStackCreateStateLocked( - (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP) - ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT - : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, - null); - mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); - } + /** + * Updates the passed-in {@code inOutBounds} based on the current state of the + * docked controller. This gets run *after* the override configuration is updated, so it's + * safe to rely on the controller's state in here (though eventually this dependence should + * be removed). + * + * This does NOT modify this TaskStack's configuration. However, it does, for the time-being, + * update docked controller state. + * + * @param parentConfig the parent configuration for reference. + * @param inOutBounds the bounds to update (both input and output). + */ + void calculateDockedBoundsForConfigChange(Configuration parentConfig, Rect inOutBounds) { + final boolean primary = getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; + repositionSplitScreenStackAfterRotation(parentConfig, primary, inOutBounds); + final DisplayCutout cutout = mDisplayContent.getDisplayInfo().displayCutout; + snapDockedStackAfterRotation(parentConfig, cutout, inOutBounds); + if (primary) { + final int newDockSide = getDockSide(parentConfig, inOutBounds); + // Update the dock create mode and clear the dock create bounds, these + // might change after a rotation and the original values will be invalid. + mService.setDockedStackCreateStateLocked( + (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP) + ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT + : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, + null); + mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); } - - return true; } /** @@ -721,7 +687,6 @@ public class TaskStack extends WindowContainer<Task> implements @Override public void onConfigurationChanged(Configuration newParentConfig) { final int prevWindowingMode = getWindowingMode(); - final boolean prevIsAlwaysOnTop = isAlwaysOnTop(); super.onConfigurationChanged(newParentConfig); // Only need to update surface size here since the super method will handle updating @@ -736,17 +701,14 @@ public class TaskStack extends WindowContainer<Task> implements if (prevWindowingMode != windowingMode) { mDisplayContent.onStackWindowingModeChanged(this); - updateBoundsForWindowModeChange(); - } - if (prevIsAlwaysOnTop != isAlwaysOnTop) { - // positionStackAt(POSITION_TOP, this) must be called even when always on top gets - // turned off because we need to make sure that the stack is moved from among always on - // top windows to below other always on top windows. Since the position the stack should - // be inserted into is calculated properly in - // {@link DisplayContent#findPositionForStack()} in both cases, we can just request that - // the stack is put at top here. - mDisplayContent.positionStackAt(POSITION_TOP, this, false /* includingParents */); + if (inSplitScreenSecondaryWindowingMode()) { + // When the stack is resized due to entering split screen secondary, offset the + // windows to compensate for the new stack position. + forAllWindows(w -> { + w.mWinAnimator.setOffsetPositionForStackResize(true); + }, true); + } } } @@ -803,12 +765,7 @@ public class TaskStack extends WindowContainer<Task> implements final boolean movedToNewDisplay = mDisplayContent == null; mDisplayContent = dc; - if (movedToNewDisplay) { - updateBoundsForWindowModeChange(); - } else { - updateBoundsForDisplayChanges(); - } - + updateSurfaceBounds(); if (mAnimationBackgroundSurface == null) { mAnimationBackgroundSurface = makeChildSurface(null).setColorLayer(true) .setName("animation background stackId=" + mStackId) @@ -818,95 +775,6 @@ public class TaskStack extends WindowContainer<Task> implements super.onDisplayChanged(dc); } - private void updateBoundsForWindowModeChange() { - final Rect bounds = calculateBoundsForWindowModeChange(); - - if (inSplitScreenSecondaryWindowingMode()) { - // When the stack is resized due to entering split screen secondary, offset the - // windows to compensate for the new stack position. - forAllWindows(w -> { - w.mWinAnimator.setOffsetPositionForStackResize(true); - }, true); - } - - setBoundsForWindowModeChange(bounds); - updateSurfaceBounds(); - } - - private void setBoundsForWindowModeChange(Rect bounds) { - if (mDisplayContent == null) { - return; - } - - if (bounds != null) { - setBounds(bounds); - return; - } - - updateBoundsForDisplayChanges(); - } - - private void updateBoundsForDisplayChanges() { - // Avoid setting override bounds to bounds inherited from parent if there was no override - // bounds set. - if (matchParentBounds()) { - setBounds(null); - return; - } - - mTmpRect2.set(getRawBounds()); - final int newRotation = mDisplayContent.getDisplayInfo().rotation; - final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi; - if (mRotation == newRotation && mDensity == newDensity) { - setBounds(mTmpRect2); - } - - // If the rotation or density didn't match, we'll update it in onConfigurationChanged. - } - - private Rect calculateBoundsForWindowModeChange() { - final boolean inSplitScreenPrimary = inSplitScreenPrimaryWindowingMode(); - final TaskStack splitScreenStack = - mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility(); - if (inSplitScreenPrimary || (splitScreenStack != null - && inSplitScreenSecondaryWindowingMode() && !splitScreenStack.fillsParent())) { - // The existence of a docked stack affects the size of other static stack created since - // the docked stack occupies a dedicated region on screen, but only if the dock stack is - // not fullscreen. If it's fullscreen, it means that we are in the transition of - // dismissing it, so we must not resize this stack. - final Rect bounds = new Rect(); - mDisplayContent.getBounds(mTmpRect); - mTmpRect2.setEmpty(); - if (splitScreenStack != null) { - if (inSplitScreenSecondaryWindowingMode() - && mDisplayContent.mDividerControllerLocked.isMinimizedDock() - && splitScreenStack.getTopChild() != null) { - // If the primary split screen stack is currently minimized, then don't use the - // stack bounds of the minimized stack, instead, use the temporary task bounds - // to calculate the appropriate uniminized size of any secondary split stack - // TODO: Find a cleaner way for computing new stack bounds while minimized that - // doesn't assume the primary stack's task bounds as the temp task bounds - splitScreenStack.getTopChild().getBounds(mTmpRect2); - } else { - splitScreenStack.getRawBounds(mTmpRect2); - } - } - final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode - == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; - getStackDockedModeBounds(mTmpRect, bounds, mTmpRect2, - mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); - return bounds; - } else if (inPinnedWindowingMode()) { - // Update the bounds based on any changes to the display info - getAnimationOrCurrentBounds(mTmpRect2); - if (mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged( - mTmpRect2, mTmpRect3)) { - return new Rect(mTmpRect3); - } - } - return null; - } - /** * Determines the stack and task bounds of the other stack when in docked mode. The current task * bounds is passed in but depending on the stack, the task and stack must match. Only in @@ -918,12 +786,22 @@ public class TaskStack extends WindowContainer<Task> implements * @param currentTempTaskBounds the current task bounds of the other stack * @param outStackBounds the calculated stack bounds of the other stack * @param outTempTaskBounds the calculated task bounds of the other stack - * @param ignoreVisibility ignore visibility in getting the stack bounds */ - void getStackDockedModeBoundsLocked(Rect currentTempTaskBounds, Rect outStackBounds, - Rect outTempTaskBounds, boolean ignoreVisibility) { + void getStackDockedModeBoundsLocked(Configuration parentConfig, Rect dockedBounds, + Rect currentTempTaskBounds, Rect outStackBounds, Rect outTempTaskBounds) { outTempTaskBounds.setEmpty(); + if (dockedBounds == null || dockedBounds.isEmpty()) { + // Calculate the primary docked bounds. + final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode + == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; + getStackDockedModeBounds(parentConfig, + true /* primary */, outStackBounds, dockedBounds, + mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); + return; + } + final int dockedSide = getDockSide(parentConfig, dockedBounds); + // When the home stack is resizable, should always have the same stack and task bounds if (isActivityTypeHome()) { final Task homeTask = findHomeTask(); @@ -931,7 +809,8 @@ public class TaskStack extends WindowContainer<Task> implements // Calculate the home stack bounds when in docked mode and the home stack is // resizeable. getDisplayContent().mDividerControllerLocked - .getHomeStackBoundsInDockedMode(outStackBounds); + .getHomeStackBoundsInDockedMode(parentConfig, + dockedSide, outStackBounds); } else { // Home stack isn't resizeable, so don't specify stack bounds. outStackBounds.setEmpty(); @@ -948,59 +827,37 @@ public class TaskStack extends WindowContainer<Task> implements return; } - if (!inSplitScreenWindowingMode() || mDisplayContent == null) { - outStackBounds.set(getRawBounds()); - return; - } - - final TaskStack dockedStack = - mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility(); - if (dockedStack == null) { - // Not sure why you are calling this method when there is no docked stack... - throw new IllegalStateException( - "Calling getStackDockedModeBoundsLocked() when there is no docked stack."); - } - if (!ignoreVisibility && !dockedStack.isVisible()) { - // The docked stack is being dismissed, but we caught before it finished being - // dismissed. In that case we want to treat it as if it is not occupying any space and - // let others occupy the whole display. - mDisplayContent.getBounds(outStackBounds); - return; - } - - final int dockedSide = dockedStack.getDockSide(); if (dockedSide == DOCKED_INVALID) { // Not sure how you got here...Only thing we can do is return current bounds. - Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack); + Slog.e(TAG_WM, "Failed to get valid docked side for docked stack"); outStackBounds.set(getRawBounds()); return; } - mDisplayContent.getBounds(mTmpRect); - dockedStack.getRawBounds(mTmpRect2); final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT; - getStackDockedModeBounds(mTmpRect, outStackBounds, mTmpRect2, + getStackDockedModeBounds(parentConfig, + false /* primary */, outStackBounds, dockedBounds, mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); - } /** * Outputs the bounds a stack should be given the presence of a docked stack on the display. - * @param displayRect The bounds of the display the docked stack is on. + * @param parentConfig The parent configuration. + * @param primary {@code true} if getting the primary stack bounds. * @param outBounds Output bounds that should be used for the stack. * @param dockedBounds Bounds of the docked stack. * @param dockDividerWidth We need to know the width of the divider make to the output bounds * close to the side of the dock. * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen. */ - private void getStackDockedModeBounds( - Rect displayRect, Rect outBounds, Rect dockedBounds, int dockDividerWidth, + private void getStackDockedModeBounds(Configuration parentConfig, boolean primary, + Rect outBounds, Rect dockedBounds, int dockDividerWidth, boolean dockOnTopOrLeft) { - final boolean dockedStack = inSplitScreenPrimaryWindowingMode(); + final Rect displayRect = parentConfig.windowConfiguration.getBounds(); final boolean splitHorizontally = displayRect.width() > displayRect.height(); outBounds.set(displayRect); - if (dockedStack) { + if (primary) { if (mService.mDockedStackCreateBounds != null) { outBounds.set(mService.mDockedStackCreateBounds); return; @@ -1009,14 +866,14 @@ public class TaskStack extends WindowContainer<Task> implements // The initial bounds of the docked stack when it is created about half the screen space // and its bounds can be adjusted after that. The bounds of all other stacks are // adjusted to occupy whatever screen space the docked stack isn't occupying. - final DisplayInfo di = mDisplayContent.getDisplayInfo(); - mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, - di.displayCutout, mTmpRect2); + final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout; + mService.mPolicy.getStableInsetsLw(parentConfig.windowConfiguration.getRotation(), + displayRect.width(), displayRect.height(), displayCutout, mTmpRect2); final int position = new DividerSnapAlgorithm(mService.mContext.getResources(), - di.logicalWidth, - di.logicalHeight, + displayRect.width(), + displayRect.height(), dockDividerWidth, - mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT, + parentConfig.orientation == ORIENTATION_PORTRAIT, mTmpRect2).getMiddleTarget().position; if (dockOnTopOrLeft) { @@ -1061,8 +918,11 @@ public class TaskStack extends WindowContainer<Task> implements final Rect bounds = new Rect(); final Rect tempBounds = new Rect(); - getStackDockedModeBoundsLocked(null /* currentTempTaskBounds */, bounds, tempBounds, - true /*ignoreVisibility*/); + TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility(); + Rect dockedBounds = + (dockedStack == null || dockedStack == this) ? null : dockedStack.getRawBounds(); + getStackDockedModeBoundsLocked(mDisplayContent.getConfiguration(), dockedBounds, + null /* currentTempTaskBounds */, bounds, tempBounds); getController().requestResize(bounds); } @@ -1520,9 +1380,6 @@ public class TaskStack extends WindowContainer<Task> implements } private int getDockSide(DisplayContent dc, Configuration parentConfig, Rect bounds) { - if (!inSplitScreenWindowingMode()) { - return DOCKED_INVALID; - } return dc.getDockedDividerController().getDockSide(bounds, parentConfig.windowConfiguration.getBounds(), parentConfig.orientation, parentConfig.windowConfiguration.getRotation()); diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java index 228ece5ab136..43e10f0a5f06 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -16,10 +16,6 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -377,64 +373,6 @@ public class DisplayContentTests extends WindowTestsBase { verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity); } - /** - * This test enforces that alwaysOnTop stack is placed at proper position. - */ - @Test - public void testAlwaysOnTopStackLocation() { - final TaskStack alwaysOnTopStack = createStackControllerOnStackOnDisplay( - WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer; - final Task task = createTaskInStack(alwaysOnTopStack, 0 /* userId */); - alwaysOnTopStack.setAlwaysOnTop(true); - mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack, - false /* includingParents */); - assertTrue(alwaysOnTopStack.isAlwaysOnTop()); - // Ensure always on top state is synced to the children of the stack. - assertTrue(alwaysOnTopStack.getTopChild().isAlwaysOnTop()); - assertEquals(alwaysOnTopStack, mDisplayContent.getTopStack()); - - final TaskStack pinnedStack = createStackControllerOnStackOnDisplay( - WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer; - assertEquals(pinnedStack, mDisplayContent.getPinnedStack()); - assertEquals(pinnedStack, mDisplayContent.getTopStack()); - - final TaskStack anotherAlwaysOnTopStack = createStackControllerOnStackOnDisplay( - WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer; - anotherAlwaysOnTopStack.setAlwaysOnTop(true); - mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack, - false /* includingParents */); - assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); - int topPosition = mDisplayContent.getStacks().size() - 1; - // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the - // existing alwaysOnTop stack. - assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1)); - - final TaskStack nonAlwaysOnTopStack = createStackControllerOnStackOnDisplay( - WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer; - assertEquals(mDisplayContent, nonAlwaysOnTopStack.getDisplayContent()); - topPosition = mDisplayContent.getStacks().size() - 1; - // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the - // existing other non-alwaysOnTop stacks. - assertEquals(nonAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 3)); - - anotherAlwaysOnTopStack.setAlwaysOnTop(false); - mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack, - false /* includingParents */); - assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop()); - // Ensure, when always on top is turned off for a stack, the stack is put just below all - // other always on top stacks. - assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2)); - anotherAlwaysOnTopStack.setAlwaysOnTop(true); - - // Ensure always on top state changes properly when windowing mode changes. - anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop()); - assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2)); - anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM); - assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); - assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1)); - } - @Test public void testDisplayCutout_rot0() { synchronized (mWm.getWindowManagerLock()) { 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 8119837f7c81..cb2a8ec8a274 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; @@ -31,6 +32,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -217,4 +219,61 @@ public class ActivityDisplayTests extends ActivityTestsBase { assertEquals(top, display.topRunningActivity()); assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */)); } + + /** + * This test enforces that alwaysOnTop stack is placed at proper position. + */ + @Test + public void testAlwaysOnTopStackLocation() { + final ActivityDisplay display = mSupervisor.getDefaultDisplay(); + final ActivityStack alwaysOnTopStack = display.createStack(WINDOWING_MODE_FREEFORM, + ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(alwaysOnTopStack).build(); + alwaysOnTopStack.setAlwaysOnTop(true); + display.positionChildAtTop(alwaysOnTopStack, false /* includingParents */); + assertTrue(alwaysOnTopStack.isAlwaysOnTop()); + // Ensure always on top state is synced to the children of the stack. + assertTrue(alwaysOnTopStack.getTopActivity().isAlwaysOnTop()); + assertEquals(alwaysOnTopStack, display.getTopStack()); + + final ActivityStack pinnedStack = display.createStack( + WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); + assertEquals(pinnedStack, display.getPinnedStack()); + assertEquals(pinnedStack, display.getTopStack()); + + final ActivityStack anotherAlwaysOnTopStack = display.createStack( + WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); + anotherAlwaysOnTopStack.setAlwaysOnTop(true); + display.positionChildAtTop(anotherAlwaysOnTopStack, false /* includingParents */); + assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); + int topPosition = display.getChildCount() - 1; + // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the + // existing alwaysOnTop stack. + assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1)); + + final ActivityStack nonAlwaysOnTopStack = display.createStack( + WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); + assertEquals(display, nonAlwaysOnTopStack.getDisplay()); + topPosition = display.getChildCount() - 1; + // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the + // existing other non-alwaysOnTop stacks. + assertEquals(nonAlwaysOnTopStack, display.getChildAt(topPosition - 3)); + + anotherAlwaysOnTopStack.setAlwaysOnTop(false); + display.positionChildAtTop(anotherAlwaysOnTopStack, false /* includingParents */); + assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop()); + // Ensure, when always on top is turned off for a stack, the stack is put just below all + // other always on top stacks. + assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 2)); + anotherAlwaysOnTopStack.setAlwaysOnTop(true); + + // Ensure always on top state changes properly when windowing mode changes. + anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop()); + assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 2)); + anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM); + assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop()); + assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1)); + } } 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 0a856efd96ae..caabdbd5640d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -622,7 +622,9 @@ class ActivityTestsBase { @Override protected DisplayWindowController createWindowContainerController() { - return mock(DisplayWindowController.class); + DisplayWindowController out = mock(DisplayWindowController.class); + out.mContainer = WindowTestUtils.createTestDisplayContent(); + return out; } void removeAllTasks() { @@ -812,7 +814,10 @@ class ActivityTestsBase { @Override PinnedStackWindowController createStackWindowController(int displayId, boolean onTop, Rect outBounds) { - return mock(PinnedStackWindowController.class); + PinnedStackWindowController controller = + mock(PinnedStackWindowController.class); + controller.mContainer = mock(TaskStack.class); + return controller; } }; } else { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 99ec0a9e2fcb..cf34fe7f802f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -77,6 +77,15 @@ public class WindowTestUtils { } } + /** Create a mocked default {@link DisplayContent}. */ + public static TestDisplayContent createTestDisplayContent() { + final TestDisplayContent displayContent = mock(TestDisplayContent.class); + DockedStackDividerController divider = mock(DockedStackDividerController.class); + when(displayContent.getDockedDividerController()).thenReturn(divider); + + return displayContent; + } + /** * Creates a mock instance of {@link StackWindowController}. */ |