1e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck/*
2e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * Copyright (C) 2014 The Android Open Source Project
3e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck *
4e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * Licensed under the Apache License, Version 2.0 (the "License");
5e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * you may not use this file except in compliance with the License.
6e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * You may obtain a copy of the License at
7e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck *
8e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck *      http://www.apache.org/licenses/LICENSE-2.0
9e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck *
10e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * Unless required by applicable law or agreed to in writing, software
11e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * distributed under the License is distributed on an "AS IS" BASIS,
12e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * See the License for the specific language governing permissions and
14e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * limitations under the License.
15e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck */
16e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
17e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reckpackage android.view;
18e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
19ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viveretteimport android.animation.Animator;
20315c329544d7c593d1072b071cbb92d9afe74021John Reckimport android.animation.TimeInterpolator;
218d8af3c1b768d590754d657a7d1242dcb462454bJohn Reckimport android.animation.ValueAnimator;
221c058e96b3fb5075c34b89cf22773373811abf7aJohn Reckimport android.graphics.Canvas;
2352244fff29042926e21fa897ef5ab11148e35299John Reckimport android.graphics.CanvasProperty;
2452244fff29042926e21fa897ef5ab11148e35299John Reckimport android.graphics.Paint;
25e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reckimport android.util.SparseIntArray;
26e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
279fa4071c4768c63902c6a74a4b480b51a8b95d43John Reckimport com.android.internal.util.VirtualRefBasePtr;
28315c329544d7c593d1072b071cbb92d9afe74021John Reckimport com.android.internal.view.animation.FallbackLUTInterpolator;
29315c329544d7c593d1072b071cbb92d9afe74021John Reckimport com.android.internal.view.animation.HasNativeInterpolator;
30315c329544d7c593d1072b071cbb92d9afe74021John Reckimport com.android.internal.view.animation.NativeInterpolatorFactory;
319fa4071c4768c63902c6a74a4b480b51a8b95d43John Reck
32ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viveretteimport java.util.ArrayList;
33e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
34e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck/**
35e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck * @hide
36e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck */
378d8af3c1b768d590754d657a7d1242dcb462454bJohn Reckpublic class RenderNodeAnimator extends Animator {
38e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    // Keep in sync with enum RenderProperty in Animator.h
3952244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int TRANSLATION_X = 0;
4052244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int TRANSLATION_Y = 1;
4152244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int TRANSLATION_Z = 2;
4252244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int SCALE_X = 3;
4352244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int SCALE_Y = 4;
4452244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int ROTATION = 5;
4552244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int ROTATION_X = 6;
4652244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int ROTATION_Y = 7;
4752244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int X = 8;
4852244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int Y = 9;
4952244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int Z = 10;
5052244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int ALPHA = 11;
51918988c1ce5af002d41c7ac37f3fa490558b0c90John Reck    // The last value in the enum, used for array size initialization
52918988c1ce5af002d41c7ac37f3fa490558b0c90John Reck    public static final int LAST_VALUE = ALPHA;
5352244fff29042926e21fa897ef5ab11148e35299John Reck
5452244fff29042926e21fa897ef5ab11148e35299John Reck    // Keep in sync with enum PaintFields in Animator.h
5552244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int PAINT_STROKE_WIDTH = 0;
56ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
57ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    /**
58ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     * Field for the Paint alpha channel, which should be specified as a value
59ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     * between 0 and 255.
60ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     */
6152244fff29042926e21fa897ef5ab11148e35299John Reck    public static final int PAINT_ALPHA = 1;
62e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
63e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    // ViewPropertyAnimator uses a mask for its values, we need to remap them
64e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    // to the enum values here. RenderPropertyAnimator can't use the mask values
65e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    // directly as internally it uses a lookup table so it needs the values to
66e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    // be sequential starting from 0
67e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    private static final SparseIntArray sViewPropertyAnimatorMap = new SparseIntArray(15) {{
68e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.TRANSLATION_X, TRANSLATION_X);
69e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.TRANSLATION_Y, TRANSLATION_Y);
70e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.TRANSLATION_Z, TRANSLATION_Z);
71e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.SCALE_X, SCALE_X);
72e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.SCALE_Y, SCALE_Y);
73e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.ROTATION, ROTATION);
74e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.ROTATION_X, ROTATION_X);
75e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.ROTATION_Y, ROTATION_Y);
76e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.X, X);
77e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.Y, Y);
78e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.Z, Z);
79e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        put(ViewPropertyAnimator.ALPHA, ALPHA);
80e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }};
81e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
829fa4071c4768c63902c6a74a4b480b51a8b95d43John Reck    private VirtualRefBasePtr mNativePtr;
83e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
84315c329544d7c593d1072b071cbb92d9afe74021John Reck    private RenderNode mTarget;
85ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    private View mViewTarget;
868d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck    private int mRenderProperty = -1;
878d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck    private float mFinalValue;
88315c329544d7c593d1072b071cbb92d9afe74021John Reck    private TimeInterpolator mInterpolator;
89ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
904d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck    private static final int STATE_PREPARE = 0;
914d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck    private static final int STATE_DELAYED = 1;
924d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck    private static final int STATE_RUNNING = 2;
934d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck    private static final int STATE_FINISHED = 3;
944d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck    private int mState = STATE_PREPARE;
95315c329544d7c593d1072b071cbb92d9afe74021John Reck
968d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck    private long mUnscaledDuration = 300;
978d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck    private long mUnscaledStartDelay = 0;
98291161ac3815fb853fd6af21055d60f57a869608John Reck    // If this is true, we will run any start delays on the UI thread. This is
99291161ac3815fb853fd6af21055d60f57a869608John Reck    // the safe default, and is necessary to ensure start listeners fire at
100291161ac3815fb853fd6af21055d60f57a869608John Reck    // the correct time. Animators created by RippleDrawable (the
101291161ac3815fb853fd6af21055d60f57a869608John Reck    // CanvasProperty<> ones) do not have this expectation, and as such will
102291161ac3815fb853fd6af21055d60f57a869608John Reck    // set this to false so that the renderthread handles the startdelay instead
103291161ac3815fb853fd6af21055d60f57a869608John Reck    private final boolean mUiThreadHandlesDelay;
104291161ac3815fb853fd6af21055d60f57a869608John Reck    private long mStartDelay = 0;
105291161ac3815fb853fd6af21055d60f57a869608John Reck    private long mStartTime;
1068d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck
107918988c1ce5af002d41c7ac37f3fa490558b0c90John Reck    public static int mapViewPropertyToRenderProperty(int viewProperty) {
108e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        return sViewPropertyAnimatorMap.get(viewProperty);
109e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
110e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
111ff941dcd815021bb20d6504eb486acb1e50592c3John Reck    public RenderNodeAnimator(int property, float finalValue) {
1128d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        mRenderProperty = property;
1138d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        mFinalValue = finalValue;
114291161ac3815fb853fd6af21055d60f57a869608John Reck        mUiThreadHandlesDelay = true;
115119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck        init(nCreateAnimator(property, finalValue));
116e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
117e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
118ff941dcd815021bb20d6504eb486acb1e50592c3John Reck    public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
1199fa4071c4768c63902c6a74a4b480b51a8b95d43John Reck        init(nCreateCanvasPropertyFloatAnimator(
120ff941dcd815021bb20d6504eb486acb1e50592c3John Reck                property.getNativeContainer(), finalValue));
121291161ac3815fb853fd6af21055d60f57a869608John Reck        mUiThreadHandlesDelay = false;
12252244fff29042926e21fa897ef5ab11148e35299John Reck    }
12352244fff29042926e21fa897ef5ab11148e35299John Reck
124ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    /**
125ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     * Creates a new render node animator for a field on a Paint property.
126ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     *
127ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     * @param property The paint property to target
128ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
129ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     *            {@link #PAINT_STROKE_WIDTH}
130ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     * @param finalValue The target value for the property
131ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette     */
132ff941dcd815021bb20d6504eb486acb1e50592c3John Reck    public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
1339fa4071c4768c63902c6a74a4b480b51a8b95d43John Reck        init(nCreateCanvasPropertyPaintAnimator(
134ff941dcd815021bb20d6504eb486acb1e50592c3John Reck                property.getNativeContainer(), paintField, finalValue));
135291161ac3815fb853fd6af21055d60f57a869608John Reck        mUiThreadHandlesDelay = false;
1369fa4071c4768c63902c6a74a4b480b51a8b95d43John Reck    }
1379fa4071c4768c63902c6a74a4b480b51a8b95d43John Reck
138af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik    public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
139119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck        init(nCreateRevealAnimator(x, y, startRadius, endRadius));
140291161ac3815fb853fd6af21055d60f57a869608John Reck        mUiThreadHandlesDelay = true;
141d3de42cae84fadfa1befd082a2cf1bf72f9ad82aJohn Reck    }
142d3de42cae84fadfa1befd082a2cf1bf72f9ad82aJohn Reck
1439fa4071c4768c63902c6a74a4b480b51a8b95d43John Reck    private void init(long ptr) {
1449fa4071c4768c63902c6a74a4b480b51a8b95d43John Reck        mNativePtr = new VirtualRefBasePtr(ptr);
14552244fff29042926e21fa897ef5ab11148e35299John Reck    }
14652244fff29042926e21fa897ef5ab11148e35299John Reck
147315c329544d7c593d1072b071cbb92d9afe74021John Reck    private void checkMutable() {
1484d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        if (mState != STATE_PREPARE) {
149315c329544d7c593d1072b071cbb92d9afe74021John Reck            throw new IllegalStateException("Animator has already started, cannot change it now!");
150315c329544d7c593d1072b071cbb92d9afe74021John Reck        }
151c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        if (mNativePtr == null) {
152c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            throw new IllegalStateException("Animator's target has been destroyed "
153c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck                    + "(trying to modify an animation after activity destroy?)");
154c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        }
155315c329544d7c593d1072b071cbb92d9afe74021John Reck    }
156315c329544d7c593d1072b071cbb92d9afe74021John Reck
157918988c1ce5af002d41c7ac37f3fa490558b0c90John Reck    static boolean isNativeInterpolator(TimeInterpolator interpolator) {
158918988c1ce5af002d41c7ac37f3fa490558b0c90John Reck        return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class);
159918988c1ce5af002d41c7ac37f3fa490558b0c90John Reck    }
160918988c1ce5af002d41c7ac37f3fa490558b0c90John Reck
161315c329544d7c593d1072b071cbb92d9afe74021John Reck    private void applyInterpolator() {
162315c329544d7c593d1072b071cbb92d9afe74021John Reck        if (mInterpolator == null) return;
163315c329544d7c593d1072b071cbb92d9afe74021John Reck
164315c329544d7c593d1072b071cbb92d9afe74021John Reck        long ni;
165918988c1ce5af002d41c7ac37f3fa490558b0c90John Reck        if (isNativeInterpolator(mInterpolator)) {
166315c329544d7c593d1072b071cbb92d9afe74021John Reck            ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
167315c329544d7c593d1072b071cbb92d9afe74021John Reck        } else {
168ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette            long duration = nGetDuration(mNativePtr.get());
169315c329544d7c593d1072b071cbb92d9afe74021John Reck            ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
170315c329544d7c593d1072b071cbb92d9afe74021John Reck        }
171315c329544d7c593d1072b071cbb92d9afe74021John Reck        nSetInterpolator(mNativePtr.get(), ni);
172315c329544d7c593d1072b071cbb92d9afe74021John Reck    }
173315c329544d7c593d1072b071cbb92d9afe74021John Reck
174ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
175ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void start() {
176ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        if (mTarget == null) {
177ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette            throw new IllegalStateException("Missing target!");
178ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        }
179ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
1804d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        if (mState != STATE_PREPARE) {
181315c329544d7c593d1072b071cbb92d9afe74021John Reck            throw new IllegalStateException("Already started!");
182315c329544d7c593d1072b071cbb92d9afe74021John Reck        }
183ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
1844d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        mState = STATE_DELAYED;
185315c329544d7c593d1072b071cbb92d9afe74021John Reck        applyInterpolator();
186291161ac3815fb853fd6af21055d60f57a869608John Reck
187c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        if (mNativePtr == null) {
188c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            // It's dead, immediately cancel
189c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            cancel();
190c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        } else if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
191291161ac3815fb853fd6af21055d60f57a869608John Reck            nSetStartDelay(mNativePtr.get(), mStartDelay);
192291161ac3815fb853fd6af21055d60f57a869608John Reck            doStart();
193291161ac3815fb853fd6af21055d60f57a869608John Reck        } else {
194291161ac3815fb853fd6af21055d60f57a869608John Reck            getHelper().addDelayedAnimation(this);
195291161ac3815fb853fd6af21055d60f57a869608John Reck        }
196291161ac3815fb853fd6af21055d60f57a869608John Reck    }
197291161ac3815fb853fd6af21055d60f57a869608John Reck
198291161ac3815fb853fd6af21055d60f57a869608John Reck    private void doStart() {
1998d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        // Alpha is a special snowflake that has the canonical value stored
2008d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        // in mTransformationInfo instead of in RenderNode, so we need to update
2018d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        // it with the final value here.
2028d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        if (mRenderProperty == RenderNodeAnimator.ALPHA) {
2038d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck            // Don't need null check because ViewPropertyAnimator's
2048d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck            // ctor calls ensureTransformationInfo()
2058d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck            mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
2068d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        }
207ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
20872d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck        moveToRunningState();
209ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
210ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        if (mViewTarget != null) {
211ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette            // Kick off a frame to start the process
212ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette            mViewTarget.invalidateViewProperty(true, false);
213ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        }
214ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
215ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
21672d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck    private void moveToRunningState() {
21772d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck        mState = STATE_RUNNING;
218c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        if (mNativePtr != null) {
219c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            nStart(mNativePtr.get());
220c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        }
22172d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck        notifyStartListeners();
22272d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck    }
22372d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck
2244d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck    private void notifyStartListeners() {
2254d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        final ArrayList<AnimatorListener> listeners = cloneListeners();
2264d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        final int numListeners = listeners == null ? 0 : listeners.size();
2274d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        for (int i = 0; i < numListeners; i++) {
2284d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck            listeners.get(i).onAnimationStart(this);
2294d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        }
2304d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck    }
2314d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck
232ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
233ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void cancel() {
23455b46eff394e23cde692e8acdfd7b42676a3f198John Reck        if (mState != STATE_PREPARE && mState != STATE_FINISHED) {
2354d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck            if (mState == STATE_DELAYED) {
2364d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck                getHelper().removeDelayedAnimation(this);
23772d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck                moveToRunningState();
2384d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck            }
23968bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck
2403b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck            final ArrayList<AnimatorListener> listeners = cloneListeners();
24168bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck            final int numListeners = listeners == null ? 0 : listeners.size();
24268bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck            for (int i = 0; i < numListeners; i++) {
24368bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck                listeners.get(i).onAnimationCancel(this);
24468bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck            }
2454d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck
246c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            end();
247ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        }
248ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
249ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
250ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
251ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void end() {
2524d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        if (mState != STATE_FINISHED) {
25372d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck            if (mState < STATE_RUNNING) {
25472d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck                getHelper().removeDelayedAnimation(this);
25572d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck                doStart();
25672d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck            }
257c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            if (mNativePtr != null) {
258c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck                nEnd(mNativePtr.get());
259c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck                if (mViewTarget != null) {
260c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck                    // Kick off a frame to flush the state change
261c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck                    mViewTarget.invalidateViewProperty(true, false);
262c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck                }
263c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            } else {
264c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck                // It's already dead, jump to onFinish
265c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck                onFinished();
26672d6e4facb1abd81809fdaddbe42f41ad885189cJohn Reck            }
267d3de42cae84fadfa1befd082a2cf1bf72f9ad82aJohn Reck        }
268ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
269ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
270ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
271ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void pause() {
272ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        throw new UnsupportedOperationException();
273ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
274ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
275ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
276ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void resume() {
277ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        throw new UnsupportedOperationException();
278315c329544d7c593d1072b071cbb92d9afe74021John Reck    }
279315c329544d7c593d1072b071cbb92d9afe74021John Reck
280ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void setTarget(View view) {
281ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        mViewTarget = view;
282119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck        setTarget(mViewTarget.mRenderNode);
283e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
284e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
285ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void setTarget(Canvas canvas) {
286c9070ebd13263a341511cf779087a46750021196Chris Craik        if (!(canvas instanceof DisplayListCanvas)) {
2871c058e96b3fb5075c34b89cf22773373811abf7aJohn Reck            throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
2881c058e96b3fb5075c34b89cf22773373811abf7aJohn Reck        }
289c9070ebd13263a341511cf779087a46750021196Chris Craik        final DisplayListCanvas recordingCanvas = (DisplayListCanvas) canvas;
290ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        setTarget(recordingCanvas.mNode);
2911c058e96b3fb5075c34b89cf22773373811abf7aJohn Reck    }
2921c058e96b3fb5075c34b89cf22773373811abf7aJohn Reck
293119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck    private void setTarget(RenderNode node) {
294c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        checkMutable();
2958d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        if (mTarget != null) {
2968d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck            throw new IllegalStateException("Target already set!");
2978d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        }
298c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        nSetListener(mNativePtr.get(), this);
299ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        mTarget = node;
3008d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        mTarget.addAnimator(this);
301e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
302e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
303c6b3264e16f1d2b72e7f9508559981ce9970157cJohn Reck    public void setStartValue(float startValue) {
304c6b3264e16f1d2b72e7f9508559981ce9970157cJohn Reck        checkMutable();
305c6b3264e16f1d2b72e7f9508559981ce9970157cJohn Reck        nSetStartValue(mNativePtr.get(), startValue);
306c6b3264e16f1d2b72e7f9508559981ce9970157cJohn Reck    }
307c6b3264e16f1d2b72e7f9508559981ce9970157cJohn Reck
308ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
309ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public void setStartDelay(long startDelay) {
310ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        checkMutable();
31168bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck        if (startDelay < 0) {
31268bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck            throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
31368bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck        }
3148d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        mUnscaledStartDelay = startDelay;
315291161ac3815fb853fd6af21055d60f57a869608John Reck        mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
316ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
317ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
318ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
319ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public long getStartDelay() {
3208d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        return mUnscaledStartDelay;
321ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
322ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
323ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
324ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public RenderNodeAnimator setDuration(long duration) {
325315c329544d7c593d1072b071cbb92d9afe74021John Reck        checkMutable();
32668bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck        if (duration < 0) {
32768bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck            throw new IllegalArgumentException("duration must be positive; " + duration);
32868bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck        }
3298d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        mUnscaledDuration = duration;
3308d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
331ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        return this;
332e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
333e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
334ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
335ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public long getDuration() {
3368d8af3c1b768d590754d657a7d1242dcb462454bJohn Reck        return mUnscaledDuration;
337ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
338ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
3391309914ebf21e705fc59d7d44014124d8a21a2d2Doris Liu    @Override
3401309914ebf21e705fc59d7d44014124d8a21a2d2Doris Liu    public long getTotalDuration() {
3411309914ebf21e705fc59d7d44014124d8a21a2d2Doris Liu        return mUnscaledDuration + mUnscaledStartDelay;
3421309914ebf21e705fc59d7d44014124d8a21a2d2Doris Liu    }
3431309914ebf21e705fc59d7d44014124d8a21a2d2Doris Liu
344ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
345ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public boolean isRunning() {
3464d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        return mState == STATE_DELAYED || mState == STATE_RUNNING;
347ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
348ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
349ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
350d3de42cae84fadfa1befd082a2cf1bf72f9ad82aJohn Reck    public boolean isStarted() {
3514d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        return mState != STATE_PREPARE;
352d3de42cae84fadfa1befd082a2cf1bf72f9ad82aJohn Reck    }
353d3de42cae84fadfa1befd082a2cf1bf72f9ad82aJohn Reck
354d3de42cae84fadfa1befd082a2cf1bf72f9ad82aJohn Reck    @Override
355315c329544d7c593d1072b071cbb92d9afe74021John Reck    public void setInterpolator(TimeInterpolator interpolator) {
356315c329544d7c593d1072b071cbb92d9afe74021John Reck        checkMutable();
357315c329544d7c593d1072b071cbb92d9afe74021John Reck        mInterpolator = interpolator;
358315c329544d7c593d1072b071cbb92d9afe74021John Reck    }
359315c329544d7c593d1072b071cbb92d9afe74021John Reck
360ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    @Override
361ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    public TimeInterpolator getInterpolator() {
362ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        return mInterpolator;
363e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
364e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
365291161ac3815fb853fd6af21055d60f57a869608John Reck    protected void onFinished() {
366c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        if (mState == STATE_PREPARE) {
367c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            // Unlikely but possible, the native side has been destroyed
368c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            // before we have started.
369c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            releaseNativePtr();
370c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            return;
371c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        }
3724d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        if (mState == STATE_DELAYED) {
3734d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck            getHelper().removeDelayedAnimation(this);
3744d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck            notifyStartListeners();
3754d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        }
3764d2c47206a8e1706e5f89ef73c0e50e7321bf862John Reck        mState = STATE_FINISHED;
377ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
3783b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck        final ArrayList<AnimatorListener> listeners = cloneListeners();
379ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        final int numListeners = listeners == null ? 0 : listeners.size();
380ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        for (int i = 0; i < numListeners; i++) {
381ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette            listeners.get(i).onAnimationEnd(this);
382ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        }
383119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck
384119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck        // Release the native object, as it has a global reference to us. This
385119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck        // breaks the cyclic reference chain, and allows this object to be
386119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck        // GC'd
387c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        releaseNativePtr();
388c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck    }
389c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck
390c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck    private void releaseNativePtr() {
391c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        if (mNativePtr != null) {
392c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            mNativePtr.release();
393c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck            mNativePtr = null;
394c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck        }
395ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    }
396ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette
3973b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck    @SuppressWarnings("unchecked")
3983b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck    private ArrayList<AnimatorListener> cloneListeners() {
3993b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck        ArrayList<AnimatorListener> listeners = getListeners();
4003b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck        if (listeners != null) {
4013b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck            listeners = (ArrayList<AnimatorListener>) listeners.clone();
4023b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck        }
4033b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck        return listeners;
4043b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck    }
4053b27e59e1ea3b9928d2ddd0d37c0a13d83ae834bJohn Reck
406ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    long getNativeAnimator() {
407ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette        return mNativePtr.get();
408e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
409e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
410291161ac3815fb853fd6af21055d60f57a869608John Reck    /**
411291161ac3815fb853fd6af21055d60f57a869608John Reck     * @return true if the animator was started, false if still delayed
412291161ac3815fb853fd6af21055d60f57a869608John Reck     */
413291161ac3815fb853fd6af21055d60f57a869608John Reck    private boolean processDelayed(long frameTimeMs) {
414291161ac3815fb853fd6af21055d60f57a869608John Reck        if (mStartTime == 0) {
415291161ac3815fb853fd6af21055d60f57a869608John Reck            mStartTime = frameTimeMs;
416291161ac3815fb853fd6af21055d60f57a869608John Reck        } else if ((frameTimeMs - mStartTime) >= mStartDelay) {
417291161ac3815fb853fd6af21055d60f57a869608John Reck            doStart();
418291161ac3815fb853fd6af21055d60f57a869608John Reck            return true;
419291161ac3815fb853fd6af21055d60f57a869608John Reck        }
420291161ac3815fb853fd6af21055d60f57a869608John Reck        return false;
421291161ac3815fb853fd6af21055d60f57a869608John Reck    }
422291161ac3815fb853fd6af21055d60f57a869608John Reck
423291161ac3815fb853fd6af21055d60f57a869608John Reck    private static DelayedAnimationHelper getHelper() {
424291161ac3815fb853fd6af21055d60f57a869608John Reck        DelayedAnimationHelper helper = sAnimationHelper.get();
425291161ac3815fb853fd6af21055d60f57a869608John Reck        if (helper == null) {
426291161ac3815fb853fd6af21055d60f57a869608John Reck            helper = new DelayedAnimationHelper();
427291161ac3815fb853fd6af21055d60f57a869608John Reck            sAnimationHelper.set(helper);
428291161ac3815fb853fd6af21055d60f57a869608John Reck        }
429291161ac3815fb853fd6af21055d60f57a869608John Reck        return helper;
430291161ac3815fb853fd6af21055d60f57a869608John Reck    }
431291161ac3815fb853fd6af21055d60f57a869608John Reck
432291161ac3815fb853fd6af21055d60f57a869608John Reck    private static ThreadLocal<DelayedAnimationHelper> sAnimationHelper =
433291161ac3815fb853fd6af21055d60f57a869608John Reck            new ThreadLocal<DelayedAnimationHelper>();
434291161ac3815fb853fd6af21055d60f57a869608John Reck
435291161ac3815fb853fd6af21055d60f57a869608John Reck    private static class DelayedAnimationHelper implements Runnable {
436291161ac3815fb853fd6af21055d60f57a869608John Reck
437291161ac3815fb853fd6af21055d60f57a869608John Reck        private ArrayList<RenderNodeAnimator> mDelayedAnims = new ArrayList<RenderNodeAnimator>();
438291161ac3815fb853fd6af21055d60f57a869608John Reck        private final Choreographer mChoreographer;
439291161ac3815fb853fd6af21055d60f57a869608John Reck        private boolean mCallbackScheduled;
440291161ac3815fb853fd6af21055d60f57a869608John Reck
441291161ac3815fb853fd6af21055d60f57a869608John Reck        public DelayedAnimationHelper() {
442291161ac3815fb853fd6af21055d60f57a869608John Reck            mChoreographer = Choreographer.getInstance();
443291161ac3815fb853fd6af21055d60f57a869608John Reck        }
444291161ac3815fb853fd6af21055d60f57a869608John Reck
445291161ac3815fb853fd6af21055d60f57a869608John Reck        public void addDelayedAnimation(RenderNodeAnimator animator) {
446291161ac3815fb853fd6af21055d60f57a869608John Reck            mDelayedAnims.add(animator);
447291161ac3815fb853fd6af21055d60f57a869608John Reck            scheduleCallback();
448291161ac3815fb853fd6af21055d60f57a869608John Reck        }
449291161ac3815fb853fd6af21055d60f57a869608John Reck
450291161ac3815fb853fd6af21055d60f57a869608John Reck        public void removeDelayedAnimation(RenderNodeAnimator animator) {
451291161ac3815fb853fd6af21055d60f57a869608John Reck            mDelayedAnims.remove(animator);
452291161ac3815fb853fd6af21055d60f57a869608John Reck        }
453291161ac3815fb853fd6af21055d60f57a869608John Reck
454291161ac3815fb853fd6af21055d60f57a869608John Reck        private void scheduleCallback() {
455291161ac3815fb853fd6af21055d60f57a869608John Reck            if (!mCallbackScheduled) {
456291161ac3815fb853fd6af21055d60f57a869608John Reck                mCallbackScheduled = true;
457291161ac3815fb853fd6af21055d60f57a869608John Reck                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
458291161ac3815fb853fd6af21055d60f57a869608John Reck            }
459291161ac3815fb853fd6af21055d60f57a869608John Reck        }
460291161ac3815fb853fd6af21055d60f57a869608John Reck
461291161ac3815fb853fd6af21055d60f57a869608John Reck        @Override
462291161ac3815fb853fd6af21055d60f57a869608John Reck        public void run() {
463291161ac3815fb853fd6af21055d60f57a869608John Reck            long frameTimeMs = mChoreographer.getFrameTime();
464291161ac3815fb853fd6af21055d60f57a869608John Reck            mCallbackScheduled = false;
465291161ac3815fb853fd6af21055d60f57a869608John Reck
466291161ac3815fb853fd6af21055d60f57a869608John Reck            int end = 0;
467291161ac3815fb853fd6af21055d60f57a869608John Reck            for (int i = 0; i < mDelayedAnims.size(); i++) {
468291161ac3815fb853fd6af21055d60f57a869608John Reck                RenderNodeAnimator animator = mDelayedAnims.get(i);
469291161ac3815fb853fd6af21055d60f57a869608John Reck                if (!animator.processDelayed(frameTimeMs)) {
470291161ac3815fb853fd6af21055d60f57a869608John Reck                    if (end != i) {
471291161ac3815fb853fd6af21055d60f57a869608John Reck                        mDelayedAnims.set(end, animator);
472291161ac3815fb853fd6af21055d60f57a869608John Reck                    }
473291161ac3815fb853fd6af21055d60f57a869608John Reck                    end++;
474291161ac3815fb853fd6af21055d60f57a869608John Reck                }
475291161ac3815fb853fd6af21055d60f57a869608John Reck            }
476291161ac3815fb853fd6af21055d60f57a869608John Reck            while (mDelayedAnims.size() > end) {
477291161ac3815fb853fd6af21055d60f57a869608John Reck                mDelayedAnims.remove(mDelayedAnims.size() - 1);
478291161ac3815fb853fd6af21055d60f57a869608John Reck            }
479291161ac3815fb853fd6af21055d60f57a869608John Reck
480291161ac3815fb853fd6af21055d60f57a869608John Reck            if (mDelayedAnims.size() > 0) {
481291161ac3815fb853fd6af21055d60f57a869608John Reck                scheduleCallback();
482291161ac3815fb853fd6af21055d60f57a869608John Reck            }
483291161ac3815fb853fd6af21055d60f57a869608John Reck        }
484291161ac3815fb853fd6af21055d60f57a869608John Reck    }
485291161ac3815fb853fd6af21055d60f57a869608John Reck
486e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    // Called by native
487119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck    private static void callOnFinished(RenderNodeAnimator animator) {
488119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck        animator.onFinished();
489e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
490e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
491291161ac3815fb853fd6af21055d60f57a869608John Reck    @Override
492291161ac3815fb853fd6af21055d60f57a869608John Reck    public Animator clone() {
493291161ac3815fb853fd6af21055d60f57a869608John Reck        throw new IllegalStateException("Cannot clone this animator");
494291161ac3815fb853fd6af21055d60f57a869608John Reck    }
495291161ac3815fb853fd6af21055d60f57a869608John Reck
496f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck    @Override
497f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck    public void setAllowRunningAsynchronously(boolean mayRunAsync) {
498f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck        checkMutable();
499f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck        nSetAllowRunningAsync(mNativePtr.get(), mayRunAsync);
500f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck    }
501f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck
502119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck    private static native long nCreateAnimator(int property, float finalValue);
503119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck    private static native long nCreateCanvasPropertyFloatAnimator(
504c6b3264e16f1d2b72e7f9508559981ce9970157cJohn Reck            long canvasProperty, float finalValue);
505119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck    private static native long nCreateCanvasPropertyPaintAnimator(
506c6b3264e16f1d2b72e7f9508559981ce9970157cJohn Reck            long canvasProperty, int paintField, float finalValue);
507119907cd2575c56b1ebf66348b52e67aaf6a88d8John Reck    private static native long nCreateRevealAnimator(
508af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik            int x, int y, float startRadius, float endRadius);
50968bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck
510c6b3264e16f1d2b72e7f9508559981ce9970157cJohn Reck    private static native void nSetStartValue(long nativePtr, float startValue);
511ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    private static native void nSetDuration(long nativePtr, long duration);
512ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    private static native long nGetDuration(long nativePtr);
513ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette    private static native void nSetStartDelay(long nativePtr, long startDelay);
514315c329544d7c593d1072b071cbb92d9afe74021John Reck    private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
515f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck    private static native void nSetAllowRunningAsync(long animPtr, boolean mayRunAsync);
516c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck    private static native void nSetListener(long animPtr, RenderNodeAnimator listener);
51768bfe0a37a0dcef52abd81688d8520c5d16e1a85John Reck
518c47c98be04d602f331e0ea9704d2c11f8c53852dJohn Reck    private static native void nStart(long animPtr);
519d3de42cae84fadfa1befd082a2cf1bf72f9ad82aJohn Reck    private static native void nEnd(long animPtr);
520e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck}
521