Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3c45363 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Cache reference to stack objects we use a lot in WM."

parents 92ec65ee 6191149c
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -3901,8 +3901,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                final ActivityStack stack = stacks.get(stackNdx);
                pw.println();
                pw.println("  Stack #" + stack.mStackId
                        + ": type=" + activityTypeToString(getActivityType())
                        + " mode=" + windowingModeToString(getWindowingMode()));
                        + ": type=" + activityTypeToString(stack.getActivityType())
                        + " mode=" + windowingModeToString(stack.getWindowingMode()));
                pw.println("  mFullscreen=" + stack.mFullscreen);
                pw.println("  isSleeping=" + stack.shouldSleepActivities());
                pw.println("  mBounds=" + stack.mBounds);
+1 −2
Original line number Diff line number Diff line
@@ -1310,8 +1310,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree

                // Notify the pinned stack upon all windows drawn. If there was an animation in
                // progress then this signal will resume that animation.
                final TaskStack pinnedStack =
                        mDisplayContent.getStack(WINDOWING_MODE_PINNED);
                final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
                if (pinnedStack != null) {
                    pinnedStack.onAllWindowsDrawn();
                }
+183 −122
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -116,7 +117,6 @@ import static com.android.server.wm.proto.DisplayProto.WINDOW_CONTAINER;

import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.app.ActivityManager.StackId;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -296,10 +296,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    /** Window tokens that are in the process of exiting, but still on screen for animations. */
    final ArrayList<WindowToken> mExitingTokens = new ArrayList<>();

    /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
     * (except a future lockscreen TaskStack) moves to the top. */
    private TaskStack mHomeStack = null;

    /** Detect user tapping outside of current focused task bounds .*/
    TaskTapPointerEventListener mTapDetector;

@@ -979,7 +975,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo

            // In the presence of the PINNED stack or System Alert
            // windows we unfortunately can not seamlessly rotate.
            if (getStack(WINDOWING_MODE_PINNED) != null) {
            if (hasPinnedStack()) {
                mayRotateSeamlessly = false;
            }
            for (int i = 0; i < mService.mSessions.size(); i++) {
@@ -1450,20 +1446,31 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    }

    TaskStack getHomeStack() {
        if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) {
            Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
        return mTaskStackContainers.getHomeStack();
    }
        return mHomeStack;

    /**
     * @return The primary split-screen stack, but only if it is visible, and {@code null} otherwise.
     */
    TaskStack getSplitScreenPrimaryStackStack() {
        TaskStack stack = mTaskStackContainers.getSplitScreenPrimaryStackStack();
        return (stack != null && stack.isVisible()) ? stack : null;
    }

    TaskStack getStackById(int stackId) {
        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.get(i);
            if (stack.mStackId == stackId) {
                return stack;
    /**
     * Like {@link #getSplitScreenPrimaryStackStack}, but also returns the stack if it's currently
     * not visible.
     */
    TaskStack getSplitScreenPrimaryStackStackIgnoringVisibility() {
        return mTaskStackContainers.getSplitScreenPrimaryStackStack();
    }

    TaskStack getPinnedStack() {
        return mTaskStackContainers.getPinnedStack();
    }
        return null;

    private boolean hasPinnedStack() {
        return mTaskStackContainers.getPinnedStack() != null;
    }

    /**
@@ -1479,29 +1486,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     * activity type. Null is no compatible stack on the display.
     */
    TaskStack getStack(int windowingMode, int activityType) {
        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.get(i);
            if (stack.isCompatible(windowingMode, activityType)) {
                return stack;
            }
        }
        return null;
        return mTaskStackContainers.getStack(windowingMode, activityType);
    }

    @VisibleForTesting
    int getStackCount() {
        return mTaskStackContainers.size();
    TaskStack getTopStack() {
        return mTaskStackContainers.getTopStack();
    }

    @VisibleForTesting
    int getStackPosition(int windowingMode, int activityType) {
        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.get(i);
            if (stack.isCompatible(windowingMode, activityType)) {
                return i;
            }
        }
        return -1;
    void onStackWindowingModeChanged(TaskStack stack) {
        mTaskStackContainers.onStackWindowingModeChanged(stack);
    }

    @Override
@@ -1522,8 +1516,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     * bounds were updated.
     */
    void updateStackBoundsAfterConfigChange(@NonNull List<Integer> changedStackList) {
        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.get(i);
        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.getChildAt(i);
            if (stack.updateBoundsAfterConfigChange()) {
                changedStackList.add(stack.mStackId);
            }
@@ -1532,7 +1526,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        // If there was no pinned stack, we still need to notify the controller of the display info
        // update as a result of the config change.  We do this here to consolidate the flow between
        // changes when there is and is not a stack.
        if (getStack(WINDOWING_MODE_PINNED) == null) {
        if (!hasPinnedStack()) {
            mPinnedStackControllerLocked.onDisplayInfoChanged();
        }
    }
@@ -1631,8 +1625,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        mDisplay.getDisplayInfo(mDisplayInfo);
        mDisplay.getMetrics(mDisplayMetrics);

        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
            mTaskStackContainers.get(i).updateDisplayInfo(null);
        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
            mTaskStackContainers.getChildAt(i).updateDisplayInfo(null);
        }
    }

@@ -1753,24 +1747,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        out.set(mContentRect);
    }

    TaskStack addStackToDisplay(int stackId, boolean onTop, StackWindowController controller) {
    TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
        if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
                + mDisplayId);

        TaskStack stack = getStackById(stackId);
        if (stack != null) {
            // It's already attached to the display...clear mDeferRemoval, set controller, and move
            // stack to appropriate z-order on display as needed.
            stack.mDeferRemoval = false;
            stack.setController(controller);
            // We're not moving the display to front when we're adding stacks, only when
            // requested to change the position of stack explicitly.
            mTaskStackContainers.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, stack,
                    false /* includingParents */);
        } else {
            stack = new TaskStack(mService, stackId, controller);
        final TaskStack stack = new TaskStack(mService, stackId, controller);
        mTaskStackContainers.addStackToDisplay(stack, onTop);
        }

        if (stack.inSplitScreenPrimaryWindowingMode()) {
            mDividerControllerLocked.notifyDockedStackExistsChanged(true);
@@ -1789,7 +1771,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                    + " to its current displayId=" + mDisplayId);
        }

        prevDc.mTaskStackContainers.removeStackFromDisplay(stack);
        prevDc.mTaskStackContainers.removeChild(stack);
        mTaskStackContainers.addStackToDisplay(stack, onTop);
    }

@@ -1823,8 +1805,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    }

    int taskIdFromPoint(int x, int y) {
        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.get(stackNdx);
        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
            final int taskId = stack.taskIdFromPoint(x, y);
            if (taskId != -1) {
                return taskId;
@@ -1840,8 +1822,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    Task findTaskForResizePoint(int x, int y) {
        final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
        mTmpTaskForResizePointSearchResult.reset();
        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.get(stackNdx);
        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
            if (!stack.getWindowConfiguration().canResizeTask()) {
                return null;
            }
@@ -1863,8 +1845,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            mTouchExcludeRegion.set(mBaseDisplayRect);
            final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
            mTmpRect2.setEmpty();
            for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
                final TaskStack stack = mTaskStackContainers.get(stackNdx);
            for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
                stack.setTouchExcludeRegion(
                        focusedTask, delta, mTouchExcludeRegion, mContentRect, mTmpRect2);
            }
@@ -1895,7 +1877,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
        }
        // TODO(multi-display): Support docked stacks on secondary displays.
        if (mDisplayId == DEFAULT_DISPLAY && getDockedStackLocked() != null) {
        if (mDisplayId == DEFAULT_DISPLAY && getSplitScreenPrimaryStackStack() != null) {
            mDividerControllerLocked.getTouchRegion(mTmpRect);
            mTmpRegion.set(mTmpRect);
            mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
@@ -1912,8 +1894,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    }

    private void resetAnimationBackgroundAnimator() {
        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
            mTaskStackContainers.get(stackNdx).resetAnimationBackgroundAnimator();
        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
            mTaskStackContainers.getChildAt(stackNdx).resetAnimationBackgroundAnimator();
        }
    }

@@ -1984,8 +1966,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            float dividerAnimationTarget) {
        boolean updated = false;

        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.get(i);
        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.getChildAt(i);
            if (stack == null || !stack.isAdjustedForIme()) {
                continue;
            }
@@ -2013,8 +1995,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo

    boolean clearImeAdjustAnimation() {
        boolean changed = false;
        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.get(i);
        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.getChildAt(i);
            if (stack != null && stack.isAdjustedForIme()) {
                stack.resetAdjustedForIme(true /* adjustBoundsNow */);
                changed  = true;
@@ -2024,8 +2006,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    }

    void beginImeAdjustAnimation() {
        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.get(i);
        for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
            final TaskStack stack = mTaskStackContainers.getChildAt(i);
            if (stack.isVisible() && stack.isAdjustedForIme()) {
                stack.beginImeAdjustAnimation();
            }
@@ -2054,8 +2036,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        // - If IME is not visible, divider is not moved and is normal width.

        if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
            for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
                final TaskStack stack = mTaskStackContainers.get(i);
            for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
                final TaskStack stack = mTaskStackContainers.getChildAt(i);
                final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
                if (stack.isVisible() && (imeOnBottom || isDockedOnBottom)
                        && stack.inSplitScreenWindowingMode()) {
@@ -2067,8 +2049,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            mDividerControllerLocked.setAdjustedForIme(
                    imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
        } else {
            for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
                final TaskStack stack = mTaskStackContainers.get(i);
            for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
                final TaskStack stack = mTaskStackContainers.getChildAt(i);
                stack.resetAdjustedForIme(!dockVisible);
            }
            mDividerControllerLocked.setAdjustedForIme(
@@ -2099,8 +2081,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    }

    void prepareFreezingTaskBounds() {
        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.get(stackNdx);
        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
            stack.prepareFreezingTaskBounds();
        }
    }
@@ -2159,22 +2141,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        final long token = proto.start(fieldId);
        super.writeToProto(proto, WINDOW_CONTAINER);
        proto.write(ID, mDisplayId);
        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.get(stackNdx);
        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
            stack.writeToProto(proto, STACKS);
        }
        mDividerControllerLocked.writeToProto(proto, DOCKED_STACK_DIVIDER_CONTROLLER);
        mPinnedStackControllerLocked.writeToProto(proto, PINNED_STACK_CONTROLLER);
        for (int i = mAboveAppWindowsContainers.size() - 1; i >= 0; --i) {
            final WindowToken windowToken = mAboveAppWindowsContainers.get(i);
        for (int i = mAboveAppWindowsContainers.getChildCount() - 1; i >= 0; --i) {
            final WindowToken windowToken = mAboveAppWindowsContainers.getChildAt(i);
            windowToken.writeToProto(proto, ABOVE_APP_WINDOWS);
        }
        for (int i = mBelowAppWindowsContainers.size() - 1; i >= 0; --i) {
            final WindowToken windowToken = mBelowAppWindowsContainers.get(i);
        for (int i = mBelowAppWindowsContainers.getChildCount() - 1; i >= 0; --i) {
            final WindowToken windowToken = mBelowAppWindowsContainers.getChildAt(i);
            windowToken.writeToProto(proto, BELOW_APP_WINDOWS);
        }
        for (int i = mImeWindowsContainers.size() - 1; i >= 0; --i) {
            final WindowToken windowToken = mImeWindowsContainers.get(i);
        for (int i = mImeWindowsContainers.getChildCount() - 1; i >= 0; --i) {
            final WindowToken windowToken = mImeWindowsContainers.getChildAt(i);
            windowToken.writeToProto(proto, IME_WINDOWS);
        }
        proto.write(DPI, mBaseDisplayDensity);
@@ -2220,8 +2202,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo

        pw.println();
        pw.println(prefix + "Application tokens in top down Z order:");
        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.get(stackNdx);
        for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
            stack.dump(prefix + "  ", pw);
        }

@@ -2239,6 +2221,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        }
        pw.println();
        mDimLayerController.dump(prefix, pw);
        pw.println();

        // Dump stack references
        final TaskStack homeStack = getHomeStack();
        if (homeStack != null) {
            pw.println(prefix + "homeStack=" + homeStack.getName());
        }
        final TaskStack pinnedStack = getPinnedStack();
        if (pinnedStack != null) {
            pw.println(prefix + "pinnedStack=" + pinnedStack.getName());
        }
        final TaskStack splitScreenPrimaryStack = getSplitScreenPrimaryStackStack();
        if (splitScreenPrimaryStack != null) {
            pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName());
        }

        pw.println();
        mDividerControllerLocked.dump(prefix, pw);
        pw.println();
@@ -2265,22 +2263,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        return stack != null && stack.isVisible();
    }

    /**
     * @return The docked stack, but only if it is visible, and {@code null} otherwise.
     */
    TaskStack getDockedStackLocked() {
        final TaskStack stack = getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
        return (stack != null && stack.isVisible()) ? stack : null;
    }

    /**
     * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not
     * visible.
     */
    TaskStack getDockedStackIgnoringVisibility() {
        return getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
    }

    /** Find the visible, touch-deliverable window under the given point */
    WindowState getTouchableWinAtPointLocked(float xf, float yf) {
        final int x = (int) xf;
@@ -3357,14 +3339,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     */
    static class DisplayChildWindowContainer<E extends WindowContainer> extends WindowContainer<E> {

        int size() {
            return mChildren.size();
        }

        E get(int index) {
            return mChildren.get(index);
        }

        @Override
        boolean fillsParent() {
            return true;
@@ -3382,25 +3356,108 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     */
    private final class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> {

        // Cached reference to some special stacks we tend to get a lot so we don't need to loop
        // through the list to find them.
        private TaskStack mHomeStack = null;
        private TaskStack mPinnedStack = null;
        private TaskStack mSplitScreenPrimaryStack = null;

        /**
         * 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.
         */
        TaskStack getStack(int windowingMode, int activityType) {
            if (activityType == ACTIVITY_TYPE_HOME) {
                return mHomeStack;
            }
            if (windowingMode == WINDOWING_MODE_PINNED) {
                return mPinnedStack;
            } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                return mSplitScreenPrimaryStack;
            }
            for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
                final TaskStack stack = mTaskStackContainers.getChildAt(i);
                if (stack.isCompatible(windowingMode, activityType)) {
                    return stack;
                }
            }
            return null;
        }

        @VisibleForTesting
        TaskStack getTopStack() {
            return mTaskStackContainers.getChildCount() > 0
                    ? mTaskStackContainers.getChildAt(mTaskStackContainers.getChildCount() - 1) : null;
        }

        TaskStack getHomeStack() {
            if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) {
                Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
            }
            return mHomeStack;
        }

        TaskStack getPinnedStack() {
            return mPinnedStack;
        }

        TaskStack getSplitScreenPrimaryStackStack() {
            return mSplitScreenPrimaryStack;
        }

        /**
         * Adds the stack to this container.
         * @see WindowManagerService#addStackToDisplay(int, int, boolean)
         * @see DisplayContent#createStack(int, boolean, StackWindowController)
         */
        void addStackToDisplay(TaskStack stack, boolean onTop) {
            addStackReferenceIfNeeded(stack);
            addChild(stack, onTop);
            stack.onDisplayChanged(DisplayContent.this);
        }

        void onStackWindowingModeChanged(TaskStack stack) {
            removeStackReferenceIfNeeded(stack);
            addStackReferenceIfNeeded(stack);
            if (stack == mPinnedStack && getTopStack() != stack) {
                // Looks like this stack changed windowing mode to pinned. Move it to the top.
                positionChildAt(POSITION_TOP, stack, false /* includingParents */);
            }
        }

        private void addStackReferenceIfNeeded(TaskStack stack) {
            if (stack.isActivityTypeHome()) {
                if (mHomeStack != null) {
                    throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
                    throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
                            + mHomeStack + " already exist on display=" + this + " stack=" + stack);
                }
                mHomeStack = stack;
            }
            addChild(stack, onTop);
            stack.onDisplayChanged(DisplayContent.this);
            final int windowingMode = stack.getWindowingMode();
            if (windowingMode == WINDOWING_MODE_PINNED) {
                if (mPinnedStack != null) {
                    throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack="
                            + mPinnedStack + " already exist on display=" + this
                            + " stack=" + stack);
                }
                mPinnedStack = stack;
            } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                if (mSplitScreenPrimaryStack != null) {
                    throw new IllegalArgumentException("addStackReferenceIfNeeded:"
                            + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack
                            + " already exist on display=" + this + " stack=" + stack);
                }
                mSplitScreenPrimaryStack = stack;
            }
        }

        /** Removes the stack from its container and prepare for changing the parent. */
        void removeStackFromDisplay(TaskStack stack) {
            removeChild(stack);
            stack.onRemovedFromDisplay();
        private void removeStackReferenceIfNeeded(TaskStack stack) {
            if (stack == mHomeStack) {
                mHomeStack = null;
            } else if (stack == mPinnedStack) {
                mPinnedStack = null;
            } else if (stack == mSplitScreenPrimaryStack) {
                mSplitScreenPrimaryStack = null;
            }
        }

        private void addChild(TaskStack stack, boolean toTop) {
@@ -3410,6 +3467,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            setLayoutNeeded();
        }

        @Override
        protected void removeChild(TaskStack stack) {
            super.removeChild(stack);
            removeStackReferenceIfNeeded(stack);
        }

        @Override
        boolean isOnTop() {
@@ -3452,8 +3514,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                    : requestedPosition >= topChildPosition;
            int targetPosition = requestedPosition;

            if (toTop && stack.getWindowingMode() != WINDOWING_MODE_PINNED
                    && getStack(WINDOWING_MODE_PINNED) != null) {
            if (toTop && stack.getWindowingMode() != WINDOWING_MODE_PINNED && hasPinnedStack()) {
                // The pinned stack is always the top most stack (always-on-top) when it is present.
                TaskStack topStack = mChildren.get(topChildPosition);
                if (topStack.getWindowingMode() != WINDOWING_MODE_PINNED) {
Loading