blob: 78ad0dabc81a89fc3a4acf3b3e1909a01399fe7b [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;
Mathew Inwooda570dee2018-08-17 14:56:00 +010022import android.annotation.UnsupportedAppUsage;
John Reck52244ff2014-05-01 21:27:37 -070023import android.graphics.CanvasProperty;
24import android.graphics.Paint;
John Reck32f140aa62018-10-04 15:08:24 -070025import android.graphics.RecordingCanvas;
26import android.graphics.RenderNode;
John Recke45b1fd2014-04-15 09:50:16 -070027import android.util.SparseIntArray;
28
John Reck9fa40712014-05-09 15:26:59 -070029import com.android.internal.util.VirtualRefBasePtr;
John Reck315c3292014-05-09 19:21:04 -070030import com.android.internal.view.animation.FallbackLUTInterpolator;
31import com.android.internal.view.animation.HasNativeInterpolator;
32import com.android.internal.view.animation.NativeInterpolatorFactory;
John Reck9fa40712014-05-09 15:26:59 -070033
Alan Viverettead2f8e32014-05-16 13:28:33 -070034import java.util.ArrayList;
John Recke45b1fd2014-04-15 09:50:16 -070035
36/**
37 * @hide
38 */
John Reck8d8af3c2014-07-01 15:23:45 -070039public class RenderNodeAnimator extends Animator {
John Recke45b1fd2014-04-15 09:50:16 -070040 // Keep in sync with enum RenderProperty in Animator.h
John Reck52244ff2014-05-01 21:27:37 -070041 public static final int TRANSLATION_X = 0;
42 public static final int TRANSLATION_Y = 1;
43 public static final int TRANSLATION_Z = 2;
44 public static final int SCALE_X = 3;
45 public static final int SCALE_Y = 4;
46 public static final int ROTATION = 5;
47 public static final int ROTATION_X = 6;
48 public static final int ROTATION_Y = 7;
49 public static final int X = 8;
50 public static final int Y = 9;
51 public static final int Z = 10;
52 public static final int ALPHA = 11;
John Reck918988c2014-05-19 10:28:35 -070053 // The last value in the enum, used for array size initialization
54 public static final int LAST_VALUE = ALPHA;
John Reck52244ff2014-05-01 21:27:37 -070055
56 // Keep in sync with enum PaintFields in Animator.h
57 public static final int PAINT_STROKE_WIDTH = 0;
Alan Viverettead2f8e32014-05-16 13:28:33 -070058
59 /**
60 * Field for the Paint alpha channel, which should be specified as a value
61 * between 0 and 255.
62 */
John Reck52244ff2014-05-01 21:27:37 -070063 public static final int PAINT_ALPHA = 1;
John Recke45b1fd2014-04-15 09:50:16 -070064
65 // ViewPropertyAnimator uses a mask for its values, we need to remap them
66 // to the enum values here. RenderPropertyAnimator can't use the mask values
67 // directly as internally it uses a lookup table so it needs the values to
68 // be sequential starting from 0
69 private static final SparseIntArray sViewPropertyAnimatorMap = new SparseIntArray(15) {{
70 put(ViewPropertyAnimator.TRANSLATION_X, TRANSLATION_X);
71 put(ViewPropertyAnimator.TRANSLATION_Y, TRANSLATION_Y);
72 put(ViewPropertyAnimator.TRANSLATION_Z, TRANSLATION_Z);
73 put(ViewPropertyAnimator.SCALE_X, SCALE_X);
74 put(ViewPropertyAnimator.SCALE_Y, SCALE_Y);
75 put(ViewPropertyAnimator.ROTATION, ROTATION);
76 put(ViewPropertyAnimator.ROTATION_X, ROTATION_X);
77 put(ViewPropertyAnimator.ROTATION_Y, ROTATION_Y);
78 put(ViewPropertyAnimator.X, X);
79 put(ViewPropertyAnimator.Y, Y);
80 put(ViewPropertyAnimator.Z, Z);
81 put(ViewPropertyAnimator.ALPHA, ALPHA);
82 }};
83
John Reck9fa40712014-05-09 15:26:59 -070084 private VirtualRefBasePtr mNativePtr;
John Recke45b1fd2014-04-15 09:50:16 -070085
John Reck315c3292014-05-09 19:21:04 -070086 private RenderNode mTarget;
Alan Viverettead2f8e32014-05-16 13:28:33 -070087 private View mViewTarget;
John Reck8d8af3c2014-07-01 15:23:45 -070088 private int mRenderProperty = -1;
89 private float mFinalValue;
John Reck315c3292014-05-09 19:21:04 -070090 private TimeInterpolator mInterpolator;
Alan Viverettead2f8e32014-05-16 13:28:33 -070091
John Reck4d2c4722014-08-29 10:40:56 -070092 private static final int STATE_PREPARE = 0;
93 private static final int STATE_DELAYED = 1;
94 private static final int STATE_RUNNING = 2;
95 private static final int STATE_FINISHED = 3;
96 private int mState = STATE_PREPARE;
John Reck315c3292014-05-09 19:21:04 -070097
John Reck8d8af3c2014-07-01 15:23:45 -070098 private long mUnscaledDuration = 300;
99 private long mUnscaledStartDelay = 0;
John Reck291161a2014-07-22 07:31:09 -0700100 // If this is true, we will run any start delays on the UI thread. This is
101 // the safe default, and is necessary to ensure start listeners fire at
102 // the correct time. Animators created by RippleDrawable (the
103 // CanvasProperty<> ones) do not have this expectation, and as such will
104 // set this to false so that the renderthread handles the startdelay instead
105 private final boolean mUiThreadHandlesDelay;
106 private long mStartDelay = 0;
107 private long mStartTime;
John Reck8d8af3c2014-07-01 15:23:45 -0700108
Mathew Inwooda570dee2018-08-17 14:56:00 +0100109 @UnsupportedAppUsage
John Reck918988c2014-05-19 10:28:35 -0700110 public static int mapViewPropertyToRenderProperty(int viewProperty) {
John Recke45b1fd2014-04-15 09:50:16 -0700111 return sViewPropertyAnimatorMap.get(viewProperty);
112 }
113
Mathew Inwooda570dee2018-08-17 14:56:00 +0100114 @UnsupportedAppUsage
John Reckff941dc2014-05-14 16:34:14 -0700115 public RenderNodeAnimator(int property, float finalValue) {
John Reck8d8af3c2014-07-01 15:23:45 -0700116 mRenderProperty = property;
117 mFinalValue = finalValue;
John Reck291161a2014-07-22 07:31:09 -0700118 mUiThreadHandlesDelay = true;
John Reck119907c2014-08-14 09:02:01 -0700119 init(nCreateAnimator(property, finalValue));
John Recke45b1fd2014-04-15 09:50:16 -0700120 }
121
Mathew Inwooda570dee2018-08-17 14:56:00 +0100122 @UnsupportedAppUsage
John Reckff941dc2014-05-14 16:34:14 -0700123 public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
John Reck9fa40712014-05-09 15:26:59 -0700124 init(nCreateCanvasPropertyFloatAnimator(
John Reckff941dc2014-05-14 16:34:14 -0700125 property.getNativeContainer(), finalValue));
John Reck291161a2014-07-22 07:31:09 -0700126 mUiThreadHandlesDelay = false;
John Reck52244ff2014-05-01 21:27:37 -0700127 }
128
Alan Viverettead2f8e32014-05-16 13:28:33 -0700129 /**
130 * Creates a new render node animator for a field on a Paint property.
131 *
132 * @param property The paint property to target
133 * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
134 * {@link #PAINT_STROKE_WIDTH}
135 * @param finalValue The target value for the property
136 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100137 @UnsupportedAppUsage
John Reckff941dc2014-05-14 16:34:14 -0700138 public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
John Reck9fa40712014-05-09 15:26:59 -0700139 init(nCreateCanvasPropertyPaintAnimator(
John Reckff941dc2014-05-14 16:34:14 -0700140 property.getNativeContainer(), paintField, finalValue));
John Reck291161a2014-07-22 07:31:09 -0700141 mUiThreadHandlesDelay = false;
John Reck9fa40712014-05-09 15:26:59 -0700142 }
143
Chris Craikaf4d04c2014-07-29 12:50:14 -0700144 public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
John Reck119907c2014-08-14 09:02:01 -0700145 init(nCreateRevealAnimator(x, y, startRadius, endRadius));
John Reck291161a2014-07-22 07:31:09 -0700146 mUiThreadHandlesDelay = true;
John Reckd3de42c2014-07-15 14:29:33 -0700147 }
148
John Reck9fa40712014-05-09 15:26:59 -0700149 private void init(long ptr) {
150 mNativePtr = new VirtualRefBasePtr(ptr);
John Reck52244ff2014-05-01 21:27:37 -0700151 }
152
John Reck315c3292014-05-09 19:21:04 -0700153 private void checkMutable() {
John Reck4d2c4722014-08-29 10:40:56 -0700154 if (mState != STATE_PREPARE) {
John Reck315c3292014-05-09 19:21:04 -0700155 throw new IllegalStateException("Animator has already started, cannot change it now!");
156 }
John Reckc47c98b2014-12-09 09:07:35 -0800157 if (mNativePtr == null) {
158 throw new IllegalStateException("Animator's target has been destroyed "
159 + "(trying to modify an animation after activity destroy?)");
160 }
John Reck315c3292014-05-09 19:21:04 -0700161 }
162
John Reck918988c2014-05-19 10:28:35 -0700163 static boolean isNativeInterpolator(TimeInterpolator interpolator) {
164 return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class);
165 }
166
John Reck315c3292014-05-09 19:21:04 -0700167 private void applyInterpolator() {
John Reck545a3472018-02-14 16:36:16 -0800168 if (mInterpolator == null || mNativePtr == null) return;
John Reck315c3292014-05-09 19:21:04 -0700169
170 long ni;
John Reck918988c2014-05-19 10:28:35 -0700171 if (isNativeInterpolator(mInterpolator)) {
John Reck315c3292014-05-09 19:21:04 -0700172 ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
173 } else {
Alan Viverettead2f8e32014-05-16 13:28:33 -0700174 long duration = nGetDuration(mNativePtr.get());
John Reck315c3292014-05-09 19:21:04 -0700175 ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
176 }
177 nSetInterpolator(mNativePtr.get(), ni);
178 }
179
Alan Viverettead2f8e32014-05-16 13:28:33 -0700180 @Override
181 public void start() {
182 if (mTarget == null) {
183 throw new IllegalStateException("Missing target!");
184 }
185
John Reck4d2c4722014-08-29 10:40:56 -0700186 if (mState != STATE_PREPARE) {
John Reck315c3292014-05-09 19:21:04 -0700187 throw new IllegalStateException("Already started!");
188 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700189
John Reck4d2c4722014-08-29 10:40:56 -0700190 mState = STATE_DELAYED;
John Reck315c3292014-05-09 19:21:04 -0700191 applyInterpolator();
John Reck291161a2014-07-22 07:31:09 -0700192
John Reckc47c98b2014-12-09 09:07:35 -0800193 if (mNativePtr == null) {
194 // It's dead, immediately cancel
195 cancel();
196 } else if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
John Reck291161a2014-07-22 07:31:09 -0700197 nSetStartDelay(mNativePtr.get(), mStartDelay);
198 doStart();
199 } else {
200 getHelper().addDelayedAnimation(this);
201 }
202 }
203
204 private void doStart() {
John Reck8d8af3c2014-07-01 15:23:45 -0700205 // Alpha is a special snowflake that has the canonical value stored
206 // in mTransformationInfo instead of in RenderNode, so we need to update
207 // it with the final value here.
208 if (mRenderProperty == RenderNodeAnimator.ALPHA) {
Chris Craik686d9722017-01-06 16:11:45 -0800209 mViewTarget.ensureTransformationInfo();
John Reck8d8af3c2014-07-01 15:23:45 -0700210 mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
211 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700212
John Reck72d6e4f2014-11-21 14:10:10 -0800213 moveToRunningState();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700214
215 if (mViewTarget != null) {
216 // Kick off a frame to start the process
217 mViewTarget.invalidateViewProperty(true, false);
218 }
John Reck315c3292014-05-09 19:21:04 -0700219 }
220
John Reck72d6e4f2014-11-21 14:10:10 -0800221 private void moveToRunningState() {
222 mState = STATE_RUNNING;
John Reckc47c98b2014-12-09 09:07:35 -0800223 if (mNativePtr != null) {
224 nStart(mNativePtr.get());
225 }
John Reck72d6e4f2014-11-21 14:10:10 -0800226 notifyStartListeners();
227 }
228
John Reck4d2c4722014-08-29 10:40:56 -0700229 private void notifyStartListeners() {
230 final ArrayList<AnimatorListener> listeners = cloneListeners();
231 final int numListeners = listeners == null ? 0 : listeners.size();
232 for (int i = 0; i < numListeners; i++) {
233 listeners.get(i).onAnimationStart(this);
234 }
235 }
236
Alan Viverettead2f8e32014-05-16 13:28:33 -0700237 @Override
238 public void cancel() {
John Reck55b46ef2014-11-03 10:00:33 -0800239 if (mState != STATE_PREPARE && mState != STATE_FINISHED) {
John Reck4d2c4722014-08-29 10:40:56 -0700240 if (mState == STATE_DELAYED) {
241 getHelper().removeDelayedAnimation(this);
John Reck72d6e4f2014-11-21 14:10:10 -0800242 moveToRunningState();
John Reck4d2c4722014-08-29 10:40:56 -0700243 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700244
John Reck3b27e592014-08-21 12:37:48 -0700245 final ArrayList<AnimatorListener> listeners = cloneListeners();
John Reck68bfe0a2014-06-24 15:34:58 -0700246 final int numListeners = listeners == null ? 0 : listeners.size();
247 for (int i = 0; i < numListeners; i++) {
248 listeners.get(i).onAnimationCancel(this);
249 }
John Reck4d2c4722014-08-29 10:40:56 -0700250
John Reckc47c98b2014-12-09 09:07:35 -0800251 end();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700252 }
John Recke45b1fd2014-04-15 09:50:16 -0700253 }
254
Alan Viverettead2f8e32014-05-16 13:28:33 -0700255 @Override
256 public void end() {
John Reck4d2c4722014-08-29 10:40:56 -0700257 if (mState != STATE_FINISHED) {
John Reck72d6e4f2014-11-21 14:10:10 -0800258 if (mState < STATE_RUNNING) {
259 getHelper().removeDelayedAnimation(this);
260 doStart();
261 }
John Reckc47c98b2014-12-09 09:07:35 -0800262 if (mNativePtr != null) {
263 nEnd(mNativePtr.get());
264 if (mViewTarget != null) {
265 // Kick off a frame to flush the state change
266 mViewTarget.invalidateViewProperty(true, false);
267 }
268 } else {
269 // It's already dead, jump to onFinish
270 onFinished();
John Reck72d6e4f2014-11-21 14:10:10 -0800271 }
John Reckd3de42c2014-07-15 14:29:33 -0700272 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700273 }
274
275 @Override
276 public void pause() {
277 throw new UnsupportedOperationException();
278 }
279
280 @Override
281 public void resume() {
282 throw new UnsupportedOperationException();
283 }
284
Mathew Inwooda570dee2018-08-17 14:56:00 +0100285 @UnsupportedAppUsage
Alan Viverettead2f8e32014-05-16 13:28:33 -0700286 public void setTarget(View view) {
287 mViewTarget = view;
John Reck119907c2014-08-14 09:02:01 -0700288 setTarget(mViewTarget.mRenderNode);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700289 }
290
John Reck32f140aa62018-10-04 15:08:24 -0700291 /** Sets the animation target to the owning view of the RecordingCanvas */
292 public void setTarget(RecordingCanvas canvas) {
John Reck0c453cc2017-11-16 13:44:35 -0800293 setTarget(canvas.mNode);
John Reck1c058e92014-05-02 14:20:53 -0700294 }
295
John Reck5c6397e2018-11-14 15:14:44 -0800296 /** @hide */
297 @UnsupportedAppUsage
298 public void setTarget(DisplayListCanvas canvas) {
299 setTarget((RecordingCanvas) canvas);
300 }
301
John Reck119907c2014-08-14 09:02:01 -0700302 private void setTarget(RenderNode node) {
John Reckc47c98b2014-12-09 09:07:35 -0800303 checkMutable();
John Reck8d8af3c2014-07-01 15:23:45 -0700304 if (mTarget != null) {
305 throw new IllegalStateException("Target already set!");
306 }
John Reckc47c98b2014-12-09 09:07:35 -0800307 nSetListener(mNativePtr.get(), this);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700308 mTarget = node;
John Reck8d8af3c2014-07-01 15:23:45 -0700309 mTarget.addAnimator(this);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700310 }
311
Mathew Inwooda570dee2018-08-17 14:56:00 +0100312 @UnsupportedAppUsage
John Reckc6b32642014-06-02 11:00:09 -0700313 public void setStartValue(float startValue) {
314 checkMutable();
315 nSetStartValue(mNativePtr.get(), startValue);
316 }
317
Alan Viverettead2f8e32014-05-16 13:28:33 -0700318 @Override
319 public void setStartDelay(long startDelay) {
320 checkMutable();
John Reck68bfe0a2014-06-24 15:34:58 -0700321 if (startDelay < 0) {
322 throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
323 }
John Reck8d8af3c2014-07-01 15:23:45 -0700324 mUnscaledStartDelay = startDelay;
John Reck291161a2014-07-22 07:31:09 -0700325 mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700326 }
327
328 @Override
329 public long getStartDelay() {
John Reck8d8af3c2014-07-01 15:23:45 -0700330 return mUnscaledStartDelay;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700331 }
332
333 @Override
334 public RenderNodeAnimator setDuration(long duration) {
John Reck315c3292014-05-09 19:21:04 -0700335 checkMutable();
John Reck68bfe0a2014-06-24 15:34:58 -0700336 if (duration < 0) {
337 throw new IllegalArgumentException("duration must be positive; " + duration);
338 }
John Reck8d8af3c2014-07-01 15:23:45 -0700339 mUnscaledDuration = duration;
340 nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
Alan Viverettead2f8e32014-05-16 13:28:33 -0700341 return this;
John Recke45b1fd2014-04-15 09:50:16 -0700342 }
343
Alan Viverettead2f8e32014-05-16 13:28:33 -0700344 @Override
345 public long getDuration() {
John Reck8d8af3c2014-07-01 15:23:45 -0700346 return mUnscaledDuration;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700347 }
348
Doris Liu13099142015-07-10 17:32:41 -0700349 @Override
350 public long getTotalDuration() {
351 return mUnscaledDuration + mUnscaledStartDelay;
352 }
353
Alan Viverettead2f8e32014-05-16 13:28:33 -0700354 @Override
355 public boolean isRunning() {
John Reck4d2c4722014-08-29 10:40:56 -0700356 return mState == STATE_DELAYED || mState == STATE_RUNNING;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700357 }
358
359 @Override
John Reckd3de42c2014-07-15 14:29:33 -0700360 public boolean isStarted() {
John Reck4d2c4722014-08-29 10:40:56 -0700361 return mState != STATE_PREPARE;
John Reckd3de42c2014-07-15 14:29:33 -0700362 }
363
364 @Override
John Reck315c3292014-05-09 19:21:04 -0700365 public void setInterpolator(TimeInterpolator interpolator) {
366 checkMutable();
367 mInterpolator = interpolator;
368 }
369
Alan Viverettead2f8e32014-05-16 13:28:33 -0700370 @Override
371 public TimeInterpolator getInterpolator() {
372 return mInterpolator;
John Recke45b1fd2014-04-15 09:50:16 -0700373 }
374
John Reck291161a2014-07-22 07:31:09 -0700375 protected void onFinished() {
John Reckc47c98b2014-12-09 09:07:35 -0800376 if (mState == STATE_PREPARE) {
377 // Unlikely but possible, the native side has been destroyed
378 // before we have started.
379 releaseNativePtr();
380 return;
381 }
John Reck4d2c4722014-08-29 10:40:56 -0700382 if (mState == STATE_DELAYED) {
383 getHelper().removeDelayedAnimation(this);
384 notifyStartListeners();
385 }
386 mState = STATE_FINISHED;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700387
John Reck3b27e592014-08-21 12:37:48 -0700388 final ArrayList<AnimatorListener> listeners = cloneListeners();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700389 final int numListeners = listeners == null ? 0 : listeners.size();
390 for (int i = 0; i < numListeners; i++) {
391 listeners.get(i).onAnimationEnd(this);
392 }
John Reck119907c2014-08-14 09:02:01 -0700393
394 // Release the native object, as it has a global reference to us. This
395 // breaks the cyclic reference chain, and allows this object to be
396 // GC'd
John Reckc47c98b2014-12-09 09:07:35 -0800397 releaseNativePtr();
398 }
399
400 private void releaseNativePtr() {
401 if (mNativePtr != null) {
402 mNativePtr.release();
403 mNativePtr = null;
404 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700405 }
406
John Reck3b27e592014-08-21 12:37:48 -0700407 @SuppressWarnings("unchecked")
408 private ArrayList<AnimatorListener> cloneListeners() {
409 ArrayList<AnimatorListener> listeners = getListeners();
410 if (listeners != null) {
411 listeners = (ArrayList<AnimatorListener>) listeners.clone();
412 }
413 return listeners;
414 }
415
John Reck32f140aa62018-10-04 15:08:24 -0700416 public long getNativeAnimator() {
Alan Viverettead2f8e32014-05-16 13:28:33 -0700417 return mNativePtr.get();
John Recke45b1fd2014-04-15 09:50:16 -0700418 }
419
John Reck291161a2014-07-22 07:31:09 -0700420 /**
421 * @return true if the animator was started, false if still delayed
422 */
423 private boolean processDelayed(long frameTimeMs) {
424 if (mStartTime == 0) {
425 mStartTime = frameTimeMs;
426 } else if ((frameTimeMs - mStartTime) >= mStartDelay) {
427 doStart();
428 return true;
429 }
430 return false;
431 }
432
433 private static DelayedAnimationHelper getHelper() {
434 DelayedAnimationHelper helper = sAnimationHelper.get();
435 if (helper == null) {
436 helper = new DelayedAnimationHelper();
437 sAnimationHelper.set(helper);
438 }
439 return helper;
440 }
441
442 private static ThreadLocal<DelayedAnimationHelper> sAnimationHelper =
443 new ThreadLocal<DelayedAnimationHelper>();
444
445 private static class DelayedAnimationHelper implements Runnable {
446
447 private ArrayList<RenderNodeAnimator> mDelayedAnims = new ArrayList<RenderNodeAnimator>();
448 private final Choreographer mChoreographer;
449 private boolean mCallbackScheduled;
450
451 public DelayedAnimationHelper() {
452 mChoreographer = Choreographer.getInstance();
453 }
454
455 public void addDelayedAnimation(RenderNodeAnimator animator) {
456 mDelayedAnims.add(animator);
457 scheduleCallback();
458 }
459
460 public void removeDelayedAnimation(RenderNodeAnimator animator) {
461 mDelayedAnims.remove(animator);
462 }
463
464 private void scheduleCallback() {
465 if (!mCallbackScheduled) {
466 mCallbackScheduled = true;
467 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
468 }
469 }
470
471 @Override
472 public void run() {
473 long frameTimeMs = mChoreographer.getFrameTime();
474 mCallbackScheduled = false;
475
476 int end = 0;
477 for (int i = 0; i < mDelayedAnims.size(); i++) {
478 RenderNodeAnimator animator = mDelayedAnims.get(i);
479 if (!animator.processDelayed(frameTimeMs)) {
480 if (end != i) {
481 mDelayedAnims.set(end, animator);
482 }
483 end++;
484 }
485 }
486 while (mDelayedAnims.size() > end) {
487 mDelayedAnims.remove(mDelayedAnims.size() - 1);
488 }
489
490 if (mDelayedAnims.size() > 0) {
491 scheduleCallback();
492 }
493 }
494 }
495
John Recke45b1fd2014-04-15 09:50:16 -0700496 // Called by native
Mathew Inwooda570dee2018-08-17 14:56:00 +0100497 @UnsupportedAppUsage
John Reck119907c2014-08-14 09:02:01 -0700498 private static void callOnFinished(RenderNodeAnimator animator) {
499 animator.onFinished();
John Recke45b1fd2014-04-15 09:50:16 -0700500 }
501
John Reck291161a2014-07-22 07:31:09 -0700502 @Override
503 public Animator clone() {
504 throw new IllegalStateException("Cannot clone this animator");
505 }
506
John Reckf5945a02014-09-05 15:57:47 -0700507 @Override
508 public void setAllowRunningAsynchronously(boolean mayRunAsync) {
509 checkMutable();
510 nSetAllowRunningAsync(mNativePtr.get(), mayRunAsync);
511 }
512
John Reck119907c2014-08-14 09:02:01 -0700513 private static native long nCreateAnimator(int property, float finalValue);
514 private static native long nCreateCanvasPropertyFloatAnimator(
John Reckc6b32642014-06-02 11:00:09 -0700515 long canvasProperty, float finalValue);
John Reck119907c2014-08-14 09:02:01 -0700516 private static native long nCreateCanvasPropertyPaintAnimator(
John Reckc6b32642014-06-02 11:00:09 -0700517 long canvasProperty, int paintField, float finalValue);
John Reck119907c2014-08-14 09:02:01 -0700518 private static native long nCreateRevealAnimator(
Chris Craikaf4d04c2014-07-29 12:50:14 -0700519 int x, int y, float startRadius, float endRadius);
John Reck68bfe0a2014-06-24 15:34:58 -0700520
John Reckc6b32642014-06-02 11:00:09 -0700521 private static native void nSetStartValue(long nativePtr, float startValue);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700522 private static native void nSetDuration(long nativePtr, long duration);
523 private static native long nGetDuration(long nativePtr);
524 private static native void nSetStartDelay(long nativePtr, long startDelay);
John Reck315c3292014-05-09 19:21:04 -0700525 private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
John Reckf5945a02014-09-05 15:57:47 -0700526 private static native void nSetAllowRunningAsync(long animPtr, boolean mayRunAsync);
John Reckc47c98b2014-12-09 09:07:35 -0800527 private static native void nSetListener(long animPtr, RenderNodeAnimator listener);
John Reck68bfe0a2014-06-24 15:34:58 -0700528
John Reckc47c98b2014-12-09 09:07:35 -0800529 private static native void nStart(long animPtr);
John Reckd3de42c2014-07-15 14:29:33 -0700530 private static native void nEnd(long animPtr);
John Recke45b1fd2014-04-15 09:50:16 -0700531}