1package com.android.launcher3.anim;
2
3import android.animation.Animator;
4import android.animation.AnimatorListenerAdapter;
5import android.animation.ValueAnimator;
6import android.graphics.Outline;
7import android.graphics.Rect;
8import android.view.View;
9import android.view.ViewOutlineProvider;
10
11import com.android.launcher3.Utilities;
12
13/**
14 * A {@link ViewOutlineProvider} that has helper functions to create reveal animations.
15 * This class should be extended so that subclasses can define the reveal shape as the
16 * animation progresses from 0 to 1.
17 */
18public abstract class RevealOutlineAnimation extends ViewOutlineProvider {
19    protected Rect mOutline;
20    protected float mOutlineRadius;
21
22    public RevealOutlineAnimation() {
23        mOutline = new Rect();
24    }
25
26    /** Returns whether elevation should be removed for the duration of the reveal animation. */
27    abstract boolean shouldRemoveElevationDuringAnimation();
28    /** Sets the progress, from 0 to 1, of the reveal animation. */
29    abstract void setProgress(float progress);
30
31    public ValueAnimator createRevealAnimator(final View revealView, boolean isReversed) {
32        ValueAnimator va =
33                isReversed ? ValueAnimator.ofFloat(1f, 0f) : ValueAnimator.ofFloat(0f, 1f);
34        final float elevation = revealView.getElevation();
35
36        va.addListener(new AnimatorListenerAdapter() {
37            private boolean mIsClippedToOutline;
38            private ViewOutlineProvider mOldOutlineProvider;
39
40            public void onAnimationStart(Animator animation) {
41                mIsClippedToOutline = revealView.getClipToOutline();
42                mOldOutlineProvider = revealView.getOutlineProvider();
43
44                revealView.setOutlineProvider(RevealOutlineAnimation.this);
45                revealView.setClipToOutline(true);
46                if (shouldRemoveElevationDuringAnimation()) {
47                    revealView.setTranslationZ(-elevation);
48                }
49            }
50
51            public void onAnimationEnd(Animator animation) {
52                revealView.setOutlineProvider(mOldOutlineProvider);
53                revealView.setClipToOutline(mIsClippedToOutline);
54                if (shouldRemoveElevationDuringAnimation()) {
55                    revealView.setTranslationZ(0);
56                }
57            }
58
59        });
60
61        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
62            @Override
63            public void onAnimationUpdate(ValueAnimator arg0) {
64                float progress = (Float) arg0.getAnimatedValue();
65                setProgress(progress);
66                revealView.invalidateOutline();
67                if (!Utilities.ATLEAST_LOLLIPOP_MR1) {
68                    revealView.invalidate();
69                }
70            }
71        });
72        return va;
73    }
74
75    @Override
76    public void getOutline(View v, Outline outline) {
77        outline.setRoundRect(mOutline, mOutlineRadius);
78    }
79
80    public float getRadius() {
81        return mOutlineRadius;
82    }
83
84    public void getOutline(Rect out) {
85        out.set(mOutline);
86    }
87}
88