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

Commit 4734fb5e authored by Josh Tsuji's avatar Josh Tsuji Committed by Android (Google) Code Review
Browse files

Merge "Remember the stack position, including across configuration changes."

parents 80f27538 875b0000
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
import com.android.systemui.bubbles.animation.StackAnimationController;
import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
@@ -173,6 +174,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    @Nullable private BubbleStackView mStackView;
    private BubbleIconFactory mBubbleIconFactory;

    /**
     * The relative position of the stack when we removed it and nulled it out. If the stack is
     * re-created, it will re-appear at this position.
     */
    @Nullable private BubbleStackView.RelativeStackPosition mPositionFromRemovedStack;

    // Tracks the id of the current (foreground) user.
    private int mCurrentUserId;
    // Saves notification keys of active bubbles when users are switched.
@@ -736,6 +743,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                    mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
                    mSysUiState, this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
                    this::hideCurrentInputMethod);
            mStackView.setStackStartPosition(mPositionFromRemovedStack);
            mStackView.addView(mBubbleScrim);
            if (mExpandListener != null) {
                mStackView.setExpandListener(mExpandListener);
@@ -806,6 +814,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        try {
            mAddedToWindowManager = false;
            if (mStackView != null) {
                mPositionFromRemovedStack = mStackView.getRelativeStackPosition();
                mWindowManager.removeView(mStackView);
                mStackView.removeView(mBubbleScrim);
                mStackView = null;
+60 −19
Original line number Diff line number Diff line
@@ -253,13 +253,8 @@ public class BubbleStackView extends FrameLayout

    /** Layout change listener that moves the stack to the nearest valid position on rotation. */
    private OnLayoutChangeListener mOrientationChangedListener;
    /** Whether the stack was on the left side of the screen prior to rotation. */
    private boolean mWasOnLeftBeforeRotation = false;
    /**
     * How far down the screen the stack was before rotation, in terms of percentage of the way down
     * the allowable region. Defaults to -1 if not set.
     */
    private float mVerticalPosPercentBeforeRotation = -1;

    @Nullable private RelativeStackPosition mRelativeStackPositionBeforeRotation;

    private int mMaxBubbles;
    private int mBubbleSize;
@@ -940,9 +935,10 @@ public class BubbleStackView extends FrameLayout
                        mExpandedViewContainer.setTranslationY(getExpandedViewY());
                        mExpandedViewContainer.setAlpha(1f);
                    }
                    if (mVerticalPosPercentBeforeRotation >= 0) {
                        mStackAnimationController.moveStackToSimilarPositionAfterRotation(
                                mWasOnLeftBeforeRotation, mVerticalPosPercentBeforeRotation);
                    if (mRelativeStackPositionBeforeRotation != null) {
                        mStackAnimationController.setStackPosition(
                                mRelativeStackPositionBeforeRotation);
                        mRelativeStackPositionBeforeRotation = null;
                    }
                    removeOnLayoutChangeListener(mOrientationChangedListener);
                };
@@ -1189,13 +1185,7 @@ public class BubbleStackView extends FrameLayout
                com.android.internal.R.dimen.status_bar_height);
        mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);

        final RectF allowablePos = mStackAnimationController.getAllowableStackPositionRegion();
        mWasOnLeftBeforeRotation = mStackAnimationController.isStackOnLeftSide();
        mVerticalPosPercentBeforeRotation =
                (mStackAnimationController.getStackPosition().y - allowablePos.top)
                        / (allowablePos.bottom - allowablePos.top);
        mVerticalPosPercentBeforeRotation =
                Math.max(0f, Math.min(1f, mVerticalPosPercentBeforeRotation));
        mRelativeStackPositionBeforeRotation = mStackAnimationController.getRelativeStackPosition();
        addOnLayoutChangeListener(mOrientationChangedListener);
        hideFlyoutImmediate();

@@ -1459,7 +1449,7 @@ public class BubbleStackView extends FrameLayout
        if (getBubbleCount() == 0 && mShouldShowUserEducation) {
            // Override the default stack position if we're showing user education.
            mStackAnimationController.setStackPosition(
                    mStackAnimationController.getDefaultStartPosition());
                    mStackAnimationController.getStartPosition());
        }

        if (getBubbleCount() == 0) {
@@ -1674,7 +1664,7 @@ public class BubbleStackView extends FrameLayout
            // Post so we have height of mUserEducationView
            mUserEducationView.post(() -> {
                final int viewHeight = mUserEducationView.getHeight();
                PointF stackPosition = mStackAnimationController.getDefaultStartPosition();
                PointF stackPosition = mStackAnimationController.getStartPosition();
                final float translationY = stackPosition.y + (mBubbleSize / 2) - (viewHeight / 2);
                mUserEducationView.setTranslationY(translationY);
                mUserEducationView.animate()
@@ -2740,10 +2730,18 @@ public class BubbleStackView extends FrameLayout
                .floatValue();
    }

    public void setStackStartPosition(RelativeStackPosition position) {
        mStackAnimationController.setStackStartPosition(position);
    }

    public PointF getStackPosition() {
        return mStackAnimationController.getStackPosition();
    }

    public RelativeStackPosition getRelativeStackPosition() {
        return mStackAnimationController.getRelativeStackPosition();
    }

    /**
     * Logs the bubble UI event.
     *
@@ -2797,4 +2795,47 @@ public class BubbleStackView extends FrameLayout
        }
        return bubbles;
    }

    /**
     * Representation of stack position that uses relative properties rather than absolute
     * coordinates. This is used to maintain similar stack positions across configuration changes.
     */
    public static class RelativeStackPosition {
        /** Whether to place the stack at the leftmost allowed position. */
        private boolean mOnLeft;

        /**
         * How far down the vertically allowed region to place the stack. For example, if the stack
         * allowed region is between y = 100 and y = 1100 and this is 0.2f, we'll place the stack at
         * 100 + (0.2f * 1000) = 300.
         */
        private float mVerticalOffsetPercent;

        public RelativeStackPosition(boolean onLeft, float verticalOffsetPercent) {
            mOnLeft = onLeft;
            mVerticalOffsetPercent = clampVerticalOffsetPercent(verticalOffsetPercent);
        }

        /** Constructs a relative position given a region and a point in that region. */
        public RelativeStackPosition(PointF position, RectF region) {
            mOnLeft = position.x < region.width() / 2;
            mVerticalOffsetPercent =
                    clampVerticalOffsetPercent((position.y - region.top) / region.height());
        }

        /** Ensures that the offset percent is between 0f and 1f. */
        private float clampVerticalOffsetPercent(float offsetPercent) {
            return Math.max(0f, Math.min(1f, offsetPercent));
        }

        /**
         * Given an allowable stack position region, returns the point within that region
         * represented by this relative position.
         */
        public PointF getAbsolutePositionInRegion(RectF region) {
            return new PointF(
                    mOnLeft ? region.left : region.right,
                    region.top + mVerticalOffsetPercent * region.height());
        }
    }
}
+47 −26
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;

import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleStackView;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.animation.PhysicsAnimator;
import com.android.systemui.util.magnetictarget.MagnetizedObject;
@@ -125,6 +126,9 @@ public class StackAnimationController extends
     */
    private Rect mAnimatingToBounds = new Rect();

    /** Initial starting location for the stack. */
    @Nullable private BubbleStackView.RelativeStackPosition mStackStartPosition;

    /** Whether or not the stack's start position has been set. */
    private boolean mStackMovedToStartPosition = false;

@@ -431,21 +435,6 @@ public class StackAnimationController extends
        return stackPos;
    }

    /**
     * Moves the stack in response to rotation. We keep it in the most similar position by keeping
     * it on the same side, and positioning it the same percentage of the way down the screen
     * (taking status bar/nav bar into account by using the allowable region's height).
     */
    public void moveStackToSimilarPositionAfterRotation(boolean wasOnLeft, float verticalPercent) {
        final RectF allowablePos = getAllowableStackPositionRegion();
        final float allowableRegionHeight = allowablePos.bottom - allowablePos.top;

        final float x = wasOnLeft ? allowablePos.left : allowablePos.right;
        final float y = (allowableRegionHeight * verticalPercent) + allowablePos.top;

        setStackPosition(new PointF(x, y));
    }

    /** Description of current animation controller state. */
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("StackAnimationController state:");
@@ -815,7 +804,7 @@ public class StackAnimationController extends
        } else {
            // When all children are removed ensure stack position is sane
            setStackPosition(mRestingStackPosition == null
                    ? getDefaultStartPosition()
                    ? getStartPosition()
                    : mRestingStackPosition);

            // Remove the stack from the coordinator since we don't have any bubbles and aren't
@@ -868,7 +857,7 @@ public class StackAnimationController extends
        mLayout.setVisibility(View.INVISIBLE);
        mLayout.post(() -> {
            setStackPosition(mRestingStackPosition == null
                    ? getDefaultStartPosition()
                    ? getStartPosition()
                    : mRestingStackPosition);
            mStackMovedToStartPosition = true;
            mLayout.setVisibility(View.VISIBLE);
@@ -938,15 +927,47 @@ public class StackAnimationController extends
        }
    }

    /** Returns the default stack position, which is on the top left. */
    public PointF getDefaultStartPosition() {
        boolean isRtl = mLayout != null
                && mLayout.getResources().getConfiguration().getLayoutDirection()
                == View.LAYOUT_DIRECTION_RTL;
        return new PointF(isRtl
                        ? getAllowableStackPositionRegion().right
                        : getAllowableStackPositionRegion().left,
                getAllowableStackPositionRegion().top + mStackStartingVerticalOffset);
    public void setStackPosition(BubbleStackView.RelativeStackPosition position) {
        setStackPosition(position.getAbsolutePositionInRegion(getAllowableStackPositionRegion()));
    }

    public BubbleStackView.RelativeStackPosition getRelativeStackPosition() {
        return new BubbleStackView.RelativeStackPosition(
                mStackPosition, getAllowableStackPositionRegion());
    }

    /**
     * Sets the starting position for the stack, where it will be located when the first bubble is
     * added.
     */
    public void setStackStartPosition(BubbleStackView.RelativeStackPosition position) {
        mStackStartPosition = position;
    }

    /**
     * Returns the starting stack position. If {@link #setStackStartPosition} was called, this will
     * return that position - otherwise, a reasonable default will be returned.
     */
    @Nullable public PointF getStartPosition() {
        if (mLayout == null) {
            return null;
        }

        if (mStackStartPosition == null) {
            // Start on the left if we're in LTR, right otherwise.
            final boolean startOnLeft =
                    mLayout.getResources().getConfiguration().getLayoutDirection()
                            != View.LAYOUT_DIRECTION_RTL;

            final float startingVerticalOffset = mLayout.getResources().getDimensionPixelOffset(
                    R.dimen.bubble_stack_starting_offset_y);

            mStackStartPosition = new BubbleStackView.RelativeStackPosition(
                    startOnLeft,
                    startingVerticalOffset / getAllowableStackPositionRegion().height());
        }

        return mStackStartPosition.getAbsolutePositionInRegion(getAllowableStackPositionRegion());
    }

    private boolean isStackPositionSet() {