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

Commit 2db0d14b authored by mpodolian's avatar mpodolian
Browse files

Updated expanded bubble menu animation.

Added logic to the handle view and menu view to implement the updated
animation specifications.

Fixes: 345687667
Flag: com.android.wm.shell.enable_bubble_bar
Test: BubbleBarHandleViewTest
Test: Manual. Have few bubbles in the bubble bar. Expand one bubble and
click on the handle view. Click anywhere outside of the menu. Click
another bubble, observe handle view is properly placed. Click on the
handle view.
video: http://recall/-/gx8ASgewUeUS3QYohfrd1J/5dgZCNbnB9LxtPrpP6cUI

Change-Id: Id9a5251792d05f45b515f0dfcf39d736f410a7dc
parent e0519f2f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:orientation="vertical"
    android:clipChildren="false"
    android:id="@+id/bubble_expanded_view">

    <com.android.wm.shell.bubbles.bar.BubbleBarHandleView
+6 −8
Original line number Diff line number Diff line
@@ -14,20 +14,18 @@
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License
  -->
<com.android.wm.shell.bubbles.bar.BubbleBarMenuView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
<com.android.wm.shell.bubbles.bar.BubbleBarMenuView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:clipToPadding="false"
    android:minWidth="@dimen/bubble_bar_manage_menu_min_width"
    android:orientation="vertical"
    android:elevation="@dimen/bubble_manage_menu_elevation"
    android:paddingTop="@dimen/bubble_bar_manage_menu_padding_top"
    android:paddingHorizontal="@dimen/bubble_bar_manage_menu_padding"
    android:paddingBottom="@dimen/bubble_bar_manage_menu_padding"
    android:clipToPadding="false">
    android:visibility="invisible"
    tools:visibility="visible">

    <LinearLayout
        android:id="@+id/bubble_bar_manage_menu_bubble_section"
+1 −1
Original line number Diff line number Diff line
@@ -222,7 +222,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView

            mHandleView.setAccessibilityDelegate(new HandleViewAccessibilityDelegate());
        }
        mMenuViewController = new BubbleBarMenuViewController(mContext, this);
        mMenuViewController = new BubbleBarMenuViewController(mContext, mHandleView, this);
        mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
            @Override
            public void onMenuVisibilityChanged(boolean visible) {
+101 −27
Original line number Diff line number Diff line
@@ -17,17 +17,18 @@ package com.android.wm.shell.bubbles.bar;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Outline;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;

import androidx.annotation.ColorInt;
import androidx.annotation.VisibleForTesting;
import androidx.core.animation.IntProperty;
import androidx.core.content.ContextCompat;

import com.android.wm.shell.R;
@@ -37,14 +38,33 @@ import com.android.wm.shell.R;
 */
public class BubbleBarHandleView extends View {
    private static final long COLOR_CHANGE_DURATION = 120;
    // Path used to draw the dots
    private final Path mPath = new Path();

    /** Custom property to set handle color. */
    private static final IntProperty<BubbleBarHandleView> HANDLE_COLOR = new IntProperty<>(
            "handleColor") {
        @Override
        public void setValue(BubbleBarHandleView bubbleBarHandleView, int color) {
            bubbleBarHandleView.setHandleColor(color);
        }

        @Override
        public Integer get(BubbleBarHandleView bubbleBarHandleView) {
            return bubbleBarHandleView.getHandleColor();
        }
    };

    @VisibleForTesting
    final Paint mHandlePaint = new Paint();
    private final @ColorInt int mHandleLightColor;
    private final @ColorInt int mHandleDarkColor;
    private @ColorInt int mCurrentColor;
    private final ArgbEvaluator mArgbEvaluator = ArgbEvaluator.getInstance();
    private final float mHandleHeight;
    private final float mHandleWidth;
    private float mCurrentHandleHeight;
    private float mCurrentHandleWidth;
    @Nullable
    private ObjectAnimator mColorChangeAnim;
    private @ColorInt int mRegionSamplerColor;

    public BubbleBarHandleView(Context context) {
        this(context, null /* attrs */);
@@ -61,28 +81,50 @@ public class BubbleBarHandleView extends View {
    public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        final int handleHeight = getResources().getDimensionPixelSize(
        mHandlePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mHandlePaint.setStyle(Paint.Style.FILL);
        mHandlePaint.setColor(0);
        mHandleHeight = getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_height);
        mHandleWidth = getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_caption_width);
        mHandleLightColor = ContextCompat.getColor(getContext(),
                R.color.bubble_bar_expanded_view_handle_light);
        mHandleDarkColor = ContextCompat.getColor(getContext(),
                R.color.bubble_bar_expanded_view_handle_dark);
        mCurrentHandleHeight = mHandleHeight;
        mCurrentHandleWidth = mHandleWidth;
        setContentDescription(getResources().getString(R.string.handle_text));
    }

    private void setHandleColor(int color) {
        mHandlePaint.setColor(color);
        invalidate();
    }

    private int getHandleColor() {
        return mHandlePaint.getColor();
    }

        setClipToOutline(true);
        setOutlineProvider(new ViewOutlineProvider() {
    @Override
            public void getOutline(View view, Outline outline) {
                final int handleCenterY = view.getHeight() / 2;
                final int handleTop = handleCenterY - handleHeight / 2;
                final int handleBottom = handleTop + handleHeight;
                final int radius = handleHeight / 2;
                RectF handle = new RectF(/* left = */ 0, handleTop, view.getWidth(), handleBottom);
                mPath.reset();
                mPath.addRoundRect(handle, radius, radius, Path.Direction.CW);
                outline.setPath(mPath);
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float handleLeft = (getWidth() - mCurrentHandleWidth) / 2;
        float handleRight = handleLeft + mCurrentHandleWidth;
        float handleCenterY = (float) getHeight() / 2;
        float handleTop = (int) (handleCenterY - mCurrentHandleHeight / 2);
        float handleBottom = handleTop + mCurrentHandleHeight;
        float cornerRadius = mCurrentHandleHeight / 2;
        canvas.drawRoundRect(handleLeft, handleTop, handleRight, handleBottom, cornerRadius,
                cornerRadius, mHandlePaint);
    }
        });
        setContentDescription(getResources().getString(R.string.handle_text));

    /** Sets handle width, height and color. Does not change the layout properties */
    private void setHandleProperties(float width, float height, int color) {
        mCurrentHandleHeight = height;
        mCurrentHandleWidth = width;
        mHandlePaint.setColor(color);
        invalidate();
    }

    /**
@@ -94,15 +136,15 @@ public class BubbleBarHandleView extends View {
     */
    public void updateHandleColor(boolean isRegionDark, boolean animated) {
        int newColor = isRegionDark ? mHandleLightColor : mHandleDarkColor;
        if (newColor == mCurrentColor) {
        if (newColor == mRegionSamplerColor) {
            return;
        }
        mRegionSamplerColor = newColor;
        if (mColorChangeAnim != null) {
            mColorChangeAnim.cancel();
        }
        mCurrentColor = newColor;
        if (animated) {
            mColorChangeAnim = ObjectAnimator.ofArgb(this, "backgroundColor", newColor);
            mColorChangeAnim = ObjectAnimator.ofArgb(this, HANDLE_COLOR, newColor);
            mColorChangeAnim.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
@@ -112,7 +154,39 @@ public class BubbleBarHandleView extends View {
            mColorChangeAnim.setDuration(COLOR_CHANGE_DURATION);
            mColorChangeAnim.start();
        } else {
            setBackgroundColor(newColor);
            setHandleColor(newColor);
        }
    }

    /** Returns handle padding top. */
    public int getHandlePaddingTop() {
        return (getHeight() - getResources().getDimensionPixelSize(
                R.dimen.bubble_bar_expanded_view_handle_height)) / 2;
    }

    /** Animates handle for the bubble menu. */
    public void animateHandleForMenu(float progress, float widthDelta, float heightDelta,
            int menuColor) {
        float currentWidth = mHandleWidth + widthDelta * progress;
        float currentHeight = mHandleHeight + heightDelta * progress;
        int color = (int) mArgbEvaluator.evaluate(progress, mRegionSamplerColor, menuColor);
        setHandleProperties(currentWidth, currentHeight, color);
        setTranslationY(heightDelta * progress / 2);
    }

    /** Restores all the properties that were animated to the default values. */
    public void restoreAnimationDefaults() {
        setHandleProperties(mHandleWidth, mHandleHeight, mRegionSamplerColor);
        setTranslationY(0);
    }

    /** Returns the handle height. */
    public int getHandleHeight() {
        return (int) mHandleHeight;
    }

    /** Returns the handle width. */
    public int getHandleWidth() {
        return (int) mHandleWidth;
    }
}
+38 −0
Original line number Diff line number Diff line
@@ -47,6 +47,10 @@ public class BubbleBarMenuView extends LinearLayout {
    private ImageView mBubbleIconView;
    private ImageView mBubbleDismissIconView;
    private TextView mBubbleTitleView;
    // The animation has three stages. Each stage transition lasts until the animation ends. In
    // stage 1, the title item content fades in. In stage 2, the background of the option items
    // fades in. In stage 3, the option item content fades in.
    private static final int SHOW_MENU_STAGES_COUNT = 3;

    public BubbleBarMenuView(Context context) {
        this(context, null /* attrs */);
@@ -97,6 +101,35 @@ public class BubbleBarMenuView extends LinearLayout {
        }
    }

    /** Animates the menu from the specified start scale. */
    public void animateFromStartScale(float currentScale, float progress) {
        int menuItemElevation = getResources().getDimensionPixelSize(
                R.dimen.bubble_manage_menu_elevation);
        setScaleX(currentScale);
        setScaleY(currentScale);
        setAlphaForTitleViews(progress);
        mBubbleSectionView.setElevation(menuItemElevation * progress);
        float actionsBackgroundAlpha = Math.max(0,
                (progress - (float) 1 / SHOW_MENU_STAGES_COUNT) * (SHOW_MENU_STAGES_COUNT - 1));
        float actionItemsAlpha = Math.max(0,
                (progress - (float) 2 / SHOW_MENU_STAGES_COUNT) * SHOW_MENU_STAGES_COUNT);
        mActionsSectionView.setAlpha(actionsBackgroundAlpha);
        mActionsSectionView.setElevation(menuItemElevation * actionsBackgroundAlpha);
        setMenuItemViewsAlpha(actionItemsAlpha);
    }

    private void setAlphaForTitleViews(float alpha) {
        mBubbleIconView.setAlpha(alpha);
        mBubbleTitleView.setAlpha(alpha);
        mBubbleDismissIconView.setAlpha(alpha);
    }

    private void setMenuItemViewsAlpha(float alpha) {
        for (int i = mActionsSectionView.getChildCount() - 1; i >= 0; i--) {
            mActionsSectionView.getChildAt(i).setAlpha(alpha);
        }
    }

    /** Update menu details with bubble info */
    void updateInfo(Bubble bubble) {
        if (bubble.getIcon() != null) {
@@ -153,6 +186,11 @@ public class BubbleBarMenuView extends LinearLayout {
        return mBubbleSectionView.getAlpha();
    }

    /** Return title menu item height. */
    public float getTitleItemHeight() {
        return mBubbleSectionView.getHeight();
    }

    /**
     * Menu action details used to create menu items
     */
Loading