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

Commit 9ad3eb3e authored by Bryce Lee's avatar Bryce Lee
Browse files

Make LaunchingTaskPositioner stateless.

The initial design cached calculations based on the available bounds.
This required the positioner to be involved in stack lifecycle events
and tied to a particular stack.

This changelist removes these dependencies and makes the
ActivityStackSupervisor the owner.

Bug: 64144308
Test: bit FrameworksServicesTests:com.android.server.am.LaunchBoundsTests
Change-Id: I4e2df4398b0818cec71d3d90fe409012191406c0
parent dc5d89e5
Loading
Loading
Loading
Loading
+5 −17
Original line number Original line Diff line number Diff line
@@ -358,8 +358,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
    /** Run all ActivityStacks through this */
    /** Run all ActivityStacks through this */
    protected final ActivityStackSupervisor mStackSupervisor;
    protected final ActivityStackSupervisor mStackSupervisor;


    private final LaunchingTaskPositioner mTaskPositioner;

    private boolean mTopActivityOccludesKeyguard;
    private boolean mTopActivityOccludesKeyguard;
    private ActivityRecord mTopDismissingKeyguardActivity;
    private ActivityRecord mTopDismissingKeyguardActivity;


@@ -462,8 +460,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        mWindowManager = mService.mWindowManager;
        mWindowManager = mService.mWindowManager;
        mStackId = stackId;
        mStackId = stackId;
        mCurrentUser = mService.mUserController.getCurrentUserId();
        mCurrentUser = mService.mUserController.getCurrentUserId();
        mTaskPositioner = windowingMode == WINDOWING_MODE_FREEFORM
                ? new LaunchingTaskPositioner() : null;
        mTmpRect2.setEmpty();
        mTmpRect2.setEmpty();
        setWindowingMode(windowingMode);
        setWindowingMode(windowingMode);
        setActivityType(activityType);
        setActivityType(activityType);
@@ -504,11 +500,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        mDisplayId = activityDisplay.mDisplayId;
        mDisplayId = activityDisplay.mDisplayId;
        mBounds = bounds != null ? new Rect(bounds) : null;
        mBounds = bounds != null ? new Rect(bounds) : null;
        mFullscreen = mBounds == null;
        mFullscreen = mBounds == null;
        if (mTaskPositioner != null) {

            activityDisplay.mDisplay.getSize(mTmpSize);
            mTaskPositioner.setDisplaySize(mTmpSize);
            mTaskPositioner.configure(mBounds);
        }
        onParentChanged();
        onParentChanged();


        activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
        activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
@@ -536,9 +528,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            display.removeChild(this);
            display.removeChild(this);
        }
        }
        mDisplayId = INVALID_DISPLAY;
        mDisplayId = INVALID_DISPLAY;
        if (mTaskPositioner != null) {
            mTaskPositioner.reset();
        }
    }
    }


    /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
    /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
@@ -642,9 +631,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai


    void setBounds(Rect bounds) {
    void setBounds(Rect bounds) {
        mBounds = mFullscreen ? null : new Rect(bounds);
        mBounds = mFullscreen ? null : new Rect(bounds);
        if (mTaskPositioner != null) {
            mTaskPositioner.configure(bounds);
        }
    }
    }


    ActivityRecord topRunningActivityLocked() {
    ActivityRecord topRunningActivityLocked() {
@@ -5137,10 +5123,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
    }
    }


    boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) {
    boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) {
        if (mTaskPositioner == null) {
        if (!task.inFreeformWindowingMode()) {
            return false;
            return false;
        }
        }
        mTaskPositioner.updateDefaultBounds(task, mTaskHistory, windowLayout);
        mStackSupervisor.getLaunchingTaskPositioner()
                .updateDefaultBounds(task, mTaskHistory, windowLayout);

        return true;
        return true;
    }
    }


+6 −0
Original line number Original line Diff line number Diff line
@@ -293,6 +293,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
    WindowManagerService mWindowManager;
    WindowManagerService mWindowManager;
    DisplayManager mDisplayManager;
    DisplayManager mDisplayManager;


    LaunchingTaskPositioner mTaskPositioner = new LaunchingTaskPositioner();

    /** Counter for next free stack ID to use for dynamic activity stacks. */
    /** Counter for next free stack ID to use for dynamic activity stacks. */
    private int mNextFreeStackId = 0;
    private int mNextFreeStackId = 0;


@@ -2138,6 +2140,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                || mService.mSupportsFreeformWindowManagement;
                || mService.mSupportsFreeformWindowManagement;
    }
    }


    LaunchingTaskPositioner getLaunchingTaskPositioner() {
        return mTaskPositioner;
    }

    protected <T extends ActivityStack> T getStack(int stackId) {
    protected <T extends ActivityStack> T getStack(int stackId) {
        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
            final T stack = mActivityDisplays.valueAt(i).getStack(stackId);
            final T stack = mActivityDisplays.valueAt(i).getStack(stackId);
+76 −86
Original line number Original line Diff line number Diff line
@@ -64,23 +64,12 @@ class LaunchingTaskPositioner {
    private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
    private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
    private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;
    private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;


    private boolean mDefaultStartBoundsConfigurationSet = false;
    private final Rect mAvailableRect = new Rect();
    private final Rect mAvailableRect = new Rect();
    private final Rect mTmpProposal = new Rect();
    private final Rect mTmpProposal = new Rect();
    private final Rect mTmpOriginal = new Rect();
    private final Rect mTmpOriginal = new Rect();


    private int mDefaultFreeformStartX;
    private int mDefaultFreeformStartY;
    private int mDefaultFreeformWidth;
    private int mDefaultFreeformHeight;
    private int mDefaultFreeformStepHorizontal;
    private int mDefaultFreeformStepVertical;
    private final Point mDisplaySize = new Point();
    private final Point mDisplaySize = new Point();


    void setDisplaySize(Point size) {
        mDisplaySize.set(size.x, size.y);
    }

    /**
    /**
     * Tries to set task's bound in a way that it won't collide with any other task. By colliding
     * Tries to set task's bound in a way that it won't collide with any other task. By colliding
     * we mean that two tasks have left-top corner very close to each other, so one might get
     * we mean that two tasks have left-top corner very close to each other, so one might get
@@ -93,52 +82,47 @@ class LaunchingTaskPositioner {
     */
     */
    void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks,
    void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks,
            @Nullable ActivityInfo.WindowLayout windowLayout) {
            @Nullable ActivityInfo.WindowLayout windowLayout) {
        if (!mDefaultStartBoundsConfigurationSet) {
        updateAvailableRect(task, mAvailableRect);
            return;

        }
        if (windowLayout == null) {
        if (windowLayout == null) {
            positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight);
            positionCenter(task, tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
                    getFreeformHeight(mAvailableRect));
            return;
            return;
        }
        }
        int width = getFinalWidth(windowLayout);
        int width = getFinalWidth(windowLayout, mAvailableRect);
        int height = getFinalHeight(windowLayout);
        int height = getFinalHeight(windowLayout, mAvailableRect);
        int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
        int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
        int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
        int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
        if (verticalGravity == Gravity.TOP) {
        if (verticalGravity == Gravity.TOP) {
            if (horizontalGravity == Gravity.RIGHT) {
            if (horizontalGravity == Gravity.RIGHT) {
                positionTopRight(task, tasks, width, height);
                positionTopRight(task, tasks, mAvailableRect, width, height);
            } else {
            } else {
                positionTopLeft(task, tasks, width, height);
                positionTopLeft(task, tasks, mAvailableRect, width, height);
            }
            }
        } else if (verticalGravity == Gravity.BOTTOM) {
        } else if (verticalGravity == Gravity.BOTTOM) {
            if (horizontalGravity == Gravity.RIGHT) {
            if (horizontalGravity == Gravity.RIGHT) {
                positionBottomRight(task, tasks, width, height);
                positionBottomRight(task, tasks, mAvailableRect, width, height);
            } else {
            } else {
                positionBottomLeft(task, tasks, width, height);
                positionBottomLeft(task, tasks, mAvailableRect, width, height);
            }
            }
        } else {
        } else {
            // Some fancy gravity setting that we don't support yet. We just put the activity in the
            // Some fancy gravity setting that we don't support yet. We just put the activity in the
            // center.
            // center.
            Slog.w(TAG, "Received unsupported gravity: " + windowLayout.gravity
            Slog.w(TAG, "Received unsupported gravity: " + windowLayout.gravity
                    + ", positioning in the center instead.");
                    + ", positioning in the center instead.");
            positionCenter(task, tasks, width, height);
            positionCenter(task, tasks, mAvailableRect, width, height);
        }
        }
    }
    }


    void configure(Rect availableSpace) {
    private void updateAvailableRect(TaskRecord task, Rect availableRect) {
        if (availableSpace == null) {
        final Rect stackBounds = task.getStack().mBounds;
            mAvailableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);

        if (stackBounds != null) {
            availableRect.set(stackBounds);
        } else {
        } else {
            mAvailableRect.set(availableSpace);
            task.getStack().getDisplay().mDisplay.getSize(mDisplaySize);
            availableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
        }
        }

        mDefaultFreeformStartX = getFreeformStartLeft(mAvailableRect);
        mDefaultFreeformStartY = getFreeformStartTop(mAvailableRect);
        mDefaultFreeformWidth = getFreeformWidth(mAvailableRect);
        mDefaultFreeformHeight = getFreeformHeight(mAvailableRect);
        mDefaultFreeformStepHorizontal = getHorizontalStep(mAvailableRect);
        mDefaultFreeformStepVertical = getVerticalStep(mAvailableRect);
        mDefaultStartBoundsConfigurationSet = true;
    }
    }


    @VisibleForTesting
    @VisibleForTesting
@@ -173,72 +157,79 @@ class LaunchingTaskPositioner {






    private int getFinalWidth(ActivityInfo.WindowLayout windowLayout) {
    private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
        int width = mDefaultFreeformWidth;
        int width = getFreeformWidth(availableRect);
        if (windowLayout.width > 0) {
        if (windowLayout.width > 0) {
            width = windowLayout.width;
            width = windowLayout.width;
        }
        }
        if (windowLayout.widthFraction > 0) {
        if (windowLayout.widthFraction > 0) {
            width = (int) (mAvailableRect.width() * windowLayout.widthFraction);
            width = (int) (availableRect.width() * windowLayout.widthFraction);
        }
        }
        return width;
        return width;
    }
    }


    private int getFinalHeight(ActivityInfo.WindowLayout windowLayout) {
    private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
        int height = mDefaultFreeformHeight;
        int height = getFreeformHeight(availableRect);
        if (windowLayout.height > 0) {
        if (windowLayout.height > 0) {
            height = windowLayout.height;
            height = windowLayout.height;
        }
        }
        if (windowLayout.heightFraction > 0) {
        if (windowLayout.heightFraction > 0) {
            height = (int) (mAvailableRect.height() * windowLayout.heightFraction);
            height = (int) (availableRect.height() * windowLayout.heightFraction);
        }
        }
        return height;
        return height;
    }
    }


    private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
    private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks,
            int height) {
            Rect availableRect, int width, int height) {
        mTmpProposal.set(mAvailableRect.left, mAvailableRect.bottom - height,
        mTmpProposal.set(availableRect.left, availableRect.bottom - height,
                mAvailableRect.left + width, mAvailableRect.bottom);
                availableRect.left + width, availableRect.bottom);
        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
        position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
                SHIFT_POLICY_HORIZONTAL_RIGHT);
    }
    }


    private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
    private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks,
            int height) {
            Rect availableRect, int width, int height) {
        mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.bottom - height,
        mTmpProposal.set(availableRect.right - width, availableRect.bottom - height,
                mAvailableRect.right, mAvailableRect.bottom);
                availableRect.right, availableRect.bottom);
        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
        position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
                SHIFT_POLICY_HORIZONTAL_LEFT);
    }
    }


    private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
    private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks,
            int height) {
            Rect availableRect, int width, int height) {
        mTmpProposal.set(mAvailableRect.left, mAvailableRect.top,
        mTmpProposal.set(availableRect.left, availableRect.top,
                mAvailableRect.left + width, mAvailableRect.top + height);
                availableRect.left + width, availableRect.top + height);
        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
        position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
                SHIFT_POLICY_HORIZONTAL_RIGHT);
    }
    }


    private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
    private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks,
            int height) {
            Rect availableRect, int width, int height) {
        mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.top,
        mTmpProposal.set(availableRect.right - width, availableRect.top,
                mAvailableRect.right, mAvailableRect.top + height);
                availableRect.right, availableRect.top + height);
        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
        position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
                SHIFT_POLICY_HORIZONTAL_LEFT);
    }
    }


    private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
    private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks,
            int height) {
            Rect availableRect, int width, int height) {
        mTmpProposal.set(mDefaultFreeformStartX, mDefaultFreeformStartY,
        final int defaultFreeformLeft = getFreeformStartLeft(availableRect);
                mDefaultFreeformStartX + width, mDefaultFreeformStartY + height);
        final int defaultFreeformTop = getFreeformStartTop(availableRect);
        position(task, tasks, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN);
        mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop,
                defaultFreeformLeft + width, defaultFreeformTop + height);
        position(task, tasks, availableRect, mTmpProposal, ALLOW_RESTART,
                SHIFT_POLICY_DIAGONAL_DOWN);
    }
    }


    private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect proposal,
    private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect availableRect,
            boolean allowRestart, int shiftPolicy) {
            Rect proposal, boolean allowRestart, int shiftPolicy) {
        mTmpOriginal.set(proposal);
        mTmpOriginal.set(proposal);
        boolean restarted = false;
        boolean restarted = false;
        while (boundsConflict(proposal, tasks)) {
        while (boundsConflict(proposal, tasks)) {
            // Unfortunately there is already a task at that spot, so we need to look for some
            // Unfortunately there is already a task at that spot, so we need to look for some
            // other place.
            // other place.
            shiftStartingPoint(proposal, shiftPolicy);
            shiftStartingPoint(proposal, availableRect, shiftPolicy);
            if (shiftedTooFar(proposal, shiftPolicy)) {
            if (shiftedTooFar(proposal, availableRect, shiftPolicy)) {
                // We don't want the task to go outside of the stack, because it won't look
                // We don't want the task to go outside of the stack, because it won't look
                // nice. Depending on the starting point we either restart, or immediately give up.
                // nice. Depending on the starting point we either restart, or immediately give up.
                if (!allowRestart) {
                if (!allowRestart) {
@@ -247,13 +238,13 @@ class LaunchingTaskPositioner {
                }
                }
                // We must have started not from the top. Let's restart from there because there
                // We must have started not from the top. Let's restart from there because there
                // might be some space there.
                // might be some space there.
                proposal.set(mAvailableRect.left, mAvailableRect.top,
                proposal.set(availableRect.left, availableRect.top,
                        mAvailableRect.left + proposal.width(),
                        availableRect.left + proposal.width(),
                        mAvailableRect.top + proposal.height());
                        availableRect.top + proposal.height());
                restarted = true;
                restarted = true;
            }
            }
            if (restarted && (proposal.left > mDefaultFreeformStartX
            if (restarted && (proposal.left > getFreeformStartLeft(availableRect)
                    || proposal.top > mDefaultFreeformStartY)) {
                    || proposal.top > getFreeformStartTop(availableRect))) {
                // If we restarted and crossed the initial position, let's not struggle anymore.
                // If we restarted and crossed the initial position, let's not struggle anymore.
                // The user already must have ton of tasks visible, we can just smack the new
                // The user already must have ton of tasks visible, we can just smack the new
                // one in the center.
                // one in the center.
@@ -264,27 +255,30 @@ class LaunchingTaskPositioner {
        task.updateOverrideConfiguration(proposal);
        task.updateOverrideConfiguration(proposal);
    }
    }


    private boolean shiftedTooFar(Rect start, int shiftPolicy) {
    private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) {
        switch (shiftPolicy) {
        switch (shiftPolicy) {
            case SHIFT_POLICY_HORIZONTAL_LEFT:
            case SHIFT_POLICY_HORIZONTAL_LEFT:
                return start.left < mAvailableRect.left;
                return start.left < availableRect.left;
            case SHIFT_POLICY_HORIZONTAL_RIGHT:
            case SHIFT_POLICY_HORIZONTAL_RIGHT:
                return start.right > mAvailableRect.right;
                return start.right > availableRect.right;
            default: // SHIFT_POLICY_DIAGONAL_DOWN
            default: // SHIFT_POLICY_DIAGONAL_DOWN
                return start.right > mAvailableRect.right || start.bottom > mAvailableRect.bottom;
                return start.right > availableRect.right || start.bottom > availableRect.bottom;
        }
        }
    }
    }


    private void shiftStartingPoint(Rect posposal, int shiftPolicy) {
    private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) {
        final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect);
        final int defaultFreeformStepVertical = getVerticalStep(availableRect);

        switch (shiftPolicy) {
        switch (shiftPolicy) {
            case SHIFT_POLICY_HORIZONTAL_LEFT:
            case SHIFT_POLICY_HORIZONTAL_LEFT:
                posposal.offset(-mDefaultFreeformStepHorizontal, 0);
                posposal.offset(-defaultFreeformStepHorizontal, 0);
                break;
                break;
            case SHIFT_POLICY_HORIZONTAL_RIGHT:
            case SHIFT_POLICY_HORIZONTAL_RIGHT:
                posposal.offset(mDefaultFreeformStepHorizontal, 0);
                posposal.offset(defaultFreeformStepHorizontal, 0);
                break;
                break;
            default: // SHIFT_POLICY_DIAGONAL_DOWN:
            default: // SHIFT_POLICY_DIAGONAL_DOWN:
                posposal.offset(mDefaultFreeformStepHorizontal, mDefaultFreeformStepVertical);
                posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical);
                break;
                break;
        }
        }
    }
    }
@@ -323,8 +317,4 @@ class LaunchingTaskPositioner {
        return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
        return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
                && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
                && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
    }
    }

    void reset() {
        mDefaultStartBoundsConfigurationSet = false;
    }
}
}