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

Commit be4e591f authored by Mykola Podolian's avatar Mykola Podolian Committed by Android (Google) Code Review
Browse files

Merge "Animate bubble bar icon sizes and padding" into main

parents 788f754c 563c2101
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -45,8 +45,6 @@
        android:layout_gravity="bottom|end"
        android:layout_marginHorizontal="@dimen/transient_taskbar_bottom_margin"
        android:paddingTop="@dimen/bubblebar_pointer_visible_size"
        android:paddingEnd="@dimen/taskbar_icon_spacing"
        android:paddingStart="@dimen/taskbar_icon_spacing"
        android:visibility="gone"
        android:gravity="center"
        android:clipChildren="false"
+7 −6
Original line number Diff line number Diff line
@@ -123,22 +123,23 @@ class BubbleBarBackground(context: Context, private var backgroundHeight: Float)
        )
        // Create background path
        val backgroundPath = Path()
        val topOffset = backgroundHeight - bounds.height().toFloat()
        val radius = backgroundHeight / 2f
        val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - width)
        val right = bounds.left + (if (anchorLeft) width else bounds.width().toFloat())
        val top = bounds.top + arrowVisibleHeight
        val top = bounds.top - topOffset + arrowVisibleHeight

        val bottom = bounds.top + bounds.height().toFloat()
        backgroundPath.addRoundRect(left, top, right, bottom, radius, radius, Path.Direction.CW)
        addArrowPathIfNeeded(backgroundPath)
        addArrowPathIfNeeded(backgroundPath, topOffset)

        // Draw background.
        canvas.drawPath(backgroundPath, fillPaint)
        canvas.drawPath(backgroundPath, strokePaint)

        canvas.restore()
    }

    private fun addArrowPathIfNeeded(sourcePath: Path) {
    private fun addArrowPathIfNeeded(sourcePath: Path, topOffset: Float) {
        if (!showingArrow || arrowHeightFraction <= 0) return
        val arrowPath = Path()
        RoundedArrowDrawable.addDownPointingRoundedTriangleToPath(
@@ -153,7 +154,7 @@ class BubbleBarBackground(context: Context, private var backgroundHeight: Float)
        arrowPath.transform(pathTransform)
        // shift to arrow position
        val arrowStart = bounds.left + arrowPositionX - (arrowWidth / 2f)
        val arrowTop = (1 - arrowHeightFraction) * arrowVisibleHeight
        val arrowTop = (1 - arrowHeightFraction) * arrowVisibleHeight - topOffset
        arrowPath.offset(arrowStart, arrowTop)
        // union with rectangle
        sourcePath.op(arrowPath, Path.Op.UNION)
@@ -180,7 +181,7 @@ class BubbleBarBackground(context: Context, private var backgroundHeight: Float)
        fillPaint.colorFilter = colorFilter
    }

    fun setHeight(newHeight: Float) {
    fun setBackgroundHeight(newHeight: Float) {
        backgroundHeight = newHeight
    }

+169 −66
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -44,6 +45,7 @@ import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.R;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.util.DisplayController;
import com.android.wm.shell.Flags;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;

import java.util.List;
@@ -85,6 +87,7 @@ public class BubbleBarView extends FrameLayout {
    private static final int MAX_VISIBLE_BUBBLES_COLLAPSED = 2;
    private static final int ARROW_POSITION_ANIMATION_DURATION_MS = 200;
    private static final int WIDTH_ANIMATION_DURATION_MS = 200;
    private static final int SCALE_ANIMATION_DURATION_MS = 200;

    private static final long FADE_OUT_ANIM_ALPHA_DURATION_MS = 50L;
    private static final long FADE_OUT_ANIM_ALPHA_DELAY_MS = 50L;
@@ -135,13 +138,12 @@ public class BubbleBarView extends FrameLayout {
    private float mBubbleBarPadding;
    // The size of a bubble in the bar
    private float mIconSize;
    // The scale of bubble icons
    private float mIconScale = 1f;
    // The elevation of the bubbles within the bar
    private final float mBubbleElevation;
    private final float mDragElevation;
    private final int mPointerSize;

    private final Rect mTempBackgroundBounds = new Rect();

    // Whether the bar is expanded (i.e. the bubble activity is being displayed).
    private boolean mIsBarExpanded = false;
    // The currently selected bubble view.
@@ -162,7 +164,8 @@ public class BubbleBarView extends FrameLayout {
    /** An animator used for scaling in a new bubble to the bubble bar while expanded. */
    @Nullable
    private ValueAnimator mNewBubbleScaleInAnimator = null;

    @Nullable
    private ValueAnimator mScalePaddingAnimator;
    @Nullable
    private Animator mBubbleBarLocationAnimator = null;

@@ -217,17 +220,10 @@ public class BubbleBarView extends FrameLayout {
        setBackgroundDrawable(mBubbleBarBackground);

        mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
        mWidthAnimator.addUpdateListener(animation -> {
            updateBubblesLayoutProperties(mBubbleBarLocation);
            invalidate();
        });
        mWidthAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
        addAnimationCallBacks(mWidthAnimator,
                /* onStart= */ () -> mBubbleBarBackground.showArrow(true),
                /* onEnd= */ () -> {
                    mBubbleBarBackground.showArrow(mIsBarExpanded);
                    if (!mIsBarExpanded && mReorderRunnable != null) {
                        mReorderRunnable.run();
@@ -242,17 +238,56 @@ public class BubbleBarView extends FrameLayout {
                        mUpdateSelectedBubbleAfterCollapse.accept(firstBubble.getBubble().getKey());
                    }
                    updateWidth();
                },
                /* onUpdate= */ animator -> {
                    updateBubblesLayoutProperties(mBubbleBarLocation);
                    invalidate();
                });
    }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }

            @Override
            public void onAnimationStart(Animator animation) {
                mBubbleBarBackground.showArrow(true);
    /**
     * Animates icon sizes and spacing between icons and bubble bar borders.
     *
     * @param newIconSize         new icon size
     * @param newBubbleBarPadding spacing between icons and bubble bar borders.
     */
    public void animateBubbleBarIconSize(float newIconSize, float newBubbleBarPadding) {
        if (!isIconSizeOrPaddingUpdated(newIconSize, newBubbleBarPadding)) {
            return;
        }
        if (!Flags.animateBubbleSizeChange()) {
            setIconSizeAndPadding(newIconSize, newBubbleBarPadding);
        }
        if (mScalePaddingAnimator != null && mScalePaddingAnimator.isRunning()) {
            mScalePaddingAnimator.cancel();
        }
        ValueAnimator scalePaddingAnimator = ValueAnimator.ofFloat(0f, 1f);
        scalePaddingAnimator.setDuration(SCALE_ANIMATION_DURATION_MS);
        boolean isPaddingUpdated = isPaddingUpdated(newBubbleBarPadding);
        boolean isIconSizeUpdated = isIconSizeUpdated(newIconSize);
        float initialScale = mIconScale;
        float initialPadding = mBubbleBarPadding;
        float targetScale = newIconSize / getScaledIconSize();

        addAnimationCallBacks(scalePaddingAnimator,
                /* onStart= */ null,
                /* onEnd= */ () -> setIconSizeAndPadding(newIconSize, newBubbleBarPadding),
                /* onUpdate= */ animator -> {
                    float transitionProgress = (float) animator.getAnimatedValue();
                    if (isIconSizeUpdated) {
                        mIconScale =
                                initialScale + (targetScale - initialScale) * transitionProgress;
                    }
                    if (isPaddingUpdated) {
                        mBubbleBarPadding = initialPadding
                                + (newBubbleBarPadding - initialPadding) * transitionProgress;
                    }
                    updateBubblesLayoutProperties(mBubbleBarLocation);
                    invalidate();
                });
        scalePaddingAnimator.start();
        mScalePaddingAnimator = scalePaddingAnimator;
    }

    @Override
@@ -267,28 +302,37 @@ public class BubbleBarView extends FrameLayout {
    }

    /**
     * Sets new icon size and spacing between icons and bubble bar borders.
     * Sets new icon sizes and newBubbleBarPadding between icons and bubble bar borders.
     *
     * @param newIconSize         new icon size
     * @param spacing     spacing between icons and bubble bar borders.
     * @param newBubbleBarPadding newBubbleBarPadding between icons and bubble bar borders.
     */
    // TODO(b/335575529): animate bubble bar icons size change
    public void setIconSizeAndPadding(float newIconSize, float spacing) {
    public void setIconSizeAndPadding(float newIconSize, float newBubbleBarPadding) {
        // TODO(b/335457839): handle new bubble animation during the size change
        mBubbleBarPadding = spacing;
        if (!isIconSizeOrPaddingUpdated(newIconSize, newBubbleBarPadding)) {
            return;
        }
        mIconScale = 1f;
        mBubbleBarPadding = newBubbleBarPadding;
        mIconSize = newIconSize;
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            childView.setScaleY(mIconScale);
            childView.setScaleY(mIconScale);
            FrameLayout.LayoutParams params = (LayoutParams) childView.getLayoutParams();
            params.height = (int) mIconSize;
            params.width = (int) mIconSize;
            childView.setLayoutParams(params);
        }
        mBubbleBarBackground.setHeight(getBubbleBarExpandedHeight());
        mBubbleBarBackground.setBackgroundHeight(getBubbleBarHeight());
        updateLayoutParams();
    }

    private float getScaledIconSize() {
        return mIconSize * mIconScale;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
@@ -698,6 +742,11 @@ public class BubbleBarView extends FrameLayout {
        setLayoutParams(lp);
    }

    private float getBubbleBarHeight() {
        return mIsBarExpanded ? getBubbleBarExpandedHeight()
                : getBubbleBarCollapsedHeight();
    }

    /** @return the horizontal margin between the bubble bar and the edge of the screen. */
    int getHorizontalMargin() {
        LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -714,7 +763,10 @@ public class BubbleBarView extends FrameLayout {
        final float expandedWidth = expandedWidth();
        final float collapsedWidth = collapsedWidth();
        int bubbleCount = getChildCount();
        final float ty = (mBubbleBarBounds.height() - mIconSize) / 2f;
        float viewBottom = mBubbleBarBounds.height() + (isExpanded() ? mPointerSize : 0);
        float bubbleBarAnimatedTop = viewBottom - getBubbleBarHeight();
        // When translating X & Y the scale is ignored, so need to deduct it from the translations
        final float ty = bubbleBarAnimatedTop + mBubbleBarPadding - getScaleIconShift();
        final boolean animate = getVisibility() == VISIBLE;
        final boolean onLeft = bubbleBarLocation.isOnLeft(isLayoutRtl());
        // elevation state is opposite to widthState - when expanded all icons are flat
@@ -729,8 +781,9 @@ public class BubbleBarView extends FrameLayout {
            bv.setDragTranslationX(0f);
            bv.setOffsetX(0f);

            bv.setScaleX(mIconScale);
            bv.setScaleY(mIconScale);
            bv.setTranslationY(ty);

            // the position of the bubble when the bar is fully expanded
            final float expandedX = getExpandedBubbleTranslationX(i, bubbleCount, onLeft);
            // the position of the bubble when the bar is fully collapsed
@@ -795,21 +848,28 @@ public class BubbleBarView extends FrameLayout {
        mBubbleBarBackground.setArrowPosition(arrowPosition);
        mBubbleBarBackground.setArrowHeightFraction(widthState);
        mBubbleBarBackground.setWidth(interpolatedWidth);
        mBubbleBarBackground.setBackgroundHeight(getBubbleBarExpandedHeight());
    }

    private float getScaleIconShift() {
        return (mIconSize - getScaledIconSize()) / 2;
    }

    private float getExpandedBubbleTranslationX(int bubbleIndex, int bubbleCount, boolean onLeft) {
        if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
            return 0;
        }
        final float iconAndSpacing = mIconSize + mExpandedBarIconsSpacing;
        final float iconAndSpacing = getScaledIconSize() + mExpandedBarIconsSpacing;
        float translationX;
        if (mNewBubbleScaleInAnimator != null && mNewBubbleScaleInAnimator.isRunning()) {
            return getExpandedBubbleTranslationXDuringScaleAnimation(
            translationX = getExpandedBubbleTranslationXDuringScaleAnimation(
                    bubbleIndex, bubbleCount, onLeft);
        } else if (onLeft) {
            return (bubbleCount - bubbleIndex - 1) * iconAndSpacing;
            translationX = mBubbleBarPadding + (bubbleCount - bubbleIndex - 1) * iconAndSpacing;
        } else {
            return bubbleIndex * iconAndSpacing;
            translationX = mBubbleBarPadding + bubbleIndex * iconAndSpacing;
        }
        return translationX - getScaleIconShift();
    }

    /**
@@ -830,17 +890,17 @@ public class BubbleBarView extends FrameLayout {
            // compiler doesn't know that.
            return 0;
        }
        final float iconAndSpacing = mIconSize + mExpandedBarIconsSpacing;
        final float iconAndSpacing = getScaledIconSize() + mExpandedBarIconsSpacing;
        final float newBubbleScale = mNewBubbleScaleInAnimator.getAnimatedFraction();
        // the new bubble is scaling in from the center, so we need to adjust its translation so
        // that the distance to the adjacent bubble scales at the same rate.
        final float pivotAdjustment = -(1 - newBubbleScale) * mIconSize / 2f;
        final float pivotAdjustment = -(1 - newBubbleScale) * getScaledIconSize() / 2f;

        if (onLeft) {
            if (bubbleIndex == 0) {
                // this is the animating bubble. use scaled spacing between it and the bubble to
                // its left
                return (bubbleCount - 1) * mIconSize
                return (bubbleCount - 1) * getScaledIconSize()
                        + (bubbleCount - 2) * mExpandedBarIconsSpacing
                        + newBubbleScale * mExpandedBarIconsSpacing
                        + pivotAdjustment;
@@ -862,13 +922,16 @@ public class BubbleBarView extends FrameLayout {
        if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
            return 0;
        }
        float translationX;
        if (onLeft) {
            // Shift the first bubble only if there are more bubbles in addition to overflow
            return bubbleIndex == 0 && bubbleCount > MAX_VISIBLE_BUBBLES_COLLAPSED
                    ? mIconOverlapAmount : 0;
            translationX = mBubbleBarPadding + (
                    bubbleIndex == 0 && bubbleCount > MAX_VISIBLE_BUBBLES_COLLAPSED
                            ? mIconOverlapAmount : 0);
        } else {
            return bubbleIndex == 0 ? 0 : mIconOverlapAmount;
            translationX = mBubbleBarPadding + (bubbleIndex == 0 ? 0 : mIconOverlapAmount);
        }
        return translationX - getScaleIconShift();
    }

    /**
@@ -976,7 +1039,7 @@ public class BubbleBarView extends FrameLayout {
        final int index = indexOfChild(mSelectedBubbleView);
        final float selectedBubbleTranslationX = getExpandedBubbleTranslationX(
                index, getChildCount(), bubbleBarLocation.isOnLeft(isLayoutRtl()));
        return getPaddingStart() + selectedBubbleTranslationX + mIconSize / 2f;
        return selectedBubbleTranslationX + mIconSize / 2f;
    }

    private float arrowPositionForSelectedWhenCollapsed(BubbleBarLocation bubbleBarLocation) {
@@ -990,7 +1053,7 @@ public class BubbleBarView extends FrameLayout {
            bubblePosition = index >= MAX_VISIBLE_BUBBLES_COLLAPSED
                    ? MAX_VISIBLE_BUBBLES_COLLAPSED - 1 : index;
        }
        return getPaddingStart() + bubblePosition * (mIconOverlapAmount) + mIconSize / 2f;
        return mBubbleBarPadding + bubblePosition * (mIconOverlapAmount) + getScaledIconSize() / 2f;
    }

    @Override
@@ -1038,7 +1101,6 @@ public class BubbleBarView extends FrameLayout {
     */
    public float expandedWidth() {
        final int childCount = getChildCount();
        final int horizontalPadding = getPaddingStart() + getPaddingEnd();
        // spaces amount is less than child count by 1, or 0 if no child views
        final float totalSpace;
        final float totalIconSize;
@@ -1047,22 +1109,22 @@ public class BubbleBarView extends FrameLayout {
            // expanded, so we have at least 2 bubbles in the bubble bar.
            final float newBubbleScale = mNewBubbleScaleInAnimator.getAnimatedFraction();
            totalSpace = (childCount - 2 + newBubbleScale) * mExpandedBarIconsSpacing;
            totalIconSize = (childCount - 1 + newBubbleScale) * mIconSize;
            totalIconSize = (childCount - 1 + newBubbleScale) * getScaledIconSize();
        } else {
            totalSpace = Math.max(childCount - 1, 0) * mExpandedBarIconsSpacing;
            totalIconSize = childCount * mIconSize;
            totalIconSize = childCount * getScaledIconSize();
        }
        return totalIconSize + totalSpace + horizontalPadding;
        return totalIconSize + totalSpace + 2 * mBubbleBarPadding;
    }

    private float collapsedWidth() {
        final int childCount = getChildCount();
        final int horizontalPadding = getPaddingStart() + getPaddingEnd();
        final float horizontalPadding = 2 * mBubbleBarPadding;
        // If there are more than 2 bubbles, the first 2 should be visible when collapsed.
        // Otherwise just the first bubble should be visible because we don't show the overflow.
        return childCount > MAX_VISIBLE_BUBBLES_COLLAPSED
                ? mIconSize + mIconOverlapAmount + horizontalPadding
                : mIconSize + horizontalPadding;
                ? getScaledIconSize() + mIconOverlapAmount + horizontalPadding
                : getScaledIconSize() + horizontalPadding;
    }

    private float getBubbleBarExpandedHeight() {
@@ -1071,7 +1133,7 @@ public class BubbleBarView extends FrameLayout {

    float getBubbleBarCollapsedHeight() {
        // the pointer is invisible when collapsed
        return mIconSize + mBubbleBarPadding * 2;
        return getScaledIconSize() + mBubbleBarPadding * 2;
    }

    /**
@@ -1103,6 +1165,7 @@ public class BubbleBarView extends FrameLayout {
        return mIsAnimatingNewBubble;
    }


    private boolean hasOverview() {
        // Overview is always the last bubble
        View lastChild = getChildAt(getChildCount() - 1);
@@ -1144,6 +1207,46 @@ public class BubbleBarView extends FrameLayout {
        setContentDescription(contentDesc);
    }

    private boolean isIconSizeOrPaddingUpdated(float newIconSize, float newBubbleBarPadding) {
        return isIconSizeUpdated(newIconSize) || isPaddingUpdated(newBubbleBarPadding);
    }

    private boolean isIconSizeUpdated(float newIconSize) {
        return Float.compare(mIconSize, newIconSize) != 0;
    }

    private boolean isPaddingUpdated(float newBubbleBarPadding) {
        return Float.compare(mBubbleBarPadding, newBubbleBarPadding) != 0;
    }

    private void addAnimationCallBacks(@NonNull ValueAnimator animator,
            @Nullable Runnable onStart,
            @Nullable Runnable onEnd,
            @Nullable ValueAnimator.AnimatorUpdateListener onUpdate) {
        if (onUpdate != null) animator.addUpdateListener(onUpdate);
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationStart(Animator animator) {
                if (onStart != null) onStart.run();
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                if (onEnd != null) onEnd.run();
            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
    }

    /** Interface for BubbleBarView to communicate with its controller. */
    interface Controller {

+28 −31
Original line number Diff line number Diff line
@@ -108,9 +108,11 @@ public class BubbleBarViewController {
        mBubbleDragController = bubbleControllers.bubbleDragController;
        mTaskbarStashController = controllers.taskbarStashController;
        mTaskbarInsetsController = controllers.taskbarInsetsController;
        mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);

        mActivity.addOnDeviceProfileChangeListener(dp -> setBubbleBarIconSize(dp.taskbarIconSize));
        setBubbleBarIconSize(mActivity.getDeviceProfile().taskbarIconSize);
        mActivity.addOnDeviceProfileChangeListener(
                dp -> updateBubbleBarIconSize(dp.taskbarIconSize, /* animate= */ true));
        updateBubbleBarIconSize(mActivity.getDeviceProfile().taskbarIconSize, /* animate= */ false);
        mBubbleBarScale.updateValue(1f);
        mBubbleClickListener = v -> onBubbleClicked(v);
        mBubbleBarClickListener = v -> onBubbleBarClicked();
@@ -123,8 +125,6 @@ public class BubbleBarViewController {
                        mBoundsChangeListener.onBoundsChanged();
                    }
                });

        mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
        mBarView.setController(new BubbleBarView.Controller() {
            @Override
            public float getBubbleBarTranslationY() {
@@ -299,33 +299,6 @@ public class BubbleBarViewController {
        }
    }

    private void setBubbleBarIconSize(int newIconSize) {
        if (newIconSize == mIconSize) {
            return;
        }
        Resources res = mActivity.getResources();
        DisplayMetrics dm = res.getDisplayMetrics();
        float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                APP_ICON_SMALL_DP, dm);
        float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                APP_ICON_MEDIUM_DP, dm);
        float largeIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                APP_ICON_LARGE_DP, dm);
        float smallMediumThreshold = (smallIconSize + mediumIconSize) / 2f;
        float mediumLargeThreshold = (mediumIconSize + largeIconSize) / 2f;
        mIconSize = newIconSize <= smallMediumThreshold
                ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_small) :
                res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
        float bubbleBarPadding = newIconSize >= mediumLargeThreshold
                ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_large) :
                res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);

        mBarView.setIconSizeAndPadding(mIconSize, bubbleBarPadding);
        mBarView.setPadding((int) bubbleBarPadding, mBarView.getPaddingTop(),
                (int) bubbleBarPadding,
                mBarView.getPaddingBottom());
    }

    /** Sets a callback that updates the selected bubble after the bubble bar collapses. */
    public void setUpdateSelectedBubbleAfterCollapse(
            Consumer<String> updateSelectedBubbleAfterCollapse) {
@@ -360,6 +333,30 @@ public class BubbleBarViewController {
    // Modifying view related properties.
    //

    private void updateBubbleBarIconSize(int newIconSize, boolean animate) {
        Resources res = mActivity.getResources();
        DisplayMetrics dm = res.getDisplayMetrics();
        float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                APP_ICON_SMALL_DP, dm);
        float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                APP_ICON_MEDIUM_DP, dm);
        float largeIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                APP_ICON_LARGE_DP, dm);
        float smallMediumThreshold = (smallIconSize + mediumIconSize) / 2f;
        float mediumLargeThreshold = (mediumIconSize + largeIconSize) / 2f;
        mIconSize = newIconSize <= smallMediumThreshold
                ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_small) :
                res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
        float bubbleBarPadding = newIconSize >= mediumLargeThreshold
                ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_large) :
                res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
        if (animate) {
            mBarView.animateBubbleBarIconSize(mIconSize, bubbleBarPadding);
        } else {
            mBarView.setIconSizeAndPadding(mIconSize, bubbleBarPadding);
        }
    }

    /**
     * Sets the translation of the bubble bar during the swipe up gesture.
     */