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

Commit c47e1712 authored by Lyn Han's avatar Lyn Han
Browse files

Animate overflow button

Add overflow button to mBubbleContainer
Update animation math to account for 6th child

Bug: 138116789
Fixes: 148233216
Test: manual: expand stack - button animates like normal bubbles
Test: manual: collapse stack - button animates like normal bubbles
Test: atest SystemUITests
Change-Id: I8bd575a116ab4a7443c2d682debc5c5207df1808
parent 0a20294d
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -866,10 +866,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                mOverflowCallback.run();
            }

            if (update.addedBubble != null) {
                mStackView.addBubble(update.addedBubble);
            }

            // Collapsing? Do this first before remaining steps.
            if (update.expandedChanged && !update.expanded) {
                mStackView.setExpanded(false);
@@ -916,6 +912,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                }
            }

            if (update.addedBubble != null) {
                mStackView.addBubble(update.addedBubble);
            }

            if (update.updatedBubble != null) {
                mStackView.updateBubble(update.updatedBubble);
            }
+26 −29
Original line number Diff line number Diff line
@@ -526,8 +526,13 @@ public class BubbleStackView extends FrameLayout {
                R.layout.bubble_expanded_view, this /* root */, false /* attachToRoot */);
        mOverflowExpandedView.setOverflow(true);

        mInflater.inflate(R.layout.bubble_overflow_button, this);
        mOverflowBtn = findViewById(R.id.bubble_overflow_button);
        mOverflowBtn = (ImageView) mInflater.inflate(R.layout.bubble_overflow_button,
                this /* root */,
                false /* attachToRoot */);

        mBubbleContainer.addView(mOverflowBtn, 0,
                new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));

        mOverflowBtn.setOnClickListener(v -> {
            setSelectedBubble(null);
        });
@@ -541,11 +546,13 @@ public class BubbleStackView extends FrameLayout {
        ColorDrawable bg = new ColorDrawable(bgColor);
        AdaptiveIconDrawable adaptiveIcon = new AdaptiveIconDrawable(bg, fg);
        mOverflowBtn.setImageDrawable(adaptiveIcon);

        mOverflowBtn.setVisibility(GONE);
    }

    void showExpandedViewContents(int displayId) {
        if (mOverflowExpandedView.getVirtualDisplayId() == displayId) {
        if (mOverflowExpandedView != null
                && mOverflowExpandedView.getVirtualDisplayId() == displayId) {
            mOverflowExpandedView.setContentVisibility(true);
        } else if (mExpandedBubble != null
                && mExpandedBubble.getExpandedView().getVirtualDisplayId() == displayId) {
@@ -714,7 +721,7 @@ public class BubbleStackView extends FrameLayout {
    private void updateSystemGestureExcludeRects() {
        // Exclude the region occupied by the first BubbleView in the stack
        Rect excludeZone = mSystemGestureExclusionRects.get(0);
        if (mBubbleContainer.getChildCount() > 0) {
        if (getBubbleCount() > 0) {
            View firstBubble = mBubbleContainer.getChildAt(0);
            excludeZone.set(firstBubble.getLeft(), firstBubble.getTop(), firstBubble.getRight(),
                    firstBubble.getBottom());
@@ -775,7 +782,7 @@ public class BubbleStackView extends FrameLayout {
            Log.d(TAG, "addBubble: " + bubble);
        }

        if (mBubbleContainer.getChildCount() == 0) {
        if (getBubbleCount() == 0) {
            mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
        }

@@ -817,16 +824,13 @@ public class BubbleStackView extends FrameLayout {
        }
        if (mIsExpanded) {
            if (DEBUG_BUBBLE_STACK_VIEW) {
                Log.d(TAG, "Expanded && overflow > 0. Show overflow button at");
                Log.d(TAG, "x: " + mExpandedAnimationController.getOverflowBtnLeft());
                Log.d(TAG, "y: " + mExpandedAnimationController.getExpandedY());
                Log.d(TAG, "Show overflow button.");
            }
            mOverflowBtn.setX(mExpandedAnimationController.getOverflowBtnLeft());
            mOverflowBtn.setY(mExpandedAnimationController.getExpandedY());
            mOverflowBtn.setVisibility(VISIBLE);
            mExpandedAnimationController.setShowOverflowBtn(true);
            if (apply) {
                mExpandedAnimationController.expandFromStack(null /* after */);
                mExpandedAnimationController.expandFromStack(() -> {
                    updatePointerPosition();
                } /* after */);
            }
        } else {
            if (DEBUG_BUBBLE_STACK_VIEW) {
@@ -947,7 +951,7 @@ public class BubbleStackView extends FrameLayout {
        if (mIsExpanded) {
            if (isIntersecting(mBubbleContainer, x, y)) {
                // Could be tapping or dragging a bubble while expanded
                for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
                for (int i = 0; i < getBubbleCount(); i++) {
                    BadgedImageView view = (BadgedImageView) mBubbleContainer.getChildAt(i);
                    if (isIntersecting(view, x, y)) {
                        return view;
@@ -1103,7 +1107,7 @@ public class BubbleStackView extends FrameLayout {

    /** Return the BubbleView at the given index from the bubble container. */
    public BadgedImageView getBubbleAt(int i) {
        return mBubbleContainer.getChildCount() > i
        return getBubbleCount() > i
                ? (BadgedImageView) mBubbleContainer.getChildAt(i)
                : null;
    }
@@ -1567,7 +1571,7 @@ public class BubbleStackView extends FrameLayout {
            return;
        }
        if (!mIsExpanded) {
            if (mBubbleContainer.getChildCount() > 0) {
            if (getBubbleCount() > 0) {
                mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect);
            }
            // Increase the touch target size of the bubble
@@ -1661,7 +1665,7 @@ public class BubbleStackView extends FrameLayout {

    /** Sets the appropriate Z-order and dot position for each bubble in the stack. */
    private void updateBubbleZOrdersAndDotPosition(boolean animate) {
        int bubbleCount = mBubbleContainer.getChildCount();
        int bubbleCount = getBubbleCount();
        for (int i = 0; i < bubbleCount; i++) {
            BadgedImageView bv = (BadgedImageView) mBubbleContainer.getChildAt(i);
            bv.setZ((mMaxBubbles * mBubbleElevation) - i);
@@ -1677,30 +1681,23 @@ public class BubbleStackView extends FrameLayout {
        if (expandedBubble == null) {
            return;
        }

        int index = getBubbleIndex(expandedBubble);
        if (index >= mMaxBubbles) {
            // In between state, where extra bubble will be overflowed, and new bubble added
            index = 0;
        }
        float bubbleLeftFromScreenLeft = mExpandedAnimationController.getBubbleLeft(index);
        float halfBubble = mBubbleSize / 2f;
        float bubbleCenter = bubbleLeftFromScreenLeft + halfBubble;
        // Padding might be adjusted for insets, so get it directly from the view
        bubbleCenter -= mExpandedViewContainer.getPaddingLeft();

        if (index >= mMaxBubbles) {
            Bubble first = mBubbleData.getBubbles().get(0);
            first.getExpandedView().setPointerPosition(bubbleCenter);
        } else {
        expandedBubble.getExpandedView().setPointerPosition(bubbleCenter);
    }
    }

    /**
     * @return the number of bubbles in the stack view.
     */
    public int getBubbleCount() {
        if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
            // Subtract 1 for the overflow button which is always in the bubble container.
            return mBubbleContainer.getChildCount() - 1;
        }
        return mBubbleContainer.getChildCount();
    }

@@ -1797,7 +1794,7 @@ public class BubbleStackView extends FrameLayout {
    /** For debugging only */
    List<Bubble> getBubblesOnScreen() {
        List<Bubble> bubbles = new ArrayList<>();
        for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
        for (int i = 0; i < getBubbleCount(); i++) {
            View child = mBubbleContainer.getChildAt(i);
            if (child instanceof BadgedImageView) {
                String key = ((BadgedImageView) child).getKey();
+18 −55
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import androidx.dynamicanimation.animation.SpringForce;

import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleExperimentConfig;

import com.google.android.collect.Sets;

@@ -67,8 +68,8 @@ public class ExpandedAnimationController
    private float mBubblePaddingTop;
    /** Size of each bubble. */
    private float mBubbleSizePx;
    /** Width of the overflow button. */
    private float mOverflowBtnWidth;
    /** Space between bubbles in row above expanded view. */
    private float mSpaceBetweenBubbles;
    /** Height of the status bar. */
    private float mStatusBarHeight;
    /** Size of display. */
@@ -99,7 +100,6 @@ public class ExpandedAnimationController
    private boolean mSpringingBubbleToTouch = false;

    private int mExpandedViewPadding;
    private boolean mShowOverflowBtn;

    public ExpandedAnimationController(Point displaySize, int expandedViewPadding,
            int orientation) {
@@ -153,14 +153,6 @@ public class ExpandedAnimationController
        }
    }

    public void setShowOverflowBtn(boolean showBtn) {
        mShowOverflowBtn = showBtn;
    }

    public boolean getShowOverflowBtn() {
        return mShowOverflowBtn;
    }

    /**
     * Animates the bubbles along a curved path, either to expand them along the top or collapse
     * them back into a stack.
@@ -391,11 +383,15 @@ public class ExpandedAnimationController
        mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
        mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
        mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
        mOverflowBtnWidth = mBubbleSizePx;
        mStatusBarHeight =
                res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
        mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);

        // Includes overflow button.
        float totalGapWidth = getWidthForDisplayingBubbles() - (mExpandedViewPadding * 2)
                - (mBubblesMaxRendered + 1) * mBubbleSizePx;
        mSpaceBetweenBubbles = totalGapWidth / mBubblesMaxRendered;

        // Ensure that all child views are at 1x scale, and visible, in case they were animating
        // in.
        mLayout.setVisibility(View.VISIBLE);
@@ -506,18 +502,10 @@ public class ExpandedAnimationController
     * @return Bubble left x from left edge of screen.
     */
    public float getBubbleLeft(int index) {
        final float bubbleFromRowLeft = index * (mBubbleSizePx + getSpaceBetweenBubbles());
        final float bubbleFromRowLeft = index * (mBubbleSizePx + mSpaceBetweenBubbles);
        return getRowLeft() + bubbleFromRowLeft;
    }

    public float getOverflowBtnLeft() {
        if (mLayout == null || mLayout.getChildCount() == 0) {
            return 0;
        }
        return getBubbleLeft(mLayout.getChildCount() - 1) + mBubbleSizePx
                + getSpaceBetweenBubbles();
    }

    /**
     * When expanded, the bubbles are centered in the screen. In portrait, all available space is
     * used. In landscape we have too much space so the value is restricted. This method accounts
@@ -566,38 +554,13 @@ public class ExpandedAnimationController
        if (mLayout == null) {
            return 0;
        }

        int bubbleCount = mLayout.getChildCount();

        final float totalBubbleWidth = bubbleCount * mBubbleSizePx;
        final float totalGapWidth = (bubbleCount - 1) * getSpaceBetweenBubbles();
        float rowWidth = totalGapWidth + totalBubbleWidth;
        if (mShowOverflowBtn) {
            rowWidth += getSpaceBetweenBubbles();
            rowWidth += mOverflowBtnWidth;
        }
        float rowWidth = (mLayout.getChildCount() * mBubbleSizePx)
                + ((mLayout.getChildCount() - 1) * mSpaceBetweenBubbles);

        // This display size we're using includes the size of the insets, we want the true
        // center of the display minus the notch here, which means we should include the
        // stable insets (e.g. status bar, nav bar) in this calculation.
        final float trueCenter = getAvailableScreenWidth(false /* subtractStableInsets */) / 2f;
        final float halfRow = rowWidth / 2f;
        final float rowLeft = trueCenter - halfRow;
        return rowLeft;
    }

    /**
     * @return Space between bubbles in row above expanded view.
     */
    private float getSpaceBetweenBubbles() {
        final float totalBubbleWidth = mBubblesMaxRendered * mBubbleSizePx;
        final float rowMargins = mExpandedViewPadding * 2;
        float totalGapWidth = getWidthForDisplayingBubbles() - rowMargins - totalBubbleWidth;
        if (mShowOverflowBtn) {
            totalGapWidth -= mBubbleSizePx;
        }
        final int gapCount = mBubblesMaxRendered - 1;
        final float gapWidth = totalGapWidth / gapCount;
        return gapWidth;
        return trueCenter - (rowWidth / 2f);
    }
}