blob: 7747580892f1b130891ea65e776d9037950e615c [file] [log] [blame]
John Recke45b1fd2014-04-15 09:50:16 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Alan Viverettead2f8e32014-05-16 13:28:33 -070019import android.animation.Animator;
John Reck315c3292014-05-09 19:21:04 -070020import android.animation.TimeInterpolator;
John Reck8d8af3c2014-07-01 15:23:45 -070021import android.animation.ValueAnimator;
John Reck1c058e92014-05-02 14:20:53 -070022import android.graphics.Canvas;
John Reck52244ff2014-05-01 21:27:37 -070023import android.graphics.CanvasProperty;
24import android.graphics.Paint;
John Recke45b1fd2014-04-15 09:50:16 -070025import android.util.SparseIntArray;
26
John Reck9fa40712014-05-09 15:26:59 -070027import com.android.internal.util.VirtualRefBasePtr;
John Reck315c3292014-05-09 19:21:04 -070028import com.android.internal.view.animation.FallbackLUTInterpolator;
29import com.android.internal.view.animation.HasNativeInterpolator;
30import com.android.internal.view.animation.NativeInterpolatorFactory;
John Reck9fa40712014-05-09 15:26:59 -070031
Alan Viverettead2f8e32014-05-16 13:28:33 -070032import java.util.ArrayList;
John Recke45b1fd2014-04-15 09:50:16 -070033
34/**
35 * @hide
36 */
John Reck8d8af3c2014-07-01 15:23:45 -070037public class RenderNodeAnimator extends Animator {
John Recke45b1fd2014-04-15 09:50:16 -070038 // Keep in sync with enum RenderProperty in Animator.h
John Reck52244ff2014-05-01 21:27:37 -070039 public static final int TRANSLATION_X = 0;
40 public static final int TRANSLATION_Y = 1;
41 public static final int TRANSLATION_Z = 2;
42 public static final int SCALE_X = 3;
43 public static final int SCALE_Y = 4;
44 public static final int ROTATION = 5;
45 public static final int ROTATION_X = 6;
46 public static final int ROTATION_Y = 7;
47 public static final int X = 8;
48 public static final int Y = 9;
49 public static final int Z = 10;
50 public static final int ALPHA = 11;
John Reck918988c2014-05-19 10:28:35 -070051 // The last value in the enum, used for array size initialization
52 public static final int LAST_VALUE = ALPHA;
John Reck52244ff2014-05-01 21:27:37 -070053
54 // Keep in sync with enum PaintFields in Animator.h
55 public static final int PAINT_STROKE_WIDTH = 0;
Alan Viverettead2f8e32014-05-16 13:28:33 -070056
57 /**
58 * Field for the Paint alpha channel, which should be specified as a value
59 * between 0 and 255.
60 */
John Reck52244ff2014-05-01 21:27:37 -070061 public static final int PAINT_ALPHA = 1;
John Recke45b1fd2014-04-15 09:50:16 -070062
63 // ViewPropertyAnimator uses a mask for its values, we need to remap them
64 // to the enum values here. RenderPropertyAnimator can't use the mask values
65 // directly as internally it uses a lookup table so it needs the values to
66 // be sequential starting from 0
67 private static final SparseIntArray sViewPropertyAnimatorMap = new SparseIntArray(15) {{
68 put(ViewPropertyAnimator.TRANSLATION_X, TRANSLATION_X);
69 put(ViewPropertyAnimator.TRANSLATION_Y, TRANSLATION_Y);
70 put(ViewPropertyAnimator.TRANSLATION_Z, TRANSLATION_Z);
71 put(ViewPropertyAnimator.SCALE_X, SCALE_X);
72 put(ViewPropertyAnimator.SCALE_Y, SCALE_Y);
73 put(ViewPropertyAnimator.ROTATION, ROTATION);
74 put(ViewPropertyAnimator.ROTATION_X, ROTATION_X);
75 put(ViewPropertyAnimator.ROTATION_Y, ROTATION_Y);
76 put(ViewPropertyAnimator.X, X);
77 put(ViewPropertyAnimator.Y, Y);
78 put(ViewPropertyAnimator.Z, Z);
79 put(ViewPropertyAnimator.ALPHA, ALPHA);
80 }};
81
John Reck9fa40712014-05-09 15:26:59 -070082 private VirtualRefBasePtr mNativePtr;
John Recke45b1fd2014-04-15 09:50:16 -070083
John Reck315c3292014-05-09 19:21:04 -070084 private RenderNode mTarget;
Alan Viverettead2f8e32014-05-16 13:28:33 -070085 private View mViewTarget;
John Reck8d8af3c2014-07-01 15:23:45 -070086 private int mRenderProperty = -1;
87 private float mFinalValue;
John Reck315c3292014-05-09 19:21:04 -070088 private TimeInterpolator mInterpolator;
Alan Viverettead2f8e32014-05-16 13:28:33 -070089
John Reck4d2c4722014-08-29 10:40:56 -070090 private static final int STATE_PREPARE = 0;
91 private static final int STATE_DELAYED = 1;
92 private static final int STATE_RUNNING = 2;
93 private static final int STATE_FINISHED = 3;
94 private int mState = STATE_PREPARE;
John Reck315c3292014-05-09 19:21:04 -070095
John Reck8d8af3c2014-07-01 15:23:45 -070096 private long mUnscaledDuration = 300;
97 private long mUnscaledStartDelay = 0;
John Reck291161a2014-07-22 07:31:09 -070098 // If this is true, we will run any start delays on the UI thread. This is
99 // the safe default, and is necessary to ensure start listeners fire at
100 // the correct time. Animators created by RippleDrawable (the
101 // CanvasProperty<> ones) do not have this expectation, and as such will
102 // set this to false so that the renderthread handles the startdelay instead
103 private final boolean mUiThreadHandlesDelay;
104 private long mStartDelay = 0;
105 private long mStartTime;
John Reck8d8af3c2014-07-01 15:23:45 -0700106
John Reck918988c2014-05-19 10:28:35 -0700107 public static int mapViewPropertyToRenderProperty(int viewProperty) {
John Recke45b1fd2014-04-15 09:50:16 -0700108 return sViewPropertyAnimatorMap.get(viewProperty);
109 }
110
John Reckff941dc2014-05-14 16:34:14 -0700111 public RenderNodeAnimator(int property, float finalValue) {
John Reck8d8af3c2014-07-01 15:23:45 -0700112 mRenderProperty = property;
113 mFinalValue = finalValue;
John Reck291161a2014-07-22 07:31:09 -0700114 mUiThreadHandlesDelay = true;
John Reck119907c2014-08-14 09:02:01 -0700115 init(nCreateAnimator(property, finalValue));
John Recke45b1fd2014-04-15 09:50:16 -0700116 }
117
John Reckff941dc2014-05-14 16:34:14 -0700118 public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
John Reck9fa40712014-05-09 15:26:59 -0700119 init(nCreateCanvasPropertyFloatAnimator(
John Reckff941dc2014-05-14 16:34:14 -0700120 property.getNativeContainer(), finalValue));
John Reck291161a2014-07-22 07:31:09 -0700121 mUiThreadHandlesDelay = false;
John Reck52244ff2014-05-01 21:27:37 -0700122 }
123
Alan Viverettead2f8e32014-05-16 13:28:33 -0700124 /**
125 * Creates a new render node animator for a field on a Paint property.
126 *
127 * @param property The paint property to target
128 * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
129 * {@link #PAINT_STROKE_WIDTH}
130 * @param finalValue The target value for the property
131 */
John Reckff941dc2014-05-14 16:34:14 -0700132 public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
John Reck9fa40712014-05-09 15:26:59 -0700133 init(nCreateCanvasPropertyPaintAnimator(
John Reckff941dc2014-05-14 16:34:14 -0700134 property.getNativeContainer(), paintField, finalValue));
John Reck291161a2014-07-22 07:31:09 -0700135 mUiThreadHandlesDelay = false;
John Reck9fa40712014-05-09 15:26:59 -0700136 }
137
Chris Craikaf4d04c2014-07-29 12:50:14 -0700138 public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
John Reck119907c2014-08-14 09:02:01 -0700139 init(nCreateRevealAnimator(x, y, startRadius, endRadius));
John Reck291161a2014-07-22 07:31:09 -0700140 mUiThreadHandlesDelay = true;
John Reckd3de42c2014-07-15 14:29:33 -0700141 }
142
John Reck9fa40712014-05-09 15:26:59 -0700143 private void init(long ptr) {
144 mNativePtr = new VirtualRefBasePtr(ptr);
John Reck52244ff2014-05-01 21:27:37 -0700145 }
146
John Reck315c3292014-05-09 19:21:04 -0700147 private void checkMutable() {
John Reck4d2c4722014-08-29 10:40:56 -0700148 if (mState != STATE_PREPARE) {
John Reck315c3292014-05-09 19:21:04 -0700149 throw new IllegalStateException("Animator has already started, cannot change it now!");
150 }
John Reckc47c98b2014-12-09 09:07:35 -0800151 if (mNativePtr == null) {
152 throw new IllegalStateException("Animator's target has been destroyed "
153 + "(trying to modify an animation after activity destroy?)");
154 }
John Reck315c3292014-05-09 19:21:04 -0700155 }
156
John Reck918988c2014-05-19 10:28:35 -0700157 static boolean isNativeInterpolator(TimeInterpolator interpolator) {
158 return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class);
159 }
160
John Reck315c3292014-05-09 19:21:04 -0700161 private void applyInterpolator() {
162 if (mInterpolator == null) return;
163
164 long ni;
John Reck918988c2014-05-19 10:28:35 -0700165 if (isNativeInterpolator(mInterpolator)) {
John Reck315c3292014-05-09 19:21:04 -0700166 ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
167 } else {
Alan Viverettead2f8e32014-05-16 13:28:33 -0700168 long duration = nGetDuration(mNativePtr.get());
John Reck315c3292014-05-09 19:21:04 -0700169 ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
170 }
171 nSetInterpolator(mNativePtr.get(), ni);
172 }
173
Alan Viverettead2f8e32014-05-16 13:28:33 -0700174 @Override
175 public void start() {
176 if (mTarget == null) {
177 throw new IllegalStateException("Missing target!");
178 }
179
John Reck4d2c4722014-08-29 10:40:56 -0700180 if (mState != STATE_PREPARE) {
John Reck315c3292014-05-09 19:21:04 -0700181 throw new IllegalStateException("Already started!");
182 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700183
John Reck4d2c4722014-08-29 10:40:56 -0700184 mState = STATE_DELAYED;
John Reck315c3292014-05-09 19:21:04 -0700185 applyInterpolator();
John Reck291161a2014-07-22 07:31:09 -0700186
John Reckc47c98b2014-12-09 09:07:35 -0800187 if (mNativePtr == null) {
188 // It's dead, immediately cancel
189 cancel();
190 } else if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
John Reck291161a2014-07-22 07:31:09 -0700191 nSetStartDelay(mNativePtr.get(), mStartDelay);
192 doStart();
193 } else {
194 getHelper().addDelayedAnimation(this);
195 }
196 }
197
198 private void doStart() {
John Reck8d8af3c2014-07-01 15:23:45 -0700199 // Alpha is a special snowflake that has the canonical value stored
200 // in mTransformationInfo instead of in RenderNode, so we need to update
201 // it with the final value here.
202 if (mRenderProperty == RenderNodeAnimator.ALPHA) {
203 // Don't need null check because ViewPropertyAnimator's
204 // ctor calls ensureTransformationInfo()
205 mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
206 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700207
John Reck72d6e4f2014-11-21 14:10:10 -0800208 moveToRunningState();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700209
210 if (mViewTarget != null) {
211 // Kick off a frame to start the process
212 mViewTarget.invalidateViewProperty(true, false);
213 }
John Reck315c3292014-05-09 19:21:04 -0700214 }
215
John Reck72d6e4f2014-11-21 14:10:10 -0800216 private void moveToRunningState() {
217 mState = STATE_RUNNING;
John Reckc47c98b2014-12-09 09:07:35 -0800218 if (mNativePtr != null) {
219 nStart(mNativePtr.get());
220 }
John Reck72d6e4f2014-11-21 14:10:10 -0800221 notifyStartListeners();
222 }
223
John Reck4d2c4722014-08-29 10:40:56 -0700224 private void notifyStartListeners() {
225 final ArrayList<AnimatorListener> listeners = cloneListeners();
226 final int numListeners = listeners == null ? 0 : listeners.size();
227 for (int i = 0; i < numListeners; i++) {
228 listeners.get(i).onAnimationStart(this);
229 }
230 }
231
Alan Viverettead2f8e32014-05-16 13:28:33 -0700232 @Override
233 public void cancel() {
John Reck55b46ef2014-11-03 10:00:33 -0800234 if (mState != STATE_PREPARE && mState != STATE_FINISHED) {
John Reck4d2c4722014-08-29 10:40:56 -0700235 if (mState == STATE_DELAYED) {
236 getHelper().removeDelayedAnimation(this);
John Reck72d6e4f2014-11-21 14:10:10 -0800237 moveToRunningState();
John Reck4d2c4722014-08-29 10:40:56 -0700238 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700239
John Reck3b27e592014-08-21 12:37:48 -0700240 final ArrayList<AnimatorListener> listeners = cloneListeners();
John Reck68bfe0a2014-06-24 15:34:58 -0700241 final int numListeners = listeners == null ? 0 : listeners.size();
242 for (int i = 0; i < numListeners; i++) {
243 listeners.get(i).onAnimationCancel(this);
244 }
John Reck4d2c4722014-08-29 10:40:56 -0700245
John Reckc47c98b2014-12-09 09:07:35 -0800246 end();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700247 }
John Recke45b1fd2014-04-15 09:50:16 -0700248 }
249
Alan Viverettead2f8e32014-05-16 13:28:33 -0700250 @Override
251 public void end() {
John Reck4d2c4722014-08-29 10:40:56 -0700252 if (mState != STATE_FINISHED) {
John Reck72d6e4f2014-11-21 14:10:10 -0800253 if (mState < STATE_RUNNING) {
254 getHelper().removeDelayedAnimation(this);
255 doStart();
256 }
John Reckc47c98b2014-12-09 09:07:35 -0800257 if (mNativePtr != null) {
258 nEnd(mNativePtr.get());
259 if (mViewTarget != null) {
260 // Kick off a frame to flush the state change
261 mViewTarget.invalidateViewProperty(true, false);
262 }
263 } else {
264 // It's already dead, jump to onFinish
265 onFinished();
John Reck72d6e4f2014-11-21 14:10:10 -0800266 }
John Reckd3de42c2014-07-15 14:29:33 -0700267 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700268 }
269
270 @Override
271 public void pause() {
272 throw new UnsupportedOperationException();
273 }
274
275 @Override
276 public void resume() {
277 throw new UnsupportedOperationException();
278 }
279
280 public void setTarget(View view) {
281 mViewTarget = view;
John Reck119907c2014-08-14 09:02:01 -0700282 setTarget(mViewTarget.mRenderNode);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700283 }
284
285 public void setTarget(Canvas canvas) {
Chris Craikc9070eb2015-03-09 18:50:14 -0700286 if (!(canvas instanceof DisplayListCanvas)) {
John Reck1c058e92014-05-02 14:20:53 -0700287 throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
288 }
Chris Craikc9070eb2015-03-09 18:50:14 -0700289 final DisplayListCanvas recordingCanvas = (DisplayListCanvas) canvas;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700290 setTarget(recordingCanvas.mNode);
John Reck1c058e92014-05-02 14:20:53 -0700291 }
292
John Reck119907c2014-08-14 09:02:01 -0700293 private void setTarget(RenderNode node) {
John Reckc47c98b2014-12-09 09:07:35 -0800294 checkMutable();
John Reck8d8af3c2014-07-01 15:23:45 -0700295 if (mTarget != null) {
296 throw new IllegalStateException("Target already set!");
297 }
John Reckc47c98b2014-12-09 09:07:35 -0800298 nSetListener(mNativePtr.get(), this);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700299 mTarget = node;
John Reck8d8af3c2014-07-01 15:23:45 -0700300 mTarget.addAnimator(this);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700301 }
302
John Reckc6b32642014-06-02 11:00:09 -0700303 public void setStartValue(float startValue) {
304 checkMutable();
305 nSetStartValue(mNativePtr.get(), startValue);
306 }
307
Alan Viverettead2f8e32014-05-16 13:28:33 -0700308 @Override
309 public void setStartDelay(long startDelay) {
310 checkMutable();
John Reck68bfe0a2014-06-24 15:34:58 -0700311 if (startDelay < 0) {
312 throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
313 }
John Reck8d8af3c2014-07-01 15:23:45 -0700314 mUnscaledStartDelay = startDelay;
John Reck291161a2014-07-22 07:31:09 -0700315 mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700316 }
317
318 @Override
319 public long getStartDelay() {
John Reck8d8af3c2014-07-01 15:23:45 -0700320 return mUnscaledStartDelay;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700321 }
322
323 @Override
324 public RenderNodeAnimator setDuration(long duration) {
John Reck315c3292014-05-09 19:21:04 -0700325 checkMutable();
John Reck68bfe0a2014-06-24 15:34:58 -0700326 if (duration < 0) {
327 throw new IllegalArgumentException("duration must be positive; " + duration);
328 }
John Reck8d8af3c2014-07-01 15:23:45 -0700329 mUnscaledDuration = duration;
330 nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
Alan Viverettead2f8e32014-05-16 13:28:33 -0700331 return this;
John Recke45b1fd2014-04-15 09:50:16 -0700332 }
333
Alan Viverettead2f8e32014-05-16 13:28:33 -0700334 @Override
335 public long getDuration() {
John Reck8d8af3c2014-07-01 15:23:45 -0700336 return mUnscaledDuration;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700337 }
338
Doris Liu13099142015-07-10 17:32:41 -0700339 @Override
340 public long getTotalDuration() {
341 return mUnscaledDuration + mUnscaledStartDelay;
342 }
343
Alan Viverettead2f8e32014-05-16 13:28:33 -0700344 @Override
345 public boolean isRunning() {
John Reck4d2c4722014-08-29 10:40:56 -0700346 return mState == STATE_DELAYED || mState == STATE_RUNNING;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700347 }
348
349 @Override
John Reckd3de42c2014-07-15 14:29:33 -0700350 public boolean isStarted() {
John Reck4d2c4722014-08-29 10:40:56 -0700351 return mState != STATE_PREPARE;
John Reckd3de42c2014-07-15 14:29:33 -0700352 }
353
354 @Override
John Reck315c3292014-05-09 19:21:04 -0700355 public void setInterpolator(TimeInterpolator interpolator) {
356 checkMutable();
357 mInterpolator = interpolator;
358 }
359
Alan Viverettead2f8e32014-05-16 13:28:33 -0700360 @Override
361 public TimeInterpolator getInterpolator() {
362 return mInterpolator;
John Recke45b1fd2014-04-15 09:50:16 -0700363 }
364
John Reck291161a2014-07-22 07:31:09 -0700365 protected void onFinished() {
John Reckc47c98b2014-12-09 09:07:35 -0800366 if (mState == STATE_PREPARE) {
367 // Unlikely but possible, the native side has been destroyed
368 // before we have started.
369 releaseNativePtr();
370 return;
371 }
John Reck4d2c4722014-08-29 10:40:56 -0700372 if (mState == STATE_DELAYED) {
373 getHelper().removeDelayedAnimation(this);
374 notifyStartListeners();
375 }
376 mState = STATE_FINISHED;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700377
John Reck3b27e592014-08-21 12:37:48 -0700378 final ArrayList<AnimatorListener> listeners = cloneListeners();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700379 final int numListeners = listeners == null ? 0 : listeners.size();
380 for (int i = 0; i < numListeners; i++) {
381 listeners.get(i).onAnimationEnd(this);
382 }
John Reck119907c2014-08-14 09:02:01 -0700383
384 // Release the native object, as it has a global reference to us. This
385 // breaks the cyclic reference chain, and allows this object to be
386 // GC'd
John Reckc47c98b2014-12-09 09:07:35 -0800387 releaseNativePtr();
388 }
389
390 private void releaseNativePtr() {
391 if (mNativePtr != null) {
392 mNativePtr.release();
393 mNativePtr = null;
394 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700395 }
396
John Reck3b27e592014-08-21 12:37:48 -0700397 @SuppressWarnings("unchecked")
398 private ArrayList<AnimatorListener> cloneListeners() {
399 ArrayList<AnimatorListener> listeners = getListeners();
400 if (listeners != null) {
401 listeners = (ArrayList<AnimatorListener>) listeners.clone();
402 }
403 return listeners;
404 }
405
Alan Viverettead2f8e32014-05-16 13:28:33 -0700406 long getNativeAnimator() {
407 return mNativePtr.get();
John Recke45b1fd2014-04-15 09:50:16 -0700408 }
409
John Reck291161a2014-07-22 07:31:09 -0700410 /**
411 * @return true if the animator was started, false if still delayed
412 */
413 private boolean processDelayed(long frameTimeMs) {
414 if (mStartTime == 0) {
415 mStartTime = frameTimeMs;
416 } else if ((frameTimeMs - mStartTime) >= mStartDelay) {
417 doStart();
418 return true;
419 }
420 return false;
421 }
422
423 private static DelayedAnimationHelper getHelper() {
424 DelayedAnimationHelper helper = sAnimationHelper.get();
425 if (helper == null) {
426 helper = new DelayedAnimationHelper();
427 sAnimationHelper.set(helper);
428 }
429 return helper;
430 }
431
432 private static ThreadLocal<DelayedAnimationHelper> sAnimationHelper =
433 new ThreadLocal<DelayedAnimationHelper>();
434
435 private static class DelayedAnimationHelper implements Runnable {
436
437 private ArrayList<RenderNodeAnimator> mDelayedAnims = new ArrayList<RenderNodeAnimator>();
438 private final Choreographer mChoreographer;
439 private boolean mCallbackScheduled;
440
441 public DelayedAnimationHelper() {
442 mChoreographer = Choreographer.getInstance();
443 }
444
445 public void addDelayedAnimation(RenderNodeAnimator animator) {
446 mDelayedAnims.add(animator);
447 scheduleCallback();
448 }
449
450 public void removeDelayedAnimation(RenderNodeAnimator animator) {
451 mDelayedAnims.remove(animator);
452 }
453
454 private void scheduleCallback() {
455 if (!mCallbackScheduled) {
456 mCallbackScheduled = true;
457 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
458 }
459 }
460
461 @Override
462 public void run() {
463 long frameTimeMs = mChoreographer.getFrameTime();
464 mCallbackScheduled = false;
465
466 int end = 0;
467 for (int i = 0; i < mDelayedAnims.size(); i++) {
468 RenderNodeAnimator animator = mDelayedAnims.get(i);
469 if (!animator.processDelayed(frameTimeMs)) {
470 if (end != i) {
471 mDelayedAnims.set(end, animator);
472 }
473 end++;
474 }
475 }
476 while (mDelayedAnims.size() > end) {
477 mDelayedAnims.remove(mDelayedAnims.size() - 1);
478 }
479
480 if (mDelayedAnims.size() > 0) {
481 scheduleCallback();
482 }
483 }
484 }
485
John Recke45b1fd2014-04-15 09:50:16 -0700486 // Called by native
John Reck119907c2014-08-14 09:02:01 -0700487 private static void callOnFinished(RenderNodeAnimator animator) {
488 animator.onFinished();
John Recke45b1fd2014-04-15 09:50:16 -0700489 }
490
John Reck291161a2014-07-22 07:31:09 -0700491 @Override
492 public Animator clone() {
493 throw new IllegalStateException("Cannot clone this animator");
494 }
495
John Reckf5945a02014-09-05 15:57:47 -0700496 @Override
497 public void setAllowRunningAsynchronously(boolean mayRunAsync) {
498 checkMutable();
499 nSetAllowRunningAsync(mNativePtr.get(), mayRunAsync);
500 }
501
John Reck119907c2014-08-14 09:02:01 -0700502 private static native long nCreateAnimator(int property, float finalValue);
503 private static native long nCreateCanvasPropertyFloatAnimator(
John Reckc6b32642014-06-02 11:00:09 -0700504 long canvasProperty, float finalValue);
John Reck119907c2014-08-14 09:02:01 -0700505 private static native long nCreateCanvasPropertyPaintAnimator(
John Reckc6b32642014-06-02 11:00:09 -0700506 long canvasProperty, int paintField, float finalValue);
John Reck119907c2014-08-14 09:02:01 -0700507 private static native long nCreateRevealAnimator(
Chris Craikaf4d04c2014-07-29 12:50:14 -0700508 int x, int y, float startRadius, float endRadius);
John Reck68bfe0a2014-06-24 15:34:58 -0700509
John Reckc6b32642014-06-02 11:00:09 -0700510 private static native void nSetStartValue(long nativePtr, float startValue);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700511 private static native void nSetDuration(long nativePtr, long duration);
512 private static native long nGetDuration(long nativePtr);
513 private static native void nSetStartDelay(long nativePtr, long startDelay);
John Reck315c3292014-05-09 19:21:04 -0700514 private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
John Reckf5945a02014-09-05 15:57:47 -0700515 private static native void nSetAllowRunningAsync(long animPtr, boolean mayRunAsync);
John Reckc47c98b2014-12-09 09:07:35 -0800516 private static native void nSetListener(long animPtr, RenderNodeAnimator listener);
John Reck68bfe0a2014-06-24 15:34:58 -0700517
John Reckc47c98b2014-12-09 09:07:35 -0800518 private static native void nStart(long animPtr);
John Reckd3de42c2014-07-15 14:29:33 -0700519 private static native void nEnd(long animPtr);
John Recke45b1fd2014-04-15 09:50:16 -0700520}