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

Commit af3974cb authored by Mady Mellor's avatar Mady Mellor Committed by Android (Google) Code Review
Browse files

Merge "Center bubbles horizontally on large screens" into sc-v2-dev

parents 1210ca0b e7981bb2
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -696,8 +696,10 @@ public class BubbleExpandedView extends LinearLayout {
                ? mPointerHeight - mPointerOverlap
                : 0;
        final float paddingRight = (showVertically && !onLeft)
                ? mPointerHeight - mPointerOverlap : 0;
        final float paddingTop = showVertically ? 0
                ? mPointerHeight - mPointerOverlap
                : 0;
        final float paddingTop = showVertically
                ? 0
                : mPointerHeight - mPointerOverlap;
        setPadding((int) paddingLeft, (int) paddingTop, (int) paddingRight, 0);

+118 −53
Original line number Diff line number Diff line
@@ -79,14 +79,18 @@ public class BubblePositioner {

    private int mBubbleSize;
    private int mSpacingBetweenBubbles;
    private float mExpandedViewLargeScreenWidth;

    private int mExpandedViewMinHeight;
    private int mExpandedViewLargeScreenWidth;
    private int mExpandedViewLargeScreenInset;

    private int mOverflowWidth;
    private int mExpandedViewPadding;
    private int mPointerMargin;
    private int mPointerWidth;
    private int mPointerHeight;
    private int mPointerOverlap;
    private int mManageButtonHeight;
    private int mExpandedViewMinHeight;
    private int mOverflowHeight;
    private int mMinimumFlyoutWidthLargeScreen;

@@ -168,15 +172,20 @@ public class BubblePositioner {
        mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size);
        mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
        mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
        mExpandedViewLargeScreenWidth = bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT;
        mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
        mExpandedViewLargeScreenWidth = (int) (bounds.width()
                * EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT);
        mExpandedViewLargeScreenInset = mIsLargeScreen
                ? (bounds.width() - mExpandedViewLargeScreenWidth) / 2
                : mExpandedViewPadding;
        mOverflowWidth = mIsLargeScreen
                ? (int) mExpandedViewLargeScreenWidth
                ? mExpandedViewLargeScreenWidth
                : res.getDimensionPixelSize(
                        R.dimen.bubble_expanded_view_phone_landscape_overflow_width);
        mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
        mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
        mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
        mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
        mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap);
        mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height);
        mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
        mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
@@ -294,27 +303,46 @@ public class BubblePositioner {
    }

    /**
     * Calculates the left & right padding for the bubble expanded view.
     * Calculates the padding for the bubble expanded view.
     *
     * On larger screens the width of the expanded view is restricted via this padding.
     * On landscape the bubble overflow expanded view is also restricted via this padding.
     * Some specifics:
     * On large screens the width of the expanded view is restricted via this padding.
     * On phone landscape the bubble overflow expanded view is also restricted via this padding.
     * On large screens & landscape no top padding is set, the top position is set via translation.
     * On phone portrait top padding is set as the space between the tip of the pointer and the
     * bubble.
     * When the overflow is shown it doesn't have the manage button to pad out the bottom so
     * padding is added.
     */
    public int[] getExpandedViewPadding(boolean onLeft, boolean isOverflow) {
    public int[] getExpandedViewContainerPadding(boolean onLeft, boolean isOverflow) {
        final int pointerTotalHeight = mPointerHeight - mPointerOverlap;
        if (mIsLargeScreen) {
            // [left, top, right, bottom]
            mPaddings[0] = onLeft
                    ? mExpandedViewLargeScreenInset - pointerTotalHeight
                    : mExpandedViewLargeScreenInset;
            mPaddings[1] = 0;
            mPaddings[2] = onLeft
                    ? mExpandedViewLargeScreenInset
                    : mExpandedViewLargeScreenInset - pointerTotalHeight;
            // Overflow doesn't show manage button / get padding from it so add padding here for it
            mPaddings[3] = isOverflow ? mExpandedViewPadding : 0;
            return mPaddings;
        } else {
            int leftPadding = mInsets.left + mExpandedViewPadding;
            int rightPadding = mInsets.right + mExpandedViewPadding;
        final boolean isLargeOrOverflow = mIsLargeScreen || isOverflow;
            final float expandedViewWidth = isOverflow
                    ? mOverflowWidth
                    : mExpandedViewLargeScreenWidth;
            if (showBubblesVertically()) {
                if (!onLeft) {
                rightPadding += mBubbleSize - mPointerHeight;
                leftPadding += isLargeOrOverflow
                    rightPadding += mBubbleSize - pointerTotalHeight;
                    leftPadding += isOverflow
                            ? (mPositionRect.width() - rightPadding - expandedViewWidth)
                            : 0;
                } else {
                leftPadding += mBubbleSize - mPointerHeight;
                rightPadding += isLargeOrOverflow
                    leftPadding += mBubbleSize - pointerTotalHeight;
                    rightPadding += isOverflow
                            ? (mPositionRect.width() - leftPadding - expandedViewWidth)
                            : 0;
                }
@@ -326,34 +354,42 @@ public class BubblePositioner {
            mPaddings[3] = 0;
            return mPaddings;
        }
    }

    /** Gets the y position of the expanded view if it was top-aligned. */
    private float getExpandedViewYTopAligned() {
        final int top = getAvailableRect().top;
        if (showBubblesVertically()) {
            return top - mPointerWidth;
            return top - mPointerWidth + mExpandedViewPadding;
        } else {
            return top + mBubbleSize + mPointerMargin;
        }
    }

    /** The maximum height the expanded view can be. */
    public float getExpandedBubblesY() {
        return getAvailableRect().top + mExpandedViewPadding;
    }

    /**
     * Calculate the maximum height the expanded view can be depending on where it's placed on
     * the screen and the size of the elements around it (e.g. padding, pointer, manage button).
     */
    public int getMaxExpandedViewHeight(boolean isOverflow) {
        // Subtract top insets because availableRect.height would account for that
        int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top;
        int paddingTop = showBubblesVertically()
                ? 0
                : mPointerHeight;
        int settingsHeight = isOverflow ? 0 : mManageButtonHeight;
        // Subtract pointer size because it's laid out in LinearLayout with the expanded view.
        int pointerSize = showBubblesVertically()
                ? mPointerWidth
                : (mPointerHeight + mPointerMargin);
        // Subtract top insets because availableRect.height would account for that
        int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top;
        int bottomPadding = isOverflow ? mExpandedViewPadding : mManageButtonHeight;
        return getAvailableRect().height()
                - expandedContainerY
                - paddingTop
                - settingsHeight
                - pointerSize;
                - pointerSize
                - bottomPadding;
    }

    /**
@@ -362,11 +398,14 @@ public class BubblePositioner {
     */
    public float getExpandedViewHeight(BubbleViewProvider bubble) {
        boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
        if (isOverflow && showBubblesVertically() && !mIsLargeScreen) {
            // overflow in landscape on phone is max
            return MAX_HEIGHT;
        }
        float desiredHeight = isOverflow
                ? mOverflowHeight
                : ((Bubble) bubble).getDesiredHeight(mContext);
        int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
        desiredHeight = Math.max(manageButtonHeight + desiredHeight, mExpandedViewMinHeight);
        desiredHeight = Math.max(desiredHeight, mExpandedViewMinHeight);
        if (desiredHeight > getMaxExpandedViewHeight(isOverflow)) {
            return MAX_HEIGHT;
        }
@@ -391,7 +430,7 @@ public class BubblePositioner {
            return topAlignment;
        }
        // If we're here, we're showing vertically & developer has made height less than maximum.
        int manageButtonHeight = isOverflow ? 0 : mManageButtonHeight;
        int manageButtonHeight = isOverflow ? mExpandedViewPadding : mManageButtonHeight;
        float pointerPosition = getPointerPosition(bubblePosition);
        float bottomIfCentered = pointerPosition + (expandedViewHeight / 2) + manageButtonHeight;
        float topIfCentered = pointerPosition - (expandedViewHeight / 2);
@@ -426,25 +465,40 @@ public class BubblePositioner {
    }

    /**
     * When bubbles are expanded in portrait, they display at the top of the screen in a horizontal
     * row. When in landscape or on a large screen, they show at the left or right side in a
     * vertical row. This method accounts for screen orientation and will return an x or y value
     * for the position of the bubble in the row.
     * Returns the position of the bubble on-screen when the stack is expanded.
     *
     * @param index bubble index in the row.
     * @param numberOfBubbles the number of bubbles (including the overflow) in the row.
     * @return the y position of the bubble if showing vertically and the x position if showing
     * horizontally.
     * @param index the index of the bubble in the stack.
     * @param numberOfBubbles the total number of bubbles in the stack.
     * @param onLeftEdge whether the stack would rest on the left edge of the screen when collapsed.
     * @return the x, y position of the bubble on-screen when the stack is expanded.
     */
    public float getBubbleXOrYForOrientation(int index, int numberOfBubbles) {
        final float positionInBar = index * (mBubbleSize + mSpacingBetweenBubbles);
    public PointF getExpandedBubbleXY(int index, int numberOfBubbles, boolean onLeftEdge) {
        final float positionInRow = index * (mBubbleSize + mSpacingBetweenBubbles);
        final float expandedStackSize = (numberOfBubbles * mBubbleSize)
                + ((numberOfBubbles - 1) * mSpacingBetweenBubbles);
        final float centerPosition = showBubblesVertically()
                ? mPositionRect.centerY()
                : mPositionRect.centerX();
        // alignment - centered on the edge
        final float rowStart = centerPosition - (expandedStackSize / 2f);
        return rowStart + positionInBar;
        float x;
        float y;
        if (showBubblesVertically()) {
            y = rowStart + positionInRow;
            int left = mIsLargeScreen
                    ? mExpandedViewLargeScreenInset - mExpandedViewPadding - mBubbleSize
                    : mPositionRect.left;
            int right = mIsLargeScreen
                    ? mPositionRect.right - mExpandedViewLargeScreenInset + mExpandedViewPadding
                    : mPositionRect.right - mBubbleSize;
            x = onLeftEdge
                    ? left
                    : right;
        } else {
            y = mPositionRect.top + mExpandedViewPadding;
            x = rowStart + positionInRow;
        }
        return new PointF(x, y);
    }

    /**
@@ -458,6 +512,17 @@ public class BubblePositioner {
        return mScreenRect.width() * FLYOUT_MAX_WIDTH_PERCENT;
    }

    /**
     * @return whether the stack is considered on the left side of the screen.
     */
    public boolean isStackOnLeft(PointF currentStackPosition) {
        if (currentStackPosition == null) {
            currentStackPosition = getRestingPosition();
        }
        final int stackCenter = (int) currentStackPosition.x + mBubbleSize / 2;
        return stackCenter < mScreenRect.width() / 2;
    }

    /**
     * Sets the stack's most recent position along the edge of the screen. This is saved when the
     * last bubble is removed, so that the stack can be restored in its previous position.
+47 −41
Original line number Diff line number Diff line
@@ -778,8 +778,8 @@ public class BubbleStackView extends FrameLayout
                floatingContentCoordinator, this::getBubbleCount, onBubbleAnimatedOut,
                this::animateShadows /* onStackAnimationFinished */, mPositioner);

        mExpandedAnimationController = new ExpandedAnimationController(
                mPositioner, mExpandedViewPadding, onBubbleAnimatedOut);
        mExpandedAnimationController = new ExpandedAnimationController(mPositioner,
                onBubbleAnimatedOut);
        mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;

        // Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
@@ -1869,28 +1869,28 @@ public class BubbleStackView extends FrameLayout
                maybeShowManageEdu();
            }
        } /* after */);

        final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
                getBubbleIndex(mExpandedBubble));
        mExpandedViewContainer.setTranslationX(0f);
        mExpandedViewContainer.setTranslationY(translationY);
        mExpandedViewContainer.setAlpha(1f);

        int index;
        if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
            index = mBubbleData.getBubbles().size();
        } else {
            index = getBubbleIndex(mExpandedBubble);
        }
        // Position of the bubble we're expanding, once it's settled in its row.
        final float bubbleWillBeAt =
                mExpandedAnimationController.getBubbleXOrYForOrientation(index);
        PointF p = mPositioner.getExpandedBubbleXY(index, mBubbleContainer.getChildCount(),
                mStackOnLeftOrWillBe);
        final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
                mPositioner.showBubblesVertically() ? p.y : p.x);
        mExpandedViewContainer.setTranslationX(0f);
        mExpandedViewContainer.setTranslationY(translationY);
        mExpandedViewContainer.setAlpha(1f);

        // How far horizontally the bubble will be animating. We'll wait a bit longer for bubbles
        // that are animating farther, so that the expanded view doesn't move as much.
        final float relevantStackPosition = showVertically
                ? mStackAnimationController.getStackPosition().y
                : mStackAnimationController.getStackPosition().x;
        final float bubbleWillBeAt = showVertically
                ? p.y
                : p.x;
        final float distanceAnimated = Math.abs(bubbleWillBeAt - relevantStackPosition);

        // Wait for the path animation target to reach its end, and add a small amount of extra time
@@ -1907,22 +1907,22 @@ public class BubbleStackView extends FrameLayout
        // Set the pivot point for the scale, so the expanded view animates out from the bubble.
        if (showVertically) {
            float pivotX;
            float pivotY = bubbleWillBeAt + mBubbleSize / 2f;
            if (mStackOnLeftOrWillBe) {
                pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding;
                pivotX = p.x + mBubbleSize + mExpandedViewPadding;
            } else {
                pivotX = mPositioner.getAvailableRect().right - mBubbleSize - mExpandedViewPadding;
                pivotX = p.x - mExpandedViewPadding;
            }
            mExpandedViewContainerMatrix.setScale(
                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                    pivotX, pivotY);
                    pivotX,
                    p.y + mBubbleSize / 2f);
        } else {
            mExpandedViewContainerMatrix.setScale(
                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                    bubbleWillBeAt + mBubbleSize / 2f,
                    translationY);
                    p.x + mBubbleSize / 2f,
                    p.y + mBubbleSize + mExpandedViewPadding);
        }
        mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);

@@ -1959,6 +1959,7 @@ public class BubbleStackView extends FrameLayout
                                mExpandedViewContainerMatrix);
                    })
                    .withEndActions(() -> {
                        mExpandedViewContainer.setAnimationMatrix(null);
                        afterExpandedViewAnimation();
                        if (mExpandedBubble != null
                                && mExpandedBubble.getExpandedView() != null) {
@@ -2009,12 +2010,11 @@ public class BubbleStackView extends FrameLayout
            index = mBubbleData.getBubbles().indexOf(mExpandedBubble);
        }
        // Value the bubble is animating from (back into the stack).
        final float expandingFromBubbleAt =
                mExpandedAnimationController.getBubbleXOrYForOrientation(index);
        final boolean showVertically = mPositioner.showBubblesVertically();
        final PointF p = mPositioner.getExpandedBubbleXY(index,
                mBubbleContainer.getChildCount(), mStackOnLeftOrWillBe);
        if (mPositioner.showBubblesVertically()) {
            float pivotX;
            float pivotY = expandingFromBubbleAt + mBubbleSize / 2f;
            float pivotY = p.y + mBubbleSize / 2f;
            if (mStackOnLeftOrWillBe) {
                pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding;
            } else {
@@ -2026,8 +2026,8 @@ public class BubbleStackView extends FrameLayout
        } else {
            mExpandedViewContainerMatrix.setScale(
                    1f, 1f,
                    expandingFromBubbleAt + mBubbleSize / 2f,
                    mPositioner.getExpandedViewY(mExpandedBubble, index));
                    p.x + mBubbleSize / 2f,
                    p.y + mBubbleSize + mExpandedViewPadding);
        }

        mExpandedViewAlphaAnimator.reverse();
@@ -2105,32 +2105,31 @@ public class BubbleStackView extends FrameLayout

        boolean isOverflow = mExpandedBubble != null
                && mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
        float expandingFromBubbleDestination =
                mExpandedAnimationController.getBubbleXOrYForOrientation(isOverflow
                        ? getBubbleCount()
                        : mBubbleData.getBubbles().indexOf(mExpandedBubble));

        PointF p = mPositioner.getExpandedBubbleXY(isOverflow
                        ? mBubbleContainer.getChildCount() - 1
                        : mBubbleData.getBubbles().indexOf(mExpandedBubble),
                    mBubbleContainer.getChildCount(), mStackOnLeftOrWillBe);
        mExpandedViewContainer.setAlpha(1f);
        mExpandedViewContainer.setVisibility(View.VISIBLE);

        if (mPositioner.showBubblesVertically()) {
            float pivotX;
            float pivotY = expandingFromBubbleDestination + mBubbleSize / 2f;
            float pivotY = p.y + mBubbleSize / 2f;
            if (mStackOnLeftOrWillBe) {
                pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding;
                pivotX = p.x + mBubbleSize + mExpandedViewPadding;
            } else {
                pivotX = mPositioner.getAvailableRect().right - mBubbleSize - mExpandedViewPadding;

                pivotX = p.x - mExpandedViewPadding;
            }
            mExpandedViewContainerMatrix.setScale(
                    0f, 0f,
                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                    pivotX, pivotY);
        } else {
            mExpandedViewContainerMatrix.setScale(
                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                    1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
                    expandingFromBubbleDestination + mBubbleSize / 2f,
                    mPositioner.getExpandedViewY(mExpandedBubble, expandingFromBubbleDestination));
                    p.x + mBubbleSize / 2f,
                    p.y + mBubbleSize + mExpandedViewPadding);
        }

        mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
@@ -2155,6 +2154,7 @@ public class BubbleStackView extends FrameLayout
                    .withEndActions(() -> {
                        mExpandedViewTemporarilyHidden = false;
                        mIsBubbleSwitchAnimating = false;
                        mExpandedViewContainer.setAnimationMatrix(null);
                    })
                    .start();
        }, 25);
@@ -2764,16 +2764,17 @@ public class BubbleStackView extends FrameLayout
        }
        boolean isOverflowExpanded = mExpandedBubble != null
                && BubbleOverflow.KEY.equals(mExpandedBubble.getKey());
        int[] paddings = mPositioner.getExpandedViewPadding(
        int[] paddings = mPositioner.getExpandedViewContainerPadding(
                mStackAnimationController.isStackOnLeftSide(), isOverflowExpanded);
        mExpandedViewContainer.setPadding(paddings[0], paddings[1], paddings[2], paddings[3]);
        if (mIsExpansionAnimating) {
            mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
        }
        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
            PointF p = mPositioner.getExpandedBubbleXY(getBubbleIndex(mExpandedBubble),
                    mBubbleContainer.getChildCount(), mStackOnLeftOrWillBe);
            mExpandedViewContainer.setTranslationY(mPositioner.getExpandedViewY(mExpandedBubble,
                    mExpandedAnimationController.getBubbleXOrYForOrientation(
                            getBubbleIndex(mExpandedBubble))));
                    mPositioner.showBubblesVertically() ? p.y : p.x));
            mExpandedViewContainer.setTranslationX(0f);
            mExpandedBubble.getExpandedView().updateView(
                    mExpandedViewContainer.getLocationOnScreen());
@@ -2856,8 +2857,13 @@ public class BubbleStackView extends FrameLayout
        if (index == -1) {
            return;
        }
        float bubblePosition = mExpandedAnimationController.getBubbleXOrYForOrientation(index);
        mExpandedBubble.getExpandedView().setPointerPosition(bubblePosition, mStackOnLeftOrWillBe);
        PointF bubblePosition = mPositioner.getExpandedBubbleXY(index,
                mBubbleContainer.getChildCount(),
                mStackOnLeftOrWillBe);
        mExpandedBubble.getExpandedView().setPointerPosition(mPositioner.showBubblesVertically()
                ? bubblePosition.y
                : bubblePosition.x,
                mStackOnLeftOrWillBe);
    }

    /**
+50 −94

File changed.

Preview size limit exceeded, changes collapsed.

+1 −4
Original line number Diff line number Diff line
@@ -305,10 +305,7 @@ public class StackAnimationController extends
        if (mLayout == null || !isStackPositionSet()) {
            return true; // Default to left, which is where it starts by default.
        }

        float stackCenter = mStackPosition.x + mBubbleSize / 2;
        float screenCenter = mLayout.getWidth() / 2;
        return stackCenter < screenCenter;
        return mPositioner.isStackOnLeft(mStackPosition);
    }

    /**
Loading