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

Commit 58b6145f authored by Pat Manning's avatar Pat Manning
Browse files

Refactor ArrowTipView so it can be customized and used in any drag layer.

Allows use in TaskbarDragLayer.

Allows customization of properties like text color, background color, and open/close animations.

Bug: 250092437
Test: manual. (Will test with TaplTestsTaskbar in follow up CL when implemented.)
Change-Id: I056395322e5fef7aa4d9fd7e4c2d73c050eff759
parent f253000b
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -518,4 +518,8 @@
        <!-- The icon drawable of a widget category. -->
        <attr name="sectionDrawable" format="reference" />
    </declare-styleable>

    <declare-styleable name="ArrowTipView">
        <attr name="arrowTipBackground" format="color" />
    </declare-styleable>
</resources>
+3 −0
Original line number Diff line number Diff line
@@ -378,4 +378,7 @@
        <item name="horizontalPadding">16dp</item>
    </style>

    <style name="ArrowTipStyle">
        <item name="arrowTipBackground">@color/arrow_tip_view_bg</item>
    </style>
</resources>
+79 −43
Original line number Diff line number Diff line
@@ -16,8 +16,13 @@

package com.android.launcher3.views;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -33,18 +38,16 @@ import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.core.content.ContextCompat;

import com.android.app.animation.Interpolators;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.graphics.TriangleShape;

/**
 * A base class for arrow tip view in launcher
 * A base class for arrow tip view in launcher.
 */
public class ArrowTipView extends AbstractFloatingView {

@@ -54,33 +57,46 @@ public class ArrowTipView extends AbstractFloatingView {
    private static final long SHOW_DURATION_MS = 300;
    private static final long HIDE_DURATION_MS = 100;

    protected final BaseDraggingActivity mActivity;
    private final ActivityContext mActivityContext;
    private final Handler mHandler = new Handler();
    private final int mArrowWidth;
    private final int mArrowMinOffset;
    private boolean mIsPointingUp;
    private Runnable mOnClosed;
    private View mArrowView;
    private final int mArrowWidth;
    private final int mArrowMinOffset;
    private final int mArrowViewPaintColor;

    private AnimatorSet mOpenAnimator = new AnimatorSet();
    private AnimatorSet mCloseAnimator = new AnimatorSet();

    public ArrowTipView(Context context) {
        this(context, false);
    }

    public ArrowTipView(Context context, boolean isPointingUp) {
        this(context, isPointingUp, R.layout.arrow_toast);
    }

    public ArrowTipView(Context context, boolean isPointingUp, int layoutId) {
        super(context, null, 0);
        mActivity = BaseDraggingActivity.fromContext(context);
        mActivityContext = ActivityContext.lookupContext(context);
        mIsPointingUp = isPointingUp;
        mArrowWidth = context.getResources().getDimensionPixelSize(R.dimen.arrow_toast_arrow_width);
        mArrowWidth = context.getResources().getDimensionPixelSize(
                R.dimen.arrow_toast_arrow_width);
        mArrowMinOffset = context.getResources().getDimensionPixelSize(
                R.dimen.dynamic_grid_cell_border_spacing);
        init(context);
        TypedArray ta = context.obtainStyledAttributes(R.styleable.ArrowTipView);
        mArrowViewPaintColor = ta.getColor(R.styleable.ArrowTipView_arrowTipBackground,
                context.getColor(R.color.arrow_tip_view_bg));
        ta.recycle();
        init(context, layoutId);
    }

    @Override
    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            close(true);
            if (mActivity.getDragLayer().isEventOverView(this, ev)) {
            if (mActivityContext.getDragLayer().isEventOverView(this, ev)) {
                return true;
            }
        }
@@ -89,18 +105,15 @@ public class ArrowTipView extends AbstractFloatingView {

    @Override
    protected void handleClose(boolean animate) {
        if (mOpenAnimator.isStarted()) {
            mOpenAnimator.cancel();
        }
        if (mIsOpen) {
            if (animate) {
                animate().alpha(0f)
                        .withLayer()
                        .setStartDelay(0)
                        .setDuration(HIDE_DURATION_MS)
                        .setInterpolator(Interpolators.ACCELERATE)
                        .withEndAction(() -> mActivity.getDragLayer().removeView(this))
                        .start();
                mCloseAnimator.start();
            } else {
                animate().cancel();
                mActivity.getDragLayer().removeView(this);
                mCloseAnimator.cancel();
                mActivityContext.getDragLayer().removeView(this);
            }
            if (mOnClosed != null) mOnClosed.run();
            mIsOpen = false;
@@ -112,12 +125,31 @@ public class ArrowTipView extends AbstractFloatingView {
        return (type & TYPE_ON_BOARD_POPUP) != 0;
    }

    private void init(Context context) {
        inflate(context, R.layout.arrow_toast, this);
    private void init(Context context, int layoutId) {
        inflate(context, layoutId, this);
        setOrientation(LinearLayout.VERTICAL);

        mArrowView = findViewById(R.id.arrow);
        updateArrowTipInView();
        setAlpha(0);

        // Create default open animator.
        mOpenAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, 1f));
        mOpenAnimator.setStartDelay(SHOW_DELAY_MS);
        mOpenAnimator.setDuration(SHOW_DURATION_MS);
        mOpenAnimator.setInterpolator(Interpolators.DECELERATE);

        // Create default close animator.
        mCloseAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, 0));
        mCloseAnimator.setStartDelay(0);
        mCloseAnimator.setDuration(HIDE_DURATION_MS);
        mCloseAnimator.setInterpolator(Interpolators.ACCELERATE);
        mCloseAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mActivityContext.getDragLayer().removeView(ArrowTipView.this);
            }
        });
    }

    /**
@@ -153,10 +185,10 @@ public class ArrowTipView extends AbstractFloatingView {
    public ArrowTipView show(
            String text, int gravity, int arrowMarginStart, int top, boolean shouldAutoClose) {
        ((TextView) findViewById(R.id.text)).setText(text);
        ViewGroup parent = mActivity.getDragLayer();
        ViewGroup parent = mActivityContext.getDragLayer();
        parent.addView(this);

        DeviceProfile grid = mActivity.getDeviceProfile();
        DeviceProfile grid = mActivityContext.getDeviceProfile();

        DragLayer.LayoutParams params = (DragLayer.LayoutParams) getLayoutParams();
        params.gravity = gravity;
@@ -185,14 +217,8 @@ public class ArrowTipView extends AbstractFloatingView {
        if (shouldAutoClose) {
            mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS);
        }
        setAlpha(0);
        animate()
                .alpha(1f)
                .withLayer()
                .setStartDelay(SHOW_DELAY_MS)
                .setDuration(SHOW_DURATION_MS)
                .setInterpolator(Interpolators.DECELERATE)
                .start();

        mOpenAnimator.start();
        return this;
    }

@@ -273,7 +299,7 @@ public class ArrowTipView extends AbstractFloatingView {
     */
    @Nullable private ArrowTipView showAtLocation(String text, @Px int arrowXCoord,
            @Px int yCoordDownPointingTip, @Px int yCoordUpPointingTip, boolean shouldAutoClose) {
        ViewGroup parent = mActivity.getDragLayer();
        ViewGroup parent = mActivityContext.getDragLayer();
        @Px int parentViewWidth = parent.getWidth();
        @Px int parentViewHeight = parent.getHeight();
        @Px int maxTextViewWidth = getContext().getResources()
@@ -288,8 +314,10 @@ public class ArrowTipView extends AbstractFloatingView {
        TextView textView = findViewById(R.id.text);
        textView.setText(text);
        textView.setMaxWidth(maxTextViewWidth);
        if (parent.indexOfChild(this) < 0) {
            parent.addView(this);
            requestLayout();
        }

        post(() -> {
            // Adjust the tooltip horizontally.
@@ -333,14 +361,8 @@ public class ArrowTipView extends AbstractFloatingView {
        if (shouldAutoClose) {
            mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS);
        }
        setAlpha(0);
        animate()
                .alpha(1f)
                .withLayer()
                .setStartDelay(SHOW_DELAY_MS)
                .setDuration(SHOW_DURATION_MS)
                .setInterpolator(Interpolators.DECELERATE)
                .start();

        mOpenAnimator.start();
        return this;
    }

@@ -351,7 +373,7 @@ public class ArrowTipView extends AbstractFloatingView {
        Paint arrowPaint = arrowDrawable.getPaint();
        @Px int arrowTipRadius = getContext().getResources()
                .getDimensionPixelSize(R.dimen.arrow_toast_corner_radius);
        arrowPaint.setColor(ContextCompat.getColor(getContext(), R.color.arrow_tip_view_bg));
        arrowPaint.setColor(mArrowViewPaintColor);
        arrowPaint.setPathEffect(new CornerPathEffect(arrowTipRadius));
        mArrowView.setBackground(arrowDrawable);
        // Add negative margin so that the rounded corners on base of arrow are not visible.
@@ -378,4 +400,18 @@ public class ArrowTipView extends AbstractFloatingView {
        super.onConfigurationChanged(newConfig);
        close(/* animate= */ false);
    }

    /**
     * Sets a custom animation to run on open of the ArrowTipView.
     */
    public void setCustomOpenAnimation(AnimatorSet animator) {
        mOpenAnimator = animator;
    }

    /**
     * Sets a custom animation to run on close of the ArrowTipView.
     */
    public void setCustomCloseAnimation(AnimatorSet animator) {
        mCloseAnimator = animator;
    }
}