blob: e48bcfdb7203156568cab685e9bf3c375abbc3d7 [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 Inwoode5ad5982018-08-17 15:07:52 +010022import android.annotation.UnsupportedAppUsage;
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
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100107 @UnsupportedAppUsage
John Reck918988c2014-05-19 10:28:35 -0700108 public static int mapViewPropertyToRenderProperty(int viewProperty) {
John Recke45b1fd2014-04-15 09:50:16 -0700109 return sViewPropertyAnimatorMap.get(viewProperty);
110 }
111
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100112 @UnsupportedAppUsage
John Reckff941dc2014-05-14 16:34:14 -0700113 public RenderNodeAnimator(int property, float finalValue) {
John Reck8d8af3c2014-07-01 15:23:45 -0700114 mRenderProperty = property;
115 mFinalValue = finalValue;
John Reck291161a2014-07-22 07:31:09 -0700116 mUiThreadHandlesDelay = true;
John Reck119907c2014-08-14 09:02:01 -0700117 init(nCreateAnimator(property, finalValue));
John Recke45b1fd2014-04-15 09:50:16 -0700118 }
119
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100120 @UnsupportedAppUsage
John Reckff941dc2014-05-14 16:34:14 -0700121 public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
John Reck9fa40712014-05-09 15:26:59 -0700122 init(nCreateCanvasPropertyFloatAnimator(
John Reckff941dc2014-05-14 16:34:14 -0700123 property.getNativeContainer(), finalValue));
John Reck291161a2014-07-22 07:31:09 -0700124 mUiThreadHandlesDelay = false;
John Reck52244ff2014-05-01 21:27:37 -0700125 }
126
Alan Viverettead2f8e32014-05-16 13:28:33 -0700127 /**
128 * Creates a new render node animator for a field on a Paint property.
129 *
130 * @param property The paint property to target
131 * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
132 * {@link #PAINT_STROKE_WIDTH}
133 * @param finalValue The target value for the property
134 */
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100135 @UnsupportedAppUsage
John Reckff941dc2014-05-14 16:34:14 -0700136 public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
John Reck9fa40712014-05-09 15:26:59 -0700137 init(nCreateCanvasPropertyPaintAnimator(
John Reckff941dc2014-05-14 16:34:14 -0700138 property.getNativeContainer(), paintField, finalValue));
John Reck291161a2014-07-22 07:31:09 -0700139 mUiThreadHandlesDelay = false;
John Reck9fa40712014-05-09 15:26:59 -0700140 }
141
Chris Craikaf4d04c2014-07-29 12:50:14 -0700142 public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
John Reck119907c2014-08-14 09:02:01 -0700143 init(nCreateRevealAnimator(x, y, startRadius, endRadius));
John Reck291161a2014-07-22 07:31:09 -0700144 mUiThreadHandlesDelay = true;
John Reckd3de42c2014-07-15 14:29:33 -0700145 }
146
John Reck9fa40712014-05-09 15:26:59 -0700147 private void init(long ptr) {
148 mNativePtr = new VirtualRefBasePtr(ptr);
John Reck52244ff2014-05-01 21:27:37 -0700149 }
150
John Reck315c3292014-05-09 19:21:04 -0700151 private void checkMutable() {
John Reck4d2c4722014-08-29 10:40:56 -0700152 if (mState != STATE_PREPARE) {
John Reck315c3292014-05-09 19:21:04 -0700153 throw new IllegalStateException("Animator has already started, cannot change it now!");
154 }
John Reckc47c98b2014-12-09 09:07:35 -0800155 if (mNativePtr == null) {
156 throw new IllegalStateException("Animator's target has been destroyed "
157 + "(trying to modify an animation after activity destroy?)");
158 }
John Reck315c3292014-05-09 19:21:04 -0700159 }
160
John Reck918988c2014-05-19 10:28:35 -0700161 static boolean isNativeInterpolator(TimeInterpolator interpolator) {
162 return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class);
163 }
164
John Reck315c3292014-05-09 19:21:04 -0700165 private void applyInterpolator() {
John Reck545a3472018-02-14 16:36:16 -0800166 if (mInterpolator == null || mNativePtr == null) return;
John Reck315c3292014-05-09 19:21:04 -0700167
168 long ni;
John Reck918988c2014-05-19 10:28:35 -0700169 if (isNativeInterpolator(mInterpolator)) {
John Reck315c3292014-05-09 19:21:04 -0700170 ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
171 } else {
Alan Viverettead2f8e32014-05-16 13:28:33 -0700172 long duration = nGetDuration(mNativePtr.get());
John Reck315c3292014-05-09 19:21:04 -0700173 ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
174 }
175 nSetInterpolator(mNativePtr.get(), ni);
176 }
177
Alan Viverettead2f8e32014-05-16 13:28:33 -0700178 @Override
179 public void start() {
180 if (mTarget == null) {
181 throw new IllegalStateException("Missing target!");
182 }
183
John Reck4d2c4722014-08-29 10:40:56 -0700184 if (mState != STATE_PREPARE) {
John Reck315c3292014-05-09 19:21:04 -0700185 throw new IllegalStateException("Already started!");
186 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700187
John Reck4d2c4722014-08-29 10:40:56 -0700188 mState = STATE_DELAYED;
John Reck315c3292014-05-09 19:21:04 -0700189 applyInterpolator();
John Reck291161a2014-07-22 07:31:09 -0700190
John Reckc47c98b2014-12-09 09:07:35 -0800191 if (mNativePtr == null) {
192 // It's dead, immediately cancel
193 cancel();
194 } else if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
John Reck291161a2014-07-22 07:31:09 -0700195 nSetStartDelay(mNativePtr.get(), mStartDelay);
196 doStart();
197 } else {
198 getHelper().addDelayedAnimation(this);
199 }
200 }
201
202 private void doStart() {
John Reck8d8af3c2014-07-01 15:23:45 -0700203 // Alpha is a special snowflake that has the canonical value stored
204 // in mTransformationInfo instead of in RenderNode, so we need to update
205 // it with the final value here.
206 if (mRenderProperty == RenderNodeAnimator.ALPHA) {
Chris Craik686d9722017-01-06 16:11:45 -0800207 mViewTarget.ensureTransformationInfo();
John Reck8d8af3c2014-07-01 15:23:45 -0700208 mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
209 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700210
John Reck72d6e4f2014-11-21 14:10:10 -0800211 moveToRunningState();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700212
213 if (mViewTarget != null) {
214 // Kick off a frame to start the process
215 mViewTarget.invalidateViewProperty(true, false);
216 }
John Reck315c3292014-05-09 19:21:04 -0700217 }
218
John Reck72d6e4f2014-11-21 14:10:10 -0800219 private void moveToRunningState() {
220 mState = STATE_RUNNING;
John Reckc47c98b2014-12-09 09:07:35 -0800221 if (mNativePtr != null) {
222 nStart(mNativePtr.get());
223 }
John Reck72d6e4f2014-11-21 14:10:10 -0800224 notifyStartListeners();
225 }
226
John Reck4d2c4722014-08-29 10:40:56 -0700227 private void notifyStartListeners() {
228 final ArrayList<AnimatorListener> listeners = cloneListeners();
229 final int numListeners = listeners == null ? 0 : listeners.size();
230 for (int i = 0; i < numListeners; i++) {
231 listeners.get(i).onAnimationStart(this);
232 }
233 }
234
Alan Viverettead2f8e32014-05-16 13:28:33 -0700235 @Override
236 public void cancel() {
John Reck55b46ef2014-11-03 10:00:33 -0800237 if (mState != STATE_PREPARE && mState != STATE_FINISHED) {
John Reck4d2c4722014-08-29 10:40:56 -0700238 if (mState == STATE_DELAYED) {
239 getHelper().removeDelayedAnimation(this);
John Reck72d6e4f2014-11-21 14:10:10 -0800240 moveToRunningState();
John Reck4d2c4722014-08-29 10:40:56 -0700241 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700242
John Reck3b27e592014-08-21 12:37:48 -0700243 final ArrayList<AnimatorListener> listeners = cloneListeners();
John Reck68bfe0a2014-06-24 15:34:58 -0700244 final int numListeners = listeners == null ? 0 : listeners.size();
245 for (int i = 0; i < numListeners; i++) {
246 listeners.get(i).onAnimationCancel(this);
247 }
John Reck4d2c4722014-08-29 10:40:56 -0700248
John Reckc47c98b2014-12-09 09:07:35 -0800249 end();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700250 }
John Recke45b1fd2014-04-15 09:50:16 -0700251 }
252
Alan Viverettead2f8e32014-05-16 13:28:33 -0700253 @Override
254 public void end() {
John Reck4d2c4722014-08-29 10:40:56 -0700255 if (mState != STATE_FINISHED) {
John Reck72d6e4f2014-11-21 14:10:10 -0800256 if (mState < STATE_RUNNING) {
257 getHelper().removeDelayedAnimation(this);
258 doStart();
259 }
John Reckc47c98b2014-12-09 09:07:35 -0800260 if (mNativePtr != null) {
261 nEnd(mNativePtr.get());
262 if (mViewTarget != null) {
263 // Kick off a frame to flush the state change
264 mViewTarget.invalidateViewProperty(true, false);
265 }
266 } else {
267 // It's already dead, jump to onFinish
268 onFinished();
John Reck72d6e4f2014-11-21 14:10:10 -0800269 }
John Reckd3de42c2014-07-15 14:29:33 -0700270 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700271 }
272
273 @Override
274 public void pause() {
275 throw new UnsupportedOperationException();
276 }
277
278 @Override
279 public void resume() {
280 throw new UnsupportedOperationException();
281 }
282
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100283 @UnsupportedAppUsage
Alan Viverettead2f8e32014-05-16 13:28:33 -0700284 public void setTarget(View view) {
285 mViewTarget = view;
John Reck119907c2014-08-14 09:02:01 -0700286 setTarget(mViewTarget.mRenderNode);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700287 }
288
John Reck0c453cc2017-11-16 13:44:35 -0800289 /** Sets the animation target to the owning view of the DisplayListCanvas */
290 public void setTarget(DisplayListCanvas canvas) {
291 setTarget(canvas.mNode);
John Reck1c058e92014-05-02 14:20:53 -0700292 }
293
John Reck119907c2014-08-14 09:02:01 -0700294 private void setTarget(RenderNode node) {
John Reckc47c98b2014-12-09 09:07:35 -0800295 checkMutable();
John Reck8d8af3c2014-07-01 15:23:45 -0700296 if (mTarget != null) {
297 throw new IllegalStateException("Target already set!");
298 }
John Reckc47c98b2014-12-09 09:07:35 -0800299 nSetListener(mNativePtr.get(), this);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700300 mTarget = node;
John Reck8d8af3c2014-07-01 15:23:45 -0700301 mTarget.addAnimator(this);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700302 }
303
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100304 @UnsupportedAppUsage
John Reckc6b32642014-06-02 11:00:09 -0700305 public void setStartValue(float startValue) {
306 checkMutable();
307 nSetStartValue(mNativePtr.get(), startValue);
308 }
309
Alan Viverettead2f8e32014-05-16 13:28:33 -0700310 @Override
311 public void setStartDelay(long startDelay) {
312 checkMutable();
John Reck68bfe0a2014-06-24 15:34:58 -0700313 if (startDelay < 0) {
314 throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
315 }
John Reck8d8af3c2014-07-01 15:23:45 -0700316 mUnscaledStartDelay = startDelay;
John Reck291161a2014-07-22 07:31:09 -0700317 mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700318 }
319
320 @Override
321 public long getStartDelay() {
John Reck8d8af3c2014-07-01 15:23:45 -0700322 return mUnscaledStartDelay;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700323 }
324
325 @Override
326 public RenderNodeAnimator setDuration(long duration) {
John Reck315c3292014-05-09 19:21:04 -0700327 checkMutable();
John Reck68bfe0a2014-06-24 15:34:58 -0700328 if (duration < 0) {
329 throw new IllegalArgumentException("duration must be positive; " + duration);
330 }
John Reck8d8af3c2014-07-01 15:23:45 -0700331 mUnscaledDuration = duration;
332 nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
Alan Viverettead2f8e32014-05-16 13:28:33 -0700333 return this;
John Recke45b1fd2014-04-15 09:50:16 -0700334 }
335
Alan Viverettead2f8e32014-05-16 13:28:33 -0700336 @Override
337 public long getDuration() {
John Reck8d8af3c2014-07-01 15:23:45 -0700338 return mUnscaledDuration;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700339 }
340
Doris Liu13099142015-07-10 17:32:41 -0700341 @Override
342 public long getTotalDuration() {
343 return mUnscaledDuration + mUnscaledStartDelay;
344 }
345
Alan Viverettead2f8e32014-05-16 13:28:33 -0700346 @Override
347 public boolean isRunning() {
John Reck4d2c4722014-08-29 10:40:56 -0700348 return mState == STATE_DELAYED || mState == STATE_RUNNING;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700349 }
350
351 @Override
John Reckd3de42c2014-07-15 14:29:33 -0700352 public boolean isStarted() {
John Reck4d2c4722014-08-29 10:40:56 -0700353 return mState != STATE_PREPARE;
John Reckd3de42c2014-07-15 14:29:33 -0700354 }
355
356 @Override
John Reck315c3292014-05-09 19:21:04 -0700357 public void setInterpolator(TimeInterpolator interpolator) {
358 checkMutable();
359 mInterpolator = interpolator;
360 }
361
Alan Viverettead2f8e32014-05-16 13:28:33 -0700362 @Override
363 public TimeInterpolator getInterpolator() {
364 return mInterpolator;
John Recke45b1fd2014-04-15 09:50:16 -0700365 }
366
John Reck291161a2014-07-22 07:31:09 -0700367 protected void onFinished() {
John Reckc47c98b2014-12-09 09:07:35 -0800368 if (mState == STATE_PREPARE) {
369 // Unlikely but possible, the native side has been destroyed
370 // before we have started.
371 releaseNativePtr();
372 return;
373 }
John Reck4d2c4722014-08-29 10:40:56 -0700374 if (mState == STATE_DELAYED) {
375 getHelper().removeDelayedAnimation(this);
376 notifyStartListeners();
377 }
378 mState = STATE_FINISHED;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700379
John Reck3b27e592014-08-21 12:37:48 -0700380 final ArrayList<AnimatorListener> listeners = cloneListeners();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700381 final int numListeners = listeners == null ? 0 : listeners.size();
382 for (int i = 0; i < numListeners; i++) {
383 listeners.get(i).onAnimationEnd(this);
384 }
John Reck119907c2014-08-14 09:02:01 -0700385
386 // Release the native object, as it has a global reference to us. This
387 // breaks the cyclic reference chain, and allows this object to be
388 // GC'd
John Reckc47c98b2014-12-09 09:07:35 -0800389 releaseNativePtr();
390 }
391
392 private void releaseNativePtr() {
393 if (mNativePtr != null) {
394 mNativePtr.release();
395 mNativePtr = null;
396 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700397 }
398
John Reck3b27e592014-08-21 12:37:48 -0700399 @SuppressWarnings("unchecked")
400 private ArrayList<AnimatorListener> cloneListeners() {
401 ArrayList<AnimatorListener> listeners = getListeners();
402 if (listeners != null) {
403 listeners = (ArrayList<AnimatorListener>) listeners.clone();
404 }
405 return listeners;
406 }
407
Alan Viverettead2f8e32014-05-16 13:28:33 -0700408 long getNativeAnimator() {
409 return mNativePtr.get();
John Recke45b1fd2014-04-15 09:50:16 -0700410 }
411
John Reck291161a2014-07-22 07:31:09 -0700412 /**
413 * @return true if the animator was started, false if still delayed
414 */
415 private boolean processDelayed(long frameTimeMs) {
416 if (mStartTime == 0) {
417 mStartTime = frameTimeMs;
418 } else if ((frameTimeMs - mStartTime) >= mStartDelay) {
419 doStart();
420 return true;
421 }
422 return false;
423 }
424
425 private static DelayedAnimationHelper getHelper() {
426 DelayedAnimationHelper helper = sAnimationHelper.get();
427 if (helper == null) {
428 helper = new DelayedAnimationHelper();
429 sAnimationHelper.set(helper);
430 }
431 return helper;
432 }
433
434 private static ThreadLocal<DelayedAnimationHelper> sAnimationHelper =
435 new ThreadLocal<DelayedAnimationHelper>();
436
437 private static class DelayedAnimationHelper implements Runnable {
438
439 private ArrayList<RenderNodeAnimator> mDelayedAnims = new ArrayList<RenderNodeAnimator>();
440 private final Choreographer mChoreographer;
441 private boolean mCallbackScheduled;
442
443 public DelayedAnimationHelper() {
444 mChoreographer = Choreographer.getInstance();
445 }
446
447 public void addDelayedAnimation(RenderNodeAnimator animator) {
448 mDelayedAnims.add(animator);
449 scheduleCallback();
450 }
451
452 public void removeDelayedAnimation(RenderNodeAnimator animator) {
453 mDelayedAnims.remove(animator);
454 }
455
456 private void scheduleCallback() {
457 if (!mCallbackScheduled) {
458 mCallbackScheduled = true;
459 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
460 }
461 }
462
463 @Override
464 public void run() {
465 long frameTimeMs = mChoreographer.getFrameTime();
466 mCallbackScheduled = false;
467
468 int end = 0;
469 for (int i = 0; i < mDelayedAnims.size(); i++) {
470 RenderNodeAnimator animator = mDelayedAnims.get(i);
471 if (!animator.processDelayed(frameTimeMs)) {
472 if (end != i) {
473 mDelayedAnims.set(end, animator);
474 }
475 end++;
476 }
477 }
478 while (mDelayedAnims.size() > end) {
479 mDelayedAnims.remove(mDelayedAnims.size() - 1);
480 }
481
482 if (mDelayedAnims.size() > 0) {
483 scheduleCallback();
484 }
485 }
486 }
487
John Recke45b1fd2014-04-15 09:50:16 -0700488 // Called by native
Mathew Inwoode5ad5982018-08-17 15:07:52 +0100489 @UnsupportedAppUsage
John Reck119907c2014-08-14 09:02:01 -0700490 private static void callOnFinished(RenderNodeAnimator animator) {
491 animator.onFinished();
John Recke45b1fd2014-04-15 09:50:16 -0700492 }
493
John Reck291161a2014-07-22 07:31:09 -0700494 @Override
495 public Animator clone() {
496 throw new IllegalStateException("Cannot clone this animator");
497 }
498
John Reckf5945a02014-09-05 15:57:47 -0700499 @Override
500 public void setAllowRunningAsynchronously(boolean mayRunAsync) {
501 checkMutable();
502 nSetAllowRunningAsync(mNativePtr.get(), mayRunAsync);
503 }
504
John Reck119907c2014-08-14 09:02:01 -0700505 private static native long nCreateAnimator(int property, float finalValue);
506 private static native long nCreateCanvasPropertyFloatAnimator(
John Reckc6b32642014-06-02 11:00:09 -0700507 long canvasProperty, float finalValue);
John Reck119907c2014-08-14 09:02:01 -0700508 private static native long nCreateCanvasPropertyPaintAnimator(
John Reckc6b32642014-06-02 11:00:09 -0700509 long canvasProperty, int paintField, float finalValue);
John Reck119907c2014-08-14 09:02:01 -0700510 private static native long nCreateRevealAnimator(
Chris Craikaf4d04c2014-07-29 12:50:14 -0700511 int x, int y, float startRadius, float endRadius);
John Reck68bfe0a2014-06-24 15:34:58 -0700512
John Reckc6b32642014-06-02 11:00:09 -0700513 private static native void nSetStartValue(long nativePtr, float startValue);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700514 private static native void nSetDuration(long nativePtr, long duration);
515 private static native long nGetDuration(long nativePtr);
516 private static native void nSetStartDelay(long nativePtr, long startDelay);
John Reck315c3292014-05-09 19:21:04 -0700517 private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
John Reckf5945a02014-09-05 15:57:47 -0700518 private static native void nSetAllowRunningAsync(long animPtr, boolean mayRunAsync);
John Reckc47c98b2014-12-09 09:07:35 -0800519 private static native void nSetListener(long animPtr, RenderNodeAnimator listener);
John Reck68bfe0a2014-06-24 15:34:58 -0700520
John Reckc47c98b2014-12-09 09:07:35 -0800521 private static native void nStart(long animPtr);
John Reckd3de42c2014-07-15 14:29:33 -0700522 private static native void nEnd(long animPtr);
John Recke45b1fd2014-04-15 09:50:16 -0700523}