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

Commit 61d5d569 authored by Lyn Han's avatar Lyn Han Committed by Mady Mellor
Browse files

Translate the dot to correct position

- Pipes the dotCenter location through to BubbleFlyoutView
- Uses the dotCenter location to animate the flyout so that the location
  doesn't jump positions
- Updates the size that BubbleIconFactory uses to be the bitmap size
  rather than bubble size (this makes the badges look closer to launcher
  sizing)

Test: atest SystemUITests
Test: manual 1) have no bubbles, post a bubble, observe flyout animation
             2) move stack to opposite side, post a bubble, observe
	        flyout animation
	     Repeat above with the different icon shapes
Bug: 129158983
Change-Id: I1dc6fb1445f554e18603275f58072a337beba0b0
parent d9ceae05
Loading
Loading
Loading
Loading
+21 −5
Original line number Diff line number Diff line
@@ -93,19 +93,19 @@ public class BadgedImageView extends ImageView {
    /**
     * Set whether the dot should appear on left or right side of the view.
     */
    public void setDotPosition(boolean onLeft) {
    void setDotOnLeft(boolean onLeft) {
        mOnLeft = onLeft;
        invalidate();
    }

    public boolean getDotPosition() {
    boolean getDotOnLeft() {
        return mOnLeft;
    }

    /**
     * Set whether the dot should show or not.
     */
    public void setShowDot(boolean showDot) {
    void setShowDot(boolean showDot) {
        mShowDot = showDot;
        invalidate();
    }
@@ -113,7 +113,7 @@ public class BadgedImageView extends ImageView {
    /**
     * @return whether the dot is being displayed.
     */
    public boolean isShowingDot() {
    boolean isShowingDot() {
        return mShowDot;
    }

@@ -136,8 +136,24 @@ public class BadgedImageView extends ImageView {
    /**
     * How big the dot should be, fraction from 0 to 1.
     */
    public void setDotScale(float fraction) {
    void setDotScale(float fraction) {
        mDotScale = fraction;
        invalidate();
    }

    /**
     * Return dot position relative to bubble view container bounds.
     */
    float[] getDotCenter() {
        float[] dotPosition;
        if (mOnLeft) {
            dotPosition = mDotRenderer.getLeftDotPosition();
        } else {
            dotPosition =  mDotRenderer.getRightDotPosition();
        }
        getDrawingRect(mTempBounds);
        float dotCenterX = mTempBounds.width() * dotPosition[0];
        float dotCenterY = mTempBounds.height() * dotPosition[1];
        return new float[]{dotCenterX, dotCenterY};
    }
}
+17 −20
Original line number Diff line number Diff line
@@ -124,16 +124,15 @@ public class BubbleFlyoutView extends FrameLayout {
    private float mBgTranslationX;
    private float mBgTranslationY;

    private float[] mDotCenter;

    /** The flyout's X translation when at rest (not animating or dragging). */
    private float mRestingTranslationX = 0f;

    /** The badge sizes are defined as percentages of the app icon size. Same value as Launcher3. */
    private static final float SIZE_PERCENTAGE = 0.228f;

    /** Extra scale down of the dot provides room for error in estimating actual dot location.
     * At the end of the flyout-to-dot animation, wherever the small dot ends up, its disappearance
     * and the appearance of the larger real dot forms a cohesive animation.*/
    private static final float DOT_SCALE = 0.8f;
    private static final float DOT_SCALE = 1f;

    /** Callback to run when the flyout is hidden. */
    @Nullable private Runnable mOnHide;
@@ -207,10 +206,11 @@ public class BubbleFlyoutView extends FrameLayout {
    void setupFlyoutStartingAsDot(
            CharSequence updateMessage, PointF stackPos, float parentWidth,
            boolean arrowPointingLeft, int dotColor, @Nullable Runnable onLayoutComplete,
            @Nullable Runnable onHide) {
            @Nullable Runnable onHide, float[] dotCenter) {
        mArrowPointingLeft = arrowPointingLeft;
        mDotColor = dotColor;
        mOnHide = onHide;
        mDotCenter = dotCenter;

        setCollapsePercent(1f);

@@ -223,14 +223,16 @@ public class BubbleFlyoutView extends FrameLayout {

        // Wait for the TextView to lay out so we know its line count.
        post(() -> {
            float restingTranslationY;
            // Multi line flyouts get top-aligned to the bubble.
            if (mFlyoutText.getLineCount() > 1) {
                setTranslationY(stackPos.y + mBubbleIconTopPadding);
                restingTranslationY = stackPos.y + mBubbleIconTopPadding;
            } else {
                // Single line flyouts are vertically centered with respect to the bubble.
                setTranslationY(
                        stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f);
                restingTranslationY =
                        stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
            }
            setTranslationY(restingTranslationY);

            // Calculate the translation required to position the flyout next to the bubble stack,
            // with the desired padding.
@@ -244,19 +246,14 @@ public class BubbleFlyoutView extends FrameLayout {
            mFlyoutToDotHeightDelta = getHeight() - mNewDotSize;

            // Calculate the translation values needed to be in the correct 'new dot' position.
            final float distanceFromFlyoutLeftToDotCenterX =
                    mFlyoutSpaceFromBubble + mBubbleIconTopPadding + mOriginalDotSize / 2;
            if (mArrowPointingLeft) {
                mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX - (mOriginalDotSize / 2);
            } else {
                mTranslationXWhenDot =
                        getWidth() + distanceFromFlyoutLeftToDotCenterX - (mOriginalDotSize / 2);
            }
            mTranslationYWhenDot =
                    getHeight() / 2f
                            - mBubbleSize / 2f
                            + mOriginalDotSize / 2;
            final float dotPositionX = stackPos.x + mDotCenter[0] - (mOriginalDotSize / 2f);
            final float dotPositionY = stackPos.y + mDotCenter[1] - (mOriginalDotSize / 2f);

            final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
            final float distanceFromLayoutTopToDotCenterY = restingTranslationY - dotPositionY;

            mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX;
            mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY;
            if (onLayoutComplete != null) {
                onLayoutComplete.run();
            }
+4 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.bubbles;
import android.content.Context;

import com.android.launcher3.icons.BaseIconFactory;
import com.android.systemui.R;

/**
 * Factory for creating normalized bubble icons.
@@ -25,8 +26,9 @@ import com.android.launcher3.icons.BaseIconFactory;
 * so there is no need to manage a pool across multiple threads.
 */
public class BubbleIconFactory extends BaseIconFactory {
    protected BubbleIconFactory(Context context, int iconBitmapSize) {
        super(context, context.getResources().getConfiguration().densityDpi, iconBitmapSize);
    protected BubbleIconFactory(Context context) {
        super(context, context.getResources().getConfiguration().densityDpi,
                context.getResources().getDimensionPixelSize(R.dimen.individual_bubble_size));
    }

    public int getBadgeSize() {
+5 −6
Original line number Diff line number Diff line
@@ -181,7 +181,6 @@ public class BubbleStackView extends FrameLayout {
    private float mVerticalPosPercentBeforeRotation = -1;

    private int mBubbleSize;
    private int mIconBitmapSize;
    private int mBubblePaddingTop;
    private int mBubbleTouchPadding;
    private int mExpandedViewPadding;
@@ -360,8 +359,7 @@ public class BubbleStackView extends FrameLayout {
        mBubbleContainer.setClipChildren(false);
        addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));

        mIconBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size);
        mBubbleIconFactory = new BubbleIconFactory(context, mIconBitmapSize);
        mBubbleIconFactory = new BubbleIconFactory(context);

        mExpandedViewContainer = new FrameLayout(context);
        mExpandedViewContainer.setElevation(elevation);
@@ -485,7 +483,7 @@ public class BubbleStackView extends FrameLayout {
     */
    public void onThemeChanged() {
        // Recreate icon factory to update default adaptive icon scale.
        mBubbleIconFactory = new BubbleIconFactory(mContext, mIconBitmapSize);
        mBubbleIconFactory = new BubbleIconFactory(mContext);
        setUpFlyout();
        for (Bubble b: mBubbleData.getBubbles()) {
            b.getIconView().setBubbleIconFactory(mBubbleIconFactory);
@@ -1096,7 +1094,7 @@ public class BubbleStackView extends FrameLayout {
                onLeft ? -deltaX / mFlyout.getWidth() : deltaX / mFlyout.getWidth();
        mFlyout.setCollapsePercent(Math.min(1f, Math.max(0f, collapsePercent)));

        // Calculate how to translate the flyout if it has been dragged too far in etiher direction.
        // Calculate how to translate the flyout if it has been dragged too far in either direction.
        float overscrollTranslation = 0f;
        if (collapsePercent < 0f || collapsePercent > 1f) {
            // Whether we are more than 100% transitioned to the dot.
@@ -1449,7 +1447,8 @@ public class BubbleStackView extends FrameLayout {
                        mStackAnimationController.isStackOnLeftSide(),
                        bubble.getIconView().getBadgeColor(),
                        afterShow,
                        mAfterFlyoutHides);
                        mAfterFlyoutHides,
                        bubble.getIconView().getDotCenter());
                mFlyout.bringToFront();
            });
        }
+9 −4
Original line number Diff line number Diff line
@@ -166,18 +166,23 @@ public class BubbleView extends FrameLayout {

    /** Sets the position of the 'new' dot, animating it out and back in if requested. */
    void setDotPosition(boolean onLeft, boolean animate) {
        if (animate && onLeft != mBadgedImageView.getDotPosition() && !mSuppressDot) {
        if (animate && onLeft != mBadgedImageView.getDotOnLeft() && !mSuppressDot) {
            animateDot(false /* showDot */, () -> {
                mBadgedImageView.setDotPosition(onLeft);
                mBadgedImageView.setDotOnLeft(onLeft);
                animateDot(true /* showDot */, null);
            });
        } else {
            mBadgedImageView.setDotPosition(onLeft);
            mBadgedImageView.setDotOnLeft(onLeft);
        }
    }

    float[] getDotCenter() {
        float[] unscaled = mBadgedImageView.getDotCenter();
        return new float[]{unscaled[0], unscaled[1]};
    }

    boolean getDotPositionOnLeft() {
        return mBadgedImageView.getDotPosition();
        return mBadgedImageView.getDotOnLeft();
    }

    /**
Loading