blob: 7ab9534941c7db3c1bff312dda6d871a26b9a2eb [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;
Mathew Inwood556d3a62019-02-06 15:12:50 +000027import android.os.Build;
John Reckfe5dfca2019-01-17 17:01:32 -080028import android.os.Handler;
John Recke45b1fd2014-04-15 09:50:16 -070029import android.util.SparseIntArray;
30
John Reck9fa40712014-05-09 15:26:59 -070031import com.android.internal.util.VirtualRefBasePtr;
John Reck315c3292014-05-09 19:21:04 -070032import com.android.internal.view.animation.FallbackLUTInterpolator;
33import com.android.internal.view.animation.HasNativeInterpolator;
34import com.android.internal.view.animation.NativeInterpolatorFactory;
John Reck9fa40712014-05-09 15:26:59 -070035
Alan Viverettead2f8e32014-05-16 13:28:33 -070036import java.util.ArrayList;
John Recke45b1fd2014-04-15 09:50:16 -070037
38/**
39 * @hide
40 */
John Reck8d8af3c2014-07-01 15:23:45 -070041public class RenderNodeAnimator extends Animator {
John Recke45b1fd2014-04-15 09:50:16 -070042 // Keep in sync with enum RenderProperty in Animator.h
John Reck52244ff2014-05-01 21:27:37 -070043 public static final int TRANSLATION_X = 0;
44 public static final int TRANSLATION_Y = 1;
45 public static final int TRANSLATION_Z = 2;
46 public static final int SCALE_X = 3;
47 public static final int SCALE_Y = 4;
48 public static final int ROTATION = 5;
49 public static final int ROTATION_X = 6;
50 public static final int ROTATION_Y = 7;
51 public static final int X = 8;
52 public static final int Y = 9;
53 public static final int Z = 10;
54 public static final int ALPHA = 11;
John Reck918988c2014-05-19 10:28:35 -070055 // The last value in the enum, used for array size initialization
56 public static final int LAST_VALUE = ALPHA;
John Reck52244ff2014-05-01 21:27:37 -070057
58 // Keep in sync with enum PaintFields in Animator.h
59 public static final int PAINT_STROKE_WIDTH = 0;
Alan Viverettead2f8e32014-05-16 13:28:33 -070060
61 /**
62 * Field for the Paint alpha channel, which should be specified as a value
63 * between 0 and 255.
64 */
John Reck52244ff2014-05-01 21:27:37 -070065 public static final int PAINT_ALPHA = 1;
John Recke45b1fd2014-04-15 09:50:16 -070066
67 // ViewPropertyAnimator uses a mask for its values, we need to remap them
68 // to the enum values here. RenderPropertyAnimator can't use the mask values
69 // directly as internally it uses a lookup table so it needs the values to
70 // be sequential starting from 0
71 private static final SparseIntArray sViewPropertyAnimatorMap = new SparseIntArray(15) {{
72 put(ViewPropertyAnimator.TRANSLATION_X, TRANSLATION_X);
73 put(ViewPropertyAnimator.TRANSLATION_Y, TRANSLATION_Y);
74 put(ViewPropertyAnimator.TRANSLATION_Z, TRANSLATION_Z);
75 put(ViewPropertyAnimator.SCALE_X, SCALE_X);
76 put(ViewPropertyAnimator.SCALE_Y, SCALE_Y);
77 put(ViewPropertyAnimator.ROTATION, ROTATION);
78 put(ViewPropertyAnimator.ROTATION_X, ROTATION_X);
79 put(ViewPropertyAnimator.ROTATION_Y, ROTATION_Y);
80 put(ViewPropertyAnimator.X, X);
81 put(ViewPropertyAnimator.Y, Y);
82 put(ViewPropertyAnimator.Z, Z);
83 put(ViewPropertyAnimator.ALPHA, ALPHA);
84 }};
85
John Reck9fa40712014-05-09 15:26:59 -070086 private VirtualRefBasePtr mNativePtr;
John Recke45b1fd2014-04-15 09:50:16 -070087
John Reckfe5dfca2019-01-17 17:01:32 -080088 private Handler mHandler;
John Reck315c3292014-05-09 19:21:04 -070089 private RenderNode mTarget;
Alan Viverettead2f8e32014-05-16 13:28:33 -070090 private View mViewTarget;
John Reck8d8af3c2014-07-01 15:23:45 -070091 private int mRenderProperty = -1;
92 private float mFinalValue;
John Reck315c3292014-05-09 19:21:04 -070093 private TimeInterpolator mInterpolator;
Alan Viverettead2f8e32014-05-16 13:28:33 -070094
John Reck4d2c4722014-08-29 10:40:56 -070095 private static final int STATE_PREPARE = 0;
96 private static final int STATE_DELAYED = 1;
97 private static final int STATE_RUNNING = 2;
98 private static final int STATE_FINISHED = 3;
99 private int mState = STATE_PREPARE;
John Reck315c3292014-05-09 19:21:04 -0700100
John Reck8d8af3c2014-07-01 15:23:45 -0700101 private long mUnscaledDuration = 300;
102 private long mUnscaledStartDelay = 0;
John Reck291161a2014-07-22 07:31:09 -0700103 // If this is true, we will run any start delays on the UI thread. This is
104 // the safe default, and is necessary to ensure start listeners fire at
105 // the correct time. Animators created by RippleDrawable (the
106 // CanvasProperty<> ones) do not have this expectation, and as such will
107 // set this to false so that the renderthread handles the startdelay instead
108 private final boolean mUiThreadHandlesDelay;
109 private long mStartDelay = 0;
110 private long mStartTime;
John Reck8d8af3c2014-07-01 15:23:45 -0700111
Mathew Inwooda570dee2018-08-17 14:56:00 +0100112 @UnsupportedAppUsage
John Reck918988c2014-05-19 10:28:35 -0700113 public static int mapViewPropertyToRenderProperty(int viewProperty) {
John Recke45b1fd2014-04-15 09:50:16 -0700114 return sViewPropertyAnimatorMap.get(viewProperty);
115 }
116
Mathew Inwooda570dee2018-08-17 14:56:00 +0100117 @UnsupportedAppUsage
John Reckff941dc2014-05-14 16:34:14 -0700118 public RenderNodeAnimator(int property, float finalValue) {
John Reck8d8af3c2014-07-01 15:23:45 -0700119 mRenderProperty = property;
120 mFinalValue = finalValue;
John Reck291161a2014-07-22 07:31:09 -0700121 mUiThreadHandlesDelay = true;
John Reck119907c2014-08-14 09:02:01 -0700122 init(nCreateAnimator(property, finalValue));
John Recke45b1fd2014-04-15 09:50:16 -0700123 }
124
Mathew Inwooda570dee2018-08-17 14:56:00 +0100125 @UnsupportedAppUsage
John Reckff941dc2014-05-14 16:34:14 -0700126 public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
John Reck9fa40712014-05-09 15:26:59 -0700127 init(nCreateCanvasPropertyFloatAnimator(
John Reckff941dc2014-05-14 16:34:14 -0700128 property.getNativeContainer(), finalValue));
John Reck291161a2014-07-22 07:31:09 -0700129 mUiThreadHandlesDelay = false;
John Reck52244ff2014-05-01 21:27:37 -0700130 }
131
Alan Viverettead2f8e32014-05-16 13:28:33 -0700132 /**
133 * Creates a new render node animator for a field on a Paint property.
134 *
135 * @param property The paint property to target
136 * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
137 * {@link #PAINT_STROKE_WIDTH}
138 * @param finalValue The target value for the property
139 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100140 @UnsupportedAppUsage
John Reckff941dc2014-05-14 16:34:14 -0700141 public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
John Reck9fa40712014-05-09 15:26:59 -0700142 init(nCreateCanvasPropertyPaintAnimator(
John Reckff941dc2014-05-14 16:34:14 -0700143 property.getNativeContainer(), paintField, finalValue));
John Reck291161a2014-07-22 07:31:09 -0700144 mUiThreadHandlesDelay = false;
John Reck9fa40712014-05-09 15:26:59 -0700145 }
146
Chris Craikaf4d04c2014-07-29 12:50:14 -0700147 public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
John Reck119907c2014-08-14 09:02:01 -0700148 init(nCreateRevealAnimator(x, y, startRadius, endRadius));
John Reck291161a2014-07-22 07:31:09 -0700149 mUiThreadHandlesDelay = true;
John Reckd3de42c2014-07-15 14:29:33 -0700150 }
151
John Reck9fa40712014-05-09 15:26:59 -0700152 private void init(long ptr) {
153 mNativePtr = new VirtualRefBasePtr(ptr);
John Reck52244ff2014-05-01 21:27:37 -0700154 }
155
John Reck315c3292014-05-09 19:21:04 -0700156 private void checkMutable() {
John Reck4d2c4722014-08-29 10:40:56 -0700157 if (mState != STATE_PREPARE) {
John Reck315c3292014-05-09 19:21:04 -0700158 throw new IllegalStateException("Animator has already started, cannot change it now!");
159 }
John Reckc47c98b2014-12-09 09:07:35 -0800160 if (mNativePtr == null) {
161 throw new IllegalStateException("Animator's target has been destroyed "
162 + "(trying to modify an animation after activity destroy?)");
163 }
John Reck315c3292014-05-09 19:21:04 -0700164 }
165
John Reck918988c2014-05-19 10:28:35 -0700166 static boolean isNativeInterpolator(TimeInterpolator interpolator) {
167 return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class);
168 }
169
John Reck315c3292014-05-09 19:21:04 -0700170 private void applyInterpolator() {
John Reck545a3472018-02-14 16:36:16 -0800171 if (mInterpolator == null || mNativePtr == null) return;
John Reck315c3292014-05-09 19:21:04 -0700172
173 long ni;
John Reck918988c2014-05-19 10:28:35 -0700174 if (isNativeInterpolator(mInterpolator)) {
John Reck315c3292014-05-09 19:21:04 -0700175 ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
176 } else {
Alan Viverettead2f8e32014-05-16 13:28:33 -0700177 long duration = nGetDuration(mNativePtr.get());
John Reck315c3292014-05-09 19:21:04 -0700178 ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
179 }
180 nSetInterpolator(mNativePtr.get(), ni);
181 }
182
Alan Viverettead2f8e32014-05-16 13:28:33 -0700183 @Override
184 public void start() {
185 if (mTarget == null) {
186 throw new IllegalStateException("Missing target!");
187 }
188
John Reck4d2c4722014-08-29 10:40:56 -0700189 if (mState != STATE_PREPARE) {
John Reck315c3292014-05-09 19:21:04 -0700190 throw new IllegalStateException("Already started!");
191 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700192
John Reck4d2c4722014-08-29 10:40:56 -0700193 mState = STATE_DELAYED;
John Reck315c3292014-05-09 19:21:04 -0700194 applyInterpolator();
John Reck291161a2014-07-22 07:31:09 -0700195
John Reckc47c98b2014-12-09 09:07:35 -0800196 if (mNativePtr == null) {
197 // It's dead, immediately cancel
198 cancel();
199 } else if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
John Reck291161a2014-07-22 07:31:09 -0700200 nSetStartDelay(mNativePtr.get(), mStartDelay);
201 doStart();
202 } else {
203 getHelper().addDelayedAnimation(this);
204 }
205 }
206
207 private void doStart() {
John Reck8d8af3c2014-07-01 15:23:45 -0700208 // Alpha is a special snowflake that has the canonical value stored
209 // in mTransformationInfo instead of in RenderNode, so we need to update
210 // it with the final value here.
211 if (mRenderProperty == RenderNodeAnimator.ALPHA) {
Chris Craik686d9722017-01-06 16:11:45 -0800212 mViewTarget.ensureTransformationInfo();
John Reck8d8af3c2014-07-01 15:23:45 -0700213 mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
214 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700215
John Reck72d6e4f2014-11-21 14:10:10 -0800216 moveToRunningState();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700217
218 if (mViewTarget != null) {
219 // Kick off a frame to start the process
220 mViewTarget.invalidateViewProperty(true, false);
221 }
John Reck315c3292014-05-09 19:21:04 -0700222 }
223
John Reck72d6e4f2014-11-21 14:10:10 -0800224 private void moveToRunningState() {
225 mState = STATE_RUNNING;
John Reckc47c98b2014-12-09 09:07:35 -0800226 if (mNativePtr != null) {
John Reckfe5dfca2019-01-17 17:01:32 -0800227 if (mHandler == null) {
228 mHandler = new Handler();
229 }
John Reckc47c98b2014-12-09 09:07:35 -0800230 nStart(mNativePtr.get());
231 }
John Reck72d6e4f2014-11-21 14:10:10 -0800232 notifyStartListeners();
233 }
234
John Reck4d2c4722014-08-29 10:40:56 -0700235 private void notifyStartListeners() {
236 final ArrayList<AnimatorListener> listeners = cloneListeners();
237 final int numListeners = listeners == null ? 0 : listeners.size();
238 for (int i = 0; i < numListeners; i++) {
239 listeners.get(i).onAnimationStart(this);
240 }
241 }
242
Alan Viverettead2f8e32014-05-16 13:28:33 -0700243 @Override
244 public void cancel() {
John Reck55b46ef2014-11-03 10:00:33 -0800245 if (mState != STATE_PREPARE && mState != STATE_FINISHED) {
John Reck4d2c4722014-08-29 10:40:56 -0700246 if (mState == STATE_DELAYED) {
247 getHelper().removeDelayedAnimation(this);
John Reck72d6e4f2014-11-21 14:10:10 -0800248 moveToRunningState();
John Reck4d2c4722014-08-29 10:40:56 -0700249 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700250
John Reck3b27e592014-08-21 12:37:48 -0700251 final ArrayList<AnimatorListener> listeners = cloneListeners();
John Reck68bfe0a2014-06-24 15:34:58 -0700252 final int numListeners = listeners == null ? 0 : listeners.size();
253 for (int i = 0; i < numListeners; i++) {
254 listeners.get(i).onAnimationCancel(this);
255 }
John Reck4d2c4722014-08-29 10:40:56 -0700256
John Reckc47c98b2014-12-09 09:07:35 -0800257 end();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700258 }
John Recke45b1fd2014-04-15 09:50:16 -0700259 }
260
Alan Viverettead2f8e32014-05-16 13:28:33 -0700261 @Override
262 public void end() {
John Reck4d2c4722014-08-29 10:40:56 -0700263 if (mState != STATE_FINISHED) {
John Reck72d6e4f2014-11-21 14:10:10 -0800264 if (mState < STATE_RUNNING) {
265 getHelper().removeDelayedAnimation(this);
266 doStart();
267 }
John Reckc47c98b2014-12-09 09:07:35 -0800268 if (mNativePtr != null) {
269 nEnd(mNativePtr.get());
270 if (mViewTarget != null) {
271 // Kick off a frame to flush the state change
272 mViewTarget.invalidateViewProperty(true, false);
273 }
274 } else {
275 // It's already dead, jump to onFinish
276 onFinished();
John Reck72d6e4f2014-11-21 14:10:10 -0800277 }
John Reckd3de42c2014-07-15 14:29:33 -0700278 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700279 }
280
281 @Override
282 public void pause() {
283 throw new UnsupportedOperationException();
284 }
285
286 @Override
287 public void resume() {
288 throw new UnsupportedOperationException();
289 }
290
Mathew Inwood8e828652019-02-13 11:11:07 +0000291 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Alan Viverettead2f8e32014-05-16 13:28:33 -0700292 public void setTarget(View view) {
293 mViewTarget = view;
John Reck119907c2014-08-14 09:02:01 -0700294 setTarget(mViewTarget.mRenderNode);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700295 }
296
John Reck32f140aa62018-10-04 15:08:24 -0700297 /** Sets the animation target to the owning view of the RecordingCanvas */
298 public void setTarget(RecordingCanvas canvas) {
John Reck0c453cc2017-11-16 13:44:35 -0800299 setTarget(canvas.mNode);
John Reck1c058e92014-05-02 14:20:53 -0700300 }
301
John Reck5c6397e2018-11-14 15:14:44 -0800302 /** @hide */
Mathew Inwood8e828652019-02-13 11:11:07 +0000303 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O)
John Reck5c6397e2018-11-14 15:14:44 -0800304 public void setTarget(DisplayListCanvas canvas) {
305 setTarget((RecordingCanvas) canvas);
306 }
307
John Reck119907c2014-08-14 09:02:01 -0700308 private void setTarget(RenderNode node) {
John Reckc47c98b2014-12-09 09:07:35 -0800309 checkMutable();
John Reck8d8af3c2014-07-01 15:23:45 -0700310 if (mTarget != null) {
311 throw new IllegalStateException("Target already set!");
312 }
John Reckc47c98b2014-12-09 09:07:35 -0800313 nSetListener(mNativePtr.get(), this);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700314 mTarget = node;
John Reck8d8af3c2014-07-01 15:23:45 -0700315 mTarget.addAnimator(this);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700316 }
317
Mathew Inwooda570dee2018-08-17 14:56:00 +0100318 @UnsupportedAppUsage
John Reckc6b32642014-06-02 11:00:09 -0700319 public void setStartValue(float startValue) {
320 checkMutable();
321 nSetStartValue(mNativePtr.get(), startValue);
322 }
323
Alan Viverettead2f8e32014-05-16 13:28:33 -0700324 @Override
325 public void setStartDelay(long startDelay) {
326 checkMutable();
John Reck68bfe0a2014-06-24 15:34:58 -0700327 if (startDelay < 0) {
328 throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
329 }
John Reck8d8af3c2014-07-01 15:23:45 -0700330 mUnscaledStartDelay = startDelay;
John Reck291161a2014-07-22 07:31:09 -0700331 mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700332 }
333
334 @Override
335 public long getStartDelay() {
John Reck8d8af3c2014-07-01 15:23:45 -0700336 return mUnscaledStartDelay;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700337 }
338
Andrei Oneaf4fb6fb2019-02-27 14:46:52 +0000339 @UnsupportedAppUsage
Alan Viverettead2f8e32014-05-16 13:28:33 -0700340 @Override
341 public RenderNodeAnimator setDuration(long duration) {
John Reck315c3292014-05-09 19:21:04 -0700342 checkMutable();
John Reck68bfe0a2014-06-24 15:34:58 -0700343 if (duration < 0) {
344 throw new IllegalArgumentException("duration must be positive; " + duration);
345 }
John Reck8d8af3c2014-07-01 15:23:45 -0700346 mUnscaledDuration = duration;
347 nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
Alan Viverettead2f8e32014-05-16 13:28:33 -0700348 return this;
John Recke45b1fd2014-04-15 09:50:16 -0700349 }
350
Alan Viverettead2f8e32014-05-16 13:28:33 -0700351 @Override
352 public long getDuration() {
John Reck8d8af3c2014-07-01 15:23:45 -0700353 return mUnscaledDuration;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700354 }
355
Doris Liu13099142015-07-10 17:32:41 -0700356 @Override
357 public long getTotalDuration() {
358 return mUnscaledDuration + mUnscaledStartDelay;
359 }
360
Alan Viverettead2f8e32014-05-16 13:28:33 -0700361 @Override
362 public boolean isRunning() {
John Reck4d2c4722014-08-29 10:40:56 -0700363 return mState == STATE_DELAYED || mState == STATE_RUNNING;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700364 }
365
366 @Override
John Reckd3de42c2014-07-15 14:29:33 -0700367 public boolean isStarted() {
John Reck4d2c4722014-08-29 10:40:56 -0700368 return mState != STATE_PREPARE;
John Reckd3de42c2014-07-15 14:29:33 -0700369 }
370
371 @Override
John Reck315c3292014-05-09 19:21:04 -0700372 public void setInterpolator(TimeInterpolator interpolator) {
373 checkMutable();
374 mInterpolator = interpolator;
375 }
376
Alan Viverettead2f8e32014-05-16 13:28:33 -0700377 @Override
378 public TimeInterpolator getInterpolator() {
379 return mInterpolator;
John Recke45b1fd2014-04-15 09:50:16 -0700380 }
381
John Reck291161a2014-07-22 07:31:09 -0700382 protected void onFinished() {
John Reckc47c98b2014-12-09 09:07:35 -0800383 if (mState == STATE_PREPARE) {
384 // Unlikely but possible, the native side has been destroyed
385 // before we have started.
386 releaseNativePtr();
387 return;
388 }
John Reck4d2c4722014-08-29 10:40:56 -0700389 if (mState == STATE_DELAYED) {
390 getHelper().removeDelayedAnimation(this);
391 notifyStartListeners();
392 }
393 mState = STATE_FINISHED;
Alan Viverettead2f8e32014-05-16 13:28:33 -0700394
John Reck3b27e592014-08-21 12:37:48 -0700395 final ArrayList<AnimatorListener> listeners = cloneListeners();
Alan Viverettead2f8e32014-05-16 13:28:33 -0700396 final int numListeners = listeners == null ? 0 : listeners.size();
397 for (int i = 0; i < numListeners; i++) {
398 listeners.get(i).onAnimationEnd(this);
399 }
John Reck119907c2014-08-14 09:02:01 -0700400
401 // Release the native object, as it has a global reference to us. This
402 // breaks the cyclic reference chain, and allows this object to be
403 // GC'd
John Reckc47c98b2014-12-09 09:07:35 -0800404 releaseNativePtr();
405 }
406
407 private void releaseNativePtr() {
408 if (mNativePtr != null) {
409 mNativePtr.release();
410 mNativePtr = null;
411 }
Alan Viverettead2f8e32014-05-16 13:28:33 -0700412 }
413
John Reck3b27e592014-08-21 12:37:48 -0700414 @SuppressWarnings("unchecked")
415 private ArrayList<AnimatorListener> cloneListeners() {
416 ArrayList<AnimatorListener> listeners = getListeners();
417 if (listeners != null) {
418 listeners = (ArrayList<AnimatorListener>) listeners.clone();
419 }
420 return listeners;
421 }
422
John Reck32f140aa62018-10-04 15:08:24 -0700423 public long getNativeAnimator() {
Alan Viverettead2f8e32014-05-16 13:28:33 -0700424 return mNativePtr.get();
John Recke45b1fd2014-04-15 09:50:16 -0700425 }
426
John Reck291161a2014-07-22 07:31:09 -0700427 /**
428 * @return true if the animator was started, false if still delayed
429 */
430 private boolean processDelayed(long frameTimeMs) {
431 if (mStartTime == 0) {
432 mStartTime = frameTimeMs;
433 } else if ((frameTimeMs - mStartTime) >= mStartDelay) {
434 doStart();
435 return true;
436 }
437 return false;
438 }
439
440 private static DelayedAnimationHelper getHelper() {
441 DelayedAnimationHelper helper = sAnimationHelper.get();
442 if (helper == null) {
443 helper = new DelayedAnimationHelper();
444 sAnimationHelper.set(helper);
445 }
446 return helper;
447 }
448
449 private static ThreadLocal<DelayedAnimationHelper> sAnimationHelper =
450 new ThreadLocal<DelayedAnimationHelper>();
451
452 private static class DelayedAnimationHelper implements Runnable {
453
454 private ArrayList<RenderNodeAnimator> mDelayedAnims = new ArrayList<RenderNodeAnimator>();
455 private final Choreographer mChoreographer;
456 private boolean mCallbackScheduled;
457
458 public DelayedAnimationHelper() {
459 mChoreographer = Choreographer.getInstance();
460 }
461
462 public void addDelayedAnimation(RenderNodeAnimator animator) {
463 mDelayedAnims.add(animator);
464 scheduleCallback();
465 }
466
467 public void removeDelayedAnimation(RenderNodeAnimator animator) {
468 mDelayedAnims.remove(animator);
469 }
470
471 private void scheduleCallback() {
472 if (!mCallbackScheduled) {
473 mCallbackScheduled = true;
474 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
475 }
476 }
477
478 @Override
479 public void run() {
480 long frameTimeMs = mChoreographer.getFrameTime();
481 mCallbackScheduled = false;
482
483 int end = 0;
484 for (int i = 0; i < mDelayedAnims.size(); i++) {
485 RenderNodeAnimator animator = mDelayedAnims.get(i);
486 if (!animator.processDelayed(frameTimeMs)) {
487 if (end != i) {
488 mDelayedAnims.set(end, animator);
489 }
490 end++;
491 }
492 }
493 while (mDelayedAnims.size() > end) {
494 mDelayedAnims.remove(mDelayedAnims.size() - 1);
495 }
496
497 if (mDelayedAnims.size() > 0) {
498 scheduleCallback();
499 }
500 }
501 }
502
John Recke45b1fd2014-04-15 09:50:16 -0700503 // Called by native
Mathew Inwooda570dee2018-08-17 14:56:00 +0100504 @UnsupportedAppUsage
John Reck119907c2014-08-14 09:02:01 -0700505 private static void callOnFinished(RenderNodeAnimator animator) {
John Reckfe5dfca2019-01-17 17:01:32 -0800506 animator.mHandler.post(animator::onFinished);
John Recke45b1fd2014-04-15 09:50:16 -0700507 }
508
John Reck291161a2014-07-22 07:31:09 -0700509 @Override
510 public Animator clone() {
511 throw new IllegalStateException("Cannot clone this animator");
512 }
513
John Reckf5945a02014-09-05 15:57:47 -0700514 @Override
515 public void setAllowRunningAsynchronously(boolean mayRunAsync) {
516 checkMutable();
517 nSetAllowRunningAsync(mNativePtr.get(), mayRunAsync);
518 }
519
John Reck119907c2014-08-14 09:02:01 -0700520 private static native long nCreateAnimator(int property, float finalValue);
521 private static native long nCreateCanvasPropertyFloatAnimator(
John Reckc6b32642014-06-02 11:00:09 -0700522 long canvasProperty, float finalValue);
John Reck119907c2014-08-14 09:02:01 -0700523 private static native long nCreateCanvasPropertyPaintAnimator(
John Reckc6b32642014-06-02 11:00:09 -0700524 long canvasProperty, int paintField, float finalValue);
John Reck119907c2014-08-14 09:02:01 -0700525 private static native long nCreateRevealAnimator(
Chris Craikaf4d04c2014-07-29 12:50:14 -0700526 int x, int y, float startRadius, float endRadius);
John Reck68bfe0a2014-06-24 15:34:58 -0700527
John Reckc6b32642014-06-02 11:00:09 -0700528 private static native void nSetStartValue(long nativePtr, float startValue);
Alan Viverettead2f8e32014-05-16 13:28:33 -0700529 private static native void nSetDuration(long nativePtr, long duration);
530 private static native long nGetDuration(long nativePtr);
531 private static native void nSetStartDelay(long nativePtr, long startDelay);
John Reck315c3292014-05-09 19:21:04 -0700532 private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
John Reckf5945a02014-09-05 15:57:47 -0700533 private static native void nSetAllowRunningAsync(long animPtr, boolean mayRunAsync);
John Reckc47c98b2014-12-09 09:07:35 -0800534 private static native void nSetListener(long animPtr, RenderNodeAnimator listener);
John Reck68bfe0a2014-06-24 15:34:58 -0700535
John Reckc47c98b2014-12-09 09:07:35 -0800536 private static native void nStart(long animPtr);
John Reckd3de42c2014-07-15 14:29:33 -0700537 private static native void nEnd(long animPtr);
John Recke45b1fd2014-04-15 09:50:16 -0700538}