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;
23bd5294bcb857a48ad22ddd54b13208ec2903c3f6Alan Viveretteimport android.util.DisplayMetrics;
24f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craikimport android.view.DisplayListCanvas;
25f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteimport android.view.RenderNodeAnimator;
26f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
27f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteimport java.util.ArrayList;
28f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
29f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette/**
30f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * Abstract class that handles hardware/software hand-off and lifecycle for
31f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette * animated ripple foreground and background components.
32f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette */
33f872ee0057ed247aa93589347f1b53afc99517f8Alan Viveretteabstract class RippleComponent {
34f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private final RippleDrawable mOwner;
35f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
36f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** Bounds used for computing max radius. May be modified by the owner. */
37f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected final Rect mBounds;
38f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
39f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** Whether we can use hardware acceleration for the exit animation. */
40f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik    private boolean mHasDisplayListCanvas;
41f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
42f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private boolean mHasPendingHardwareAnimator;
43f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private RenderNodeAnimatorSet mHardwareAnimator;
44f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
45f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private Animator mSoftwareAnimator;
46f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
47f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** Whether we have an explicit maximum radius. */
48f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private boolean mHasMaxRadius;
49f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
50f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** How big this ripple should be when fully entered. */
51f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected float mTargetRadius;
52f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
53f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /** Screen density used to adjust pixel-based constants. */
54bd5294bcb857a48ad22ddd54b13208ec2903c3f6Alan Viverette    protected float mDensityScale;
55f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
56b7303a36baf8d0ac3efdeeee3310ef5974ba9ceaJorim Jaggi    /**
57b7303a36baf8d0ac3efdeeee3310ef5974ba9ceaJorim Jaggi     * If set, force all ripple animations to not run on RenderThread, even if it would be
58b7303a36baf8d0ac3efdeeee3310ef5974ba9ceaJorim Jaggi     * available.
59b7303a36baf8d0ac3efdeeee3310ef5974ba9ceaJorim Jaggi     */
60b7303a36baf8d0ac3efdeeee3310ef5974ba9ceaJorim Jaggi    private final boolean mForceSoftware;
61b7303a36baf8d0ac3efdeeee3310ef5974ba9ceaJorim Jaggi
62b7303a36baf8d0ac3efdeeee3310ef5974ba9ceaJorim Jaggi    public RippleComponent(RippleDrawable owner, Rect bounds, boolean forceSoftware) {
63f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        mOwner = owner;
64f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        mBounds = bounds;
65b7303a36baf8d0ac3efdeeee3310ef5974ba9ceaJorim Jaggi        mForceSoftware = forceSoftware;
66f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
67f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
685bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette    public void onBoundsChange() {
695bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette        if (!mHasMaxRadius) {
705bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette            mTargetRadius = getTargetRadius(mBounds);
715bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette            onTargetRadiusChanged(mTargetRadius);
725bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette        }
735bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette    }
745bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette
75bd5294bcb857a48ad22ddd54b13208ec2903c3f6Alan Viverette    public final void setup(float maxRadius, int densityDpi) {
76f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (maxRadius >= 0) {
77f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHasMaxRadius = true;
78f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mTargetRadius = maxRadius;
79f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        } else {
805bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette            mTargetRadius = getTargetRadius(mBounds);
81f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
82f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
83bd5294bcb857a48ad22ddd54b13208ec2903c3f6Alan Viverette        mDensityScale = densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
84f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
85f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        onTargetRadiusChanged(mTargetRadius);
86f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
87f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
885bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette    private static float getTargetRadius(Rect bounds) {
895bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette        final float halfWidth = bounds.width() / 2.0f;
905bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette        final float halfHeight = bounds.height() / 2.0f;
915bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette        return (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
925bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette    }
935bc0144302bb378e5f007baa4bf6620ab9031879Alan Viverette
94f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
95f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Starts a ripple enter animation.
96f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
97f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param fast whether the ripple should enter quickly
98f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
99f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public final void enter(boolean fast) {
100f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        cancel();
101f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
102f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        mSoftwareAnimator = createSoftwareEnter(fast);
1036a67db41388165aca63d0d5de2830cc096ed930bAlan Viverette
1046a67db41388165aca63d0d5de2830cc096ed930bAlan Viverette        if (mSoftwareAnimator != null) {
1056a67db41388165aca63d0d5de2830cc096ed930bAlan Viverette            mSoftwareAnimator.start();
1066a67db41388165aca63d0d5de2830cc096ed930bAlan Viverette        }
107f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
108f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
109f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
110f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Starts a ripple exit animation.
111f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
112f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public final void exit() {
113f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        cancel();
114f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
115f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik        if (mHasDisplayListCanvas) {
116f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // We don't have access to a canvas here, but we expect one on the
117f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // next frame. We'll start the render thread animation then.
118f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHasPendingHardwareAnimator = true;
119f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
120f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // Request another frame.
121f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            invalidateSelf();
122f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        } else {
123f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mSoftwareAnimator = createSoftwareExit();
124f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mSoftwareAnimator.start();
125f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
126f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
127f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
128f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
129f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Cancels all animations. Software animation values are left in the
130f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * current state, while hardware animation values jump to the end state.
131f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
132f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public void cancel() {
133f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        cancelSoftwareAnimations();
134f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        endHardwareAnimations();
135f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
136f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
137f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
138f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Ends all animations, jumping values to the end state.
139f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
140f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public void end() {
141f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        endSoftwareAnimations();
142f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        endHardwareAnimations();
143f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
144f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
145f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
146f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Draws the ripple to the canvas, inheriting the paint's color and alpha
147f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * properties.
148f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
149f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param c the canvas to which the ripple should be drawn
150f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param p the paint used to draw the ripple
151f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @return {@code true} if something was drawn, {@code false} otherwise
152f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
153f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public boolean draw(Canvas c, Paint p) {
154b7303a36baf8d0ac3efdeeee3310ef5974ba9ceaJorim Jaggi        final boolean hasDisplayListCanvas = !mForceSoftware && c.isHardwareAccelerated()
155f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik                && c instanceof DisplayListCanvas;
156f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik        if (mHasDisplayListCanvas != hasDisplayListCanvas) {
157f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik            mHasDisplayListCanvas = hasDisplayListCanvas;
158f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
159f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik            if (!hasDisplayListCanvas) {
160f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                // We've switched from hardware to non-hardware mode. Panic.
161f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                endHardwareAnimations();
162f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
163f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
164f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
165f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik        if (hasDisplayListCanvas) {
166f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik            final DisplayListCanvas hw = (DisplayListCanvas) c;
167f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            startPendingAnimation(hw, p);
168f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
169f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            if (mHardwareAnimator != null) {
170f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                return drawHardware(hw);
171f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
172f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
173f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
174f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        return drawSoftware(c, p);
175f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
176f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
177f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
178f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Populates {@code bounds} with the maximum drawing bounds of the ripple
179f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * relative to its center. The resulting bounds should be translated into
180f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * parent drawable coordinates before use.
181f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
182f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param bounds the rect to populate with drawing bounds
183f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
184f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public void getBounds(Rect bounds) {
185f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        final int r = (int) Math.ceil(mTargetRadius);
186f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        bounds.set(-r, -r, r, r);
187f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
188f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
189f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
190f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Starts the pending hardware animation, if available.
191f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
192f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param hw hardware canvas on which the animation should draw
193f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param p paint whose properties the hardware canvas should use
194f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
195f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik    private void startPendingAnimation(DisplayListCanvas hw, Paint p) {
196f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mHasPendingHardwareAnimator) {
197f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHasPendingHardwareAnimator = false;
198f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
199f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHardwareAnimator = createHardwareExit(new Paint(p));
200f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHardwareAnimator.start(hw);
201f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
202f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // Preemptively jump the software values to the end state now that
203f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            // the hardware exit has read whatever values it needs.
204f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            jumpValuesToExit();
205f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
206f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
207f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
208f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
209f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Cancels any current software animations, leaving the values in their
210f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * current state.
211f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
212f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private void cancelSoftwareAnimations() {
213f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mSoftwareAnimator != null) {
214f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mSoftwareAnimator.cancel();
215fc8882f1340055e00f6c21449983e92413045275Alan Viverette            mSoftwareAnimator = null;
216f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
217f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
218f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
219f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
220f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Ends any current software animations, jumping the values to their end
221f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * state.
222f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
223f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private void endSoftwareAnimations() {
224f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mSoftwareAnimator != null) {
225f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mSoftwareAnimator.end();
226fc8882f1340055e00f6c21449983e92413045275Alan Viverette            mSoftwareAnimator = null;
227f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
228f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
229f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
230f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
231f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Ends any pending or current hardware animations.
232f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * <p>
233f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Hardware animations can't synchronize values back to the software
234f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * thread, so there is no "cancel" equivalent.
235f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
236f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    private void endHardwareAnimations() {
237f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mHardwareAnimator != null) {
238f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHardwareAnimator.end();
239f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHardwareAnimator = null;
240f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
241f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
242f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (mHasPendingHardwareAnimator) {
243f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mHasPendingHardwareAnimator = false;
244c3b68dff1654f95a9512027b29e8da49a15f4194Alan Viverette
245c3b68dff1654f95a9512027b29e8da49a15f4194Alan Viverette            // Manually jump values to their exited state. Normally we'd do that
246c3b68dff1654f95a9512027b29e8da49a15f4194Alan Viverette            // later when starting the hardware exit, but we're aborting early.
247c3b68dff1654f95a9512027b29e8da49a15f4194Alan Viverette            jumpValuesToExit();
248f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
249f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
250f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
251f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected final void invalidateSelf() {
25215ce834e52806378d6ab2b90f573bae14cb3fd4bAlan Viverette        mOwner.invalidateSelf(false);
253f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
254f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
255f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected final boolean isHardwareAnimating() {
256f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        return mHardwareAnimator != null && mHardwareAnimator.isRunning()
257f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                || mHasPendingHardwareAnimator;
258f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
259f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
260f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected final void onHotspotBoundsChanged() {
261f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        if (!mHasMaxRadius) {
262f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final float halfWidth = mBounds.width() / 2.0f;
263f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final float halfHeight = mBounds.height() / 2.0f;
264f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final float targetRadius = (float) Math.sqrt(halfWidth * halfWidth
265f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                    + halfHeight * halfHeight);
266f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
267f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            onTargetRadiusChanged(targetRadius);
268f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
269f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
270f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
271f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
272f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Called when the target radius changes.
273f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     *
274f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * @param targetRadius the new target radius
275f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
276f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected void onTargetRadiusChanged(float targetRadius) {
277f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        // Stub.
278f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
279f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
280f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract Animator createSoftwareEnter(boolean fast);
281f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
282f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract Animator createSoftwareExit();
283f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
284f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract RenderNodeAnimatorSet createHardwareExit(Paint p);
285f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
286f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik    protected abstract boolean drawHardware(DisplayListCanvas c);
287f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
288f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract boolean drawSoftware(Canvas c, Paint p);
289f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
290f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    /**
291f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * Called when the hardware exit is cancelled. Jumps software values to end
292f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     * state to ensure that software and hardware values are synchronized.
293f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette     */
294f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    protected abstract void jumpValuesToExit();
295f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
296f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    public static class RenderNodeAnimatorSet {
297f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        private final ArrayList<RenderNodeAnimator> mAnimators = new ArrayList<>();
298f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
299f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public void add(RenderNodeAnimator anim) {
300f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mAnimators.add(anim);
301f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
302f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
303f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public void clear() {
304f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            mAnimators.clear();
305f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
306f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
307f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik        public void start(DisplayListCanvas target) {
308f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            if (target == null) {
309f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                throw new IllegalArgumentException("Hardware canvas must be non-null");
310f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
311f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
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.setTarget(target);
317f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                anim.start();
318f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
319f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
320f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
321f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public void cancel() {
322f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final ArrayList<RenderNodeAnimator> animators = mAnimators;
323f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final int N = animators.size();
324f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            for (int i = 0; i < N; i++) {
325f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                final RenderNodeAnimator anim = animators.get(i);
326f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                anim.cancel();
327f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
328f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
329f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
330f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public void end() {
331f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final ArrayList<RenderNodeAnimator> animators = mAnimators;
332f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final int N = animators.size();
333f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            for (int i = 0; i < N; i++) {
334f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                final RenderNodeAnimator anim = animators.get(i);
335f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                anim.end();
336f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
337f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
338f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette
339f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        public boolean isRunning() {
340f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final ArrayList<RenderNodeAnimator> animators = mAnimators;
341f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            final int N = animators.size();
342f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            for (int i = 0; i < N; i++) {
343f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                final RenderNodeAnimator anim = animators.get(i);
344f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                if (anim.isRunning()) {
345f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                    return true;
346f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette                }
347f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            }
348f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette            return false;
349f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette        }
350f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette    }
351f872ee0057ed247aa93589347f1b53afc99517f8Alan Viverette}
352