RippleComponent.java revision f872ee0057ed247aa93589347f1b53afc99517f8
1f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette/*
2f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * Copyright (C) 2015 The Android Open Source Project
3f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette *
4f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License");
5f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * you may not use this file except in compliance with the License.
6f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * You may obtain a copy of the License at
7f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette *
8f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette *      http://www.apache.org/licenses/LICENSE-2.0
9f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette *
10f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * Unless required by applicable law or agreed to in writing, software
11f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS,
12f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * See the License for the specific language governing permissions and
14f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * limitations under the License.
15f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette */
16f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
17f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverettepackage android.graphics.drawable;
18f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
19f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteimport android.animation.Animator;
20f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteimport android.graphics.Canvas;
21f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteimport android.graphics.Paint;
22f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteimport android.graphics.Rect;
23f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteimport android.view.HardwareCanvas;
24f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteimport android.view.RenderNodeAnimator;
25f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
26f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteimport java.util.ArrayList;
27f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
28f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette/**
29f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * Abstract class that handles hardware/software hand-off and lifecycle for
30f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * animated ripple foreground and background components.
31f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette */
32f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteabstract class RippleComponent {
33f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private final RippleDrawable mOwner;
34f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
35f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** Bounds used for computing max radius. May be modified by the owner. */
36f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected final Rect mBounds;
37f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
38f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** Whether we can use hardware acceleration for the exit animation. */
39f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private boolean mHasHardwareCanvas;
40f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
41f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private boolean mHasPendingHardwareAnimator;
42f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private RenderNodeAnimatorSet mHardwareAnimator;
43f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
44f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private Animator mSoftwareAnimator;
45f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
46f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** Whether we have an explicit maximum radius. */
47f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private boolean mHasMaxRadius;
48f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
49f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** How big this ripple should be when fully entered. */
50f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected float mTargetRadius;
51f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
52f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** Screen density used to adjust pixel-based constants. */
53f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected float mDensity;
54f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
55f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public RippleComponent(RippleDrawable owner, Rect bounds) {
56f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        mOwner = owner;
57f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        mBounds = bounds;
58f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
59f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
60f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public final void setup(float maxRadius, float density) {
61f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (maxRadius >= 0) {
62f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHasMaxRadius = true;
63f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mTargetRadius = maxRadius;
64f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        } else {
65f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final float halfWidth = mBounds.width() / 2.0f;
66f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final float halfHeight = mBounds.height() / 2.0f;
67f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mTargetRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
68f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
69f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
70f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        mDensity = density;
71f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
72f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        onSetup();
73f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        onTargetRadiusChanged(mTargetRadius);
74f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
75f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
76f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
77f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Starts a ripple enter animation.
78f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
79f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param fast whether the ripple should enter quickly
80f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
81f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public final void enter(boolean fast) {
82f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        cancel();
83f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
84f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        mSoftwareAnimator = createSoftwareEnter(fast);
85f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        mSoftwareAnimator.start();
86f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
87f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
88f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
89f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Starts a ripple exit animation.
90f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
91f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public final void exit() {
92f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        cancel();
93f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
94f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mHasHardwareCanvas) {
95f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // We don't have access to a canvas here, but we expect one on the
96f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // next frame. We'll start the render thread animation then.
97f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHasPendingHardwareAnimator = true;
98f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
99f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // Request another frame.
100f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            invalidateSelf();
101f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        } else {
102f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mSoftwareAnimator = createSoftwareExit();
103f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mSoftwareAnimator.start();
104f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
105f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
106f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
107f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
108f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Cancels all animations. Software animation values are left in the
109f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * current state, while hardware animation values jump to the end state.
110f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
111f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public void cancel() {
112f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        cancelSoftwareAnimations();
113f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        endHardwareAnimations();
114f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
115f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
116f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
117f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Ends all animations, jumping values to the end state.
118f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
119f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public void end() {
120f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        endSoftwareAnimations();
121f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        endHardwareAnimations();
122f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
123f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
124f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
125f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Draws the ripple to the canvas, inheriting the paint's color and alpha
126f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * properties.
127f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
128f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param c the canvas to which the ripple should be drawn
129f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param p the paint used to draw the ripple
130f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @return {@code true} if something was drawn, {@code false} otherwise
131f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
132f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public boolean draw(Canvas c, Paint p) {
133f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        final boolean hasHardwareCanvas = c.isHardwareAccelerated()
134f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                && c instanceof HardwareCanvas;
135f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mHasHardwareCanvas != hasHardwareCanvas) {
136f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHasHardwareCanvas = hasHardwareCanvas;
137f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
138f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            if (!hasHardwareCanvas) {
139f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                // We've switched from hardware to non-hardware mode. Panic.
140f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                endHardwareAnimations();
141f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
142f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
143f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
144f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (hasHardwareCanvas) {
145f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final HardwareCanvas hw = (HardwareCanvas) c;
146f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            startPendingAnimation(hw, p);
147f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
148f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            if (mHardwareAnimator != null) {
149f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                return drawHardware(hw);
150f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
151f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
152f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
153f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        return drawSoftware(c, p);
154f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
155f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
156f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
157f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Populates {@code bounds} with the maximum drawing bounds of the ripple
158f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * relative to its center. The resulting bounds should be translated into
159f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * parent drawable coordinates before use.
160f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
161f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param bounds the rect to populate with drawing bounds
162f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
163f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public void getBounds(Rect bounds) {
164f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        final int r = (int) Math.ceil(mTargetRadius);
165f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        bounds.set(-r, -r, r, r);
166f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
167f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
168f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
169f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Starts the pending hardware animation, if available.
170f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
171f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param hw hardware canvas on which the animation should draw
172f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param p paint whose properties the hardware canvas should use
173f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
174f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private void startPendingAnimation(HardwareCanvas hw, Paint p) {
175f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mHasPendingHardwareAnimator) {
176f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHasPendingHardwareAnimator = false;
177f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
178f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHardwareAnimator = createHardwareExit(new Paint(p));
179f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHardwareAnimator.start(hw);
180f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
181f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // Preemptively jump the software values to the end state now that
182f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // the hardware exit has read whatever values it needs.
183f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            jumpValuesToExit();
184f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
185f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
186f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
187f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
188f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Cancels any current software animations, leaving the values in their
189f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * current state.
190f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
191f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private void cancelSoftwareAnimations() {
192f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mSoftwareAnimator != null) {
193f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mSoftwareAnimator.cancel();
194f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
195f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
196f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
197f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
198f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Ends any current software animations, jumping the values to their end
199f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * state.
200f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
201f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private void endSoftwareAnimations() {
202f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mSoftwareAnimator != null) {
203f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mSoftwareAnimator.end();
204f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
205f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
206f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
207f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
208f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Ends any pending or current hardware animations.
209f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * <p>
210f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Hardware animations can't synchronize values back to the software
211f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * thread, so there is no "cancel" equivalent.
212f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
213f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private void endHardwareAnimations() {
214f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mHardwareAnimator != null) {
215f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHardwareAnimator.end();
216f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHardwareAnimator = null;
217f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
218f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
219f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mHasPendingHardwareAnimator) {
220f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHasPendingHardwareAnimator = false;
221f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
222f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
223f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
224f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected final void invalidateSelf() {
225f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        mOwner.invalidateSelf();
226f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
227f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
228f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected final boolean isHardwareAnimating() {
229f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        return mHardwareAnimator != null && mHardwareAnimator.isRunning()
230f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                || mHasPendingHardwareAnimator;
231f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
232f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
233f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected final void onHotspotBoundsChanged() {
234f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (!mHasMaxRadius) {
235f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final float halfWidth = mBounds.width() / 2.0f;
236f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final float halfHeight = mBounds.height() / 2.0f;
237f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final float targetRadius = (float) Math.sqrt(halfWidth * halfWidth
238f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                    + halfHeight * halfHeight);
239f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
240f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            onTargetRadiusChanged(targetRadius);
241f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
242f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
243f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
244f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
245f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Called when the target radius changes.
246f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
247f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param targetRadius the new target radius
248f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
249f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected void onTargetRadiusChanged(float targetRadius) {
250f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        // Stub.
251f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
252f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
253f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
254f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Called during ripple setup, which occurs before the first enter
255f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * animation.
256f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
257f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected void onSetup() {
258f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        // Stub.
259f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
260f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
261f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract Animator createSoftwareEnter(boolean fast);
262f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
263f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract Animator createSoftwareExit();
264f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
265f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract RenderNodeAnimatorSet createHardwareExit(Paint p);
266f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
267f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract boolean drawHardware(HardwareCanvas c);
268f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
269f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract boolean drawSoftware(Canvas c, Paint p);
270f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
271f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
272f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Called when the hardware exit is cancelled. Jumps software values to end
273f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * state to ensure that software and hardware values are synchronized.
274f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
275f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract void jumpValuesToExit();
276f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
277f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public static class RenderNodeAnimatorSet {
278f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        private final ArrayList<RenderNodeAnimator> mAnimators = new ArrayList<>();
279f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
280f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public void add(RenderNodeAnimator anim) {
281f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mAnimators.add(anim);
282f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
283f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
284f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public void clear() {
285f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mAnimators.clear();
286f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
287f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
288f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public void start(HardwareCanvas target) {
289f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            if (target == null) {
290f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                throw new IllegalArgumentException("Hardware canvas must be non-null");
291f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
292f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
293f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final ArrayList<RenderNodeAnimator> animators = mAnimators;
294f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final int N = animators.size();
295f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            for (int i = 0; i < N; i++) {
296f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                final RenderNodeAnimator anim = animators.get(i);
297f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                anim.setTarget(target);
298f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                anim.start();
299f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
300f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
301f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
302f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public void cancel() {
303f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final ArrayList<RenderNodeAnimator> animators = mAnimators;
304f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final int N = animators.size();
305f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            for (int i = 0; i < N; i++) {
306f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                final RenderNodeAnimator anim = animators.get(i);
307f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                anim.cancel();
308f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
309f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
310f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
311f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public void end() {
312f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final ArrayList<RenderNodeAnimator> animators = mAnimators;
313f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final int N = animators.size();
314f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            for (int i = 0; i < N; i++) {
315f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                final RenderNodeAnimator anim = animators.get(i);
316f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                anim.end();
317f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
318f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
319f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
320f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public boolean isRunning() {
321f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final ArrayList<RenderNodeAnimator> animators = mAnimators;
322f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final int N = animators.size();
323f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            for (int i = 0; i < N; i++) {
324f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                final RenderNodeAnimator anim = animators.get(i);
325f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                if (anim.isRunning()) {
326f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                    return true;
327f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                }
328f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
329f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            return false;
330f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
331f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
332f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette}
333