RenderNodeAnimator.java revision af4d04cab6d48ae0d6a5e79bd30f679af87abaad
1/*
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
19import android.animation.Animator;
20import android.animation.TimeInterpolator;
21import android.animation.ValueAnimator;
22import android.graphics.Canvas;
23import android.graphics.CanvasProperty;
24import android.graphics.Paint;
25import android.util.SparseIntArray;
26
27import com.android.internal.util.VirtualRefBasePtr;
28import com.android.internal.view.animation.FallbackLUTInterpolator;
29import com.android.internal.view.animation.HasNativeInterpolator;
30import com.android.internal.view.animation.NativeInterpolatorFactory;
31
32import java.lang.ref.WeakReference;
33import java.util.ArrayList;
34
35/**
36 * @hide
37 */
38public class RenderNodeAnimator extends Animator {
39    // Keep in sync with enum RenderProperty in Animator.h
40    public static final int TRANSLATION_X = 0;
41    public static final int TRANSLATION_Y = 1;
42    public static final int TRANSLATION_Z = 2;
43    public static final int SCALE_X = 3;
44    public static final int SCALE_Y = 4;
45    public static final int ROTATION = 5;
46    public static final int ROTATION_X = 6;
47    public static final int ROTATION_Y = 7;
48    public static final int X = 8;
49    public static final int Y = 9;
50    public static final int Z = 10;
51    public static final int ALPHA = 11;
52    // The last value in the enum, used for array size initialization
53    public static final int LAST_VALUE = ALPHA;
54
55    // Keep in sync with enum PaintFields in Animator.h
56    public static final int PAINT_STROKE_WIDTH = 0;
57
58    /**
59     * Field for the Paint alpha channel, which should be specified as a value
60     * between 0 and 255.
61     */
62    public static final int PAINT_ALPHA = 1;
63
64    // ViewPropertyAnimator uses a mask for its values, we need to remap them
65    // to the enum values here. RenderPropertyAnimator can't use the mask values
66    // directly as internally it uses a lookup table so it needs the values to
67    // be sequential starting from 0
68    private static final SparseIntArray sViewPropertyAnimatorMap = new SparseIntArray(15) {{
69        put(ViewPropertyAnimator.TRANSLATION_X, TRANSLATION_X);
70        put(ViewPropertyAnimator.TRANSLATION_Y, TRANSLATION_Y);
71        put(ViewPropertyAnimator.TRANSLATION_Z, TRANSLATION_Z);
72        put(ViewPropertyAnimator.SCALE_X, SCALE_X);
73        put(ViewPropertyAnimator.SCALE_Y, SCALE_Y);
74        put(ViewPropertyAnimator.ROTATION, ROTATION);
75        put(ViewPropertyAnimator.ROTATION_X, ROTATION_X);
76        put(ViewPropertyAnimator.ROTATION_Y, ROTATION_Y);
77        put(ViewPropertyAnimator.X, X);
78        put(ViewPropertyAnimator.Y, Y);
79        put(ViewPropertyAnimator.Z, Z);
80        put(ViewPropertyAnimator.ALPHA, ALPHA);
81    }};
82
83    private VirtualRefBasePtr mNativePtr;
84
85    private RenderNode mTarget;
86    private View mViewTarget;
87    private int mRenderProperty = -1;
88    private float mFinalValue;
89    private TimeInterpolator mInterpolator;
90
91    private boolean mStarted = false;
92    private boolean mFinished = false;
93
94    private long mUnscaledDuration = 300;
95    private long mUnscaledStartDelay = 0;
96
97    public static int mapViewPropertyToRenderProperty(int viewProperty) {
98        return sViewPropertyAnimatorMap.get(viewProperty);
99    }
100
101    public RenderNodeAnimator(int property, float finalValue) {
102        mRenderProperty = property;
103        mFinalValue = finalValue;
104        init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
105                property, finalValue));
106    }
107
108    public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
109        init(nCreateCanvasPropertyFloatAnimator(
110                new WeakReference<RenderNodeAnimator>(this),
111                property.getNativeContainer(), finalValue));
112    }
113
114    /**
115     * Creates a new render node animator for a field on a Paint property.
116     *
117     * @param property The paint property to target
118     * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
119     *            {@link #PAINT_STROKE_WIDTH}
120     * @param finalValue The target value for the property
121     */
122    public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
123        init(nCreateCanvasPropertyPaintAnimator(
124                new WeakReference<RenderNodeAnimator>(this),
125                property.getNativeContainer(), paintField, finalValue));
126    }
127
128    public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
129        init(nCreateRevealAnimator(new WeakReference<RenderNodeAnimator>(this),
130                x, y, startRadius, endRadius));
131    }
132
133    private void init(long ptr) {
134        mNativePtr = new VirtualRefBasePtr(ptr);
135    }
136
137    private void checkMutable() {
138        if (mStarted) {
139            throw new IllegalStateException("Animator has already started, cannot change it now!");
140        }
141    }
142
143    static boolean isNativeInterpolator(TimeInterpolator interpolator) {
144        return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class);
145    }
146
147    private void applyInterpolator() {
148        if (mInterpolator == null) return;
149
150        long ni;
151        if (isNativeInterpolator(mInterpolator)) {
152            ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
153        } else {
154            long duration = nGetDuration(mNativePtr.get());
155            ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
156        }
157        nSetInterpolator(mNativePtr.get(), ni);
158    }
159
160    @Override
161    public void start() {
162        if (mTarget == null) {
163            throw new IllegalStateException("Missing target!");
164        }
165
166        if (mStarted) {
167            throw new IllegalStateException("Already started!");
168        }
169
170        mStarted = true;
171        applyInterpolator();
172        nStart(mNativePtr.get());
173
174        // Alpha is a special snowflake that has the canonical value stored
175        // in mTransformationInfo instead of in RenderNode, so we need to update
176        // it with the final value here.
177        if (mRenderProperty == RenderNodeAnimator.ALPHA) {
178            // Don't need null check because ViewPropertyAnimator's
179            // ctor calls ensureTransformationInfo()
180            mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
181        }
182
183        final ArrayList<AnimatorListener> listeners = getListeners();
184        final int numListeners = listeners == null ? 0 : listeners.size();
185        for (int i = 0; i < numListeners; i++) {
186            listeners.get(i).onAnimationStart(this);
187        }
188
189        if (mViewTarget != null) {
190            // Kick off a frame to start the process
191            mViewTarget.invalidateViewProperty(true, false);
192        }
193    }
194
195    @Override
196    public void cancel() {
197        if (!mFinished) {
198            nEnd(mNativePtr.get());
199
200            final ArrayList<AnimatorListener> listeners = getListeners();
201            final int numListeners = listeners == null ? 0 : listeners.size();
202            for (int i = 0; i < numListeners; i++) {
203                listeners.get(i).onAnimationCancel(this);
204            }
205        }
206    }
207
208    @Override
209    public void end() {
210        if (!mFinished) {
211            nEnd(mNativePtr.get());
212        }
213    }
214
215    @Override
216    public void pause() {
217        throw new UnsupportedOperationException();
218    }
219
220    @Override
221    public void resume() {
222        throw new UnsupportedOperationException();
223    }
224
225    public void setTarget(View view) {
226        mViewTarget = view;
227        mTarget = view.mRenderNode;
228        mTarget.addAnimator(this);
229    }
230
231    public void setTarget(Canvas canvas) {
232        if (!(canvas instanceof GLES20RecordingCanvas)) {
233            throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
234        }
235
236        final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
237        setTarget(recordingCanvas.mNode);
238    }
239
240    public void setTarget(RenderNode node) {
241        if (mTarget != null) {
242            throw new IllegalStateException("Target already set!");
243        }
244        mViewTarget = null;
245        mTarget = node;
246        mTarget.addAnimator(this);
247    }
248
249    public void setStartValue(float startValue) {
250        checkMutable();
251        nSetStartValue(mNativePtr.get(), startValue);
252    }
253
254    @Override
255    public void setStartDelay(long startDelay) {
256        checkMutable();
257        if (startDelay < 0) {
258            throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
259        }
260        mUnscaledStartDelay = startDelay;
261        nSetStartDelay(mNativePtr.get(), (long) (startDelay * ValueAnimator.getDurationScale()));
262    }
263
264    @Override
265    public long getStartDelay() {
266        return mUnscaledStartDelay;
267    }
268
269    @Override
270    public RenderNodeAnimator setDuration(long duration) {
271        checkMutable();
272        if (duration < 0) {
273            throw new IllegalArgumentException("duration must be positive; " + duration);
274        }
275        mUnscaledDuration = duration;
276        nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
277        return this;
278    }
279
280    @Override
281    public long getDuration() {
282        return mUnscaledDuration;
283    }
284
285    @Override
286    public boolean isRunning() {
287        return mStarted && !mFinished;
288    }
289
290    @Override
291    public boolean isStarted() {
292        return mStarted;
293    }
294
295    @Override
296    public void setInterpolator(TimeInterpolator interpolator) {
297        checkMutable();
298        mInterpolator = interpolator;
299    }
300
301    @Override
302    public TimeInterpolator getInterpolator() {
303        return mInterpolator;
304    }
305
306    private void onFinished() {
307        mFinished = true;
308
309        final ArrayList<AnimatorListener> listeners = getListeners();
310        final int numListeners = listeners == null ? 0 : listeners.size();
311        for (int i = 0; i < numListeners; i++) {
312            listeners.get(i).onAnimationEnd(this);
313        }
314    }
315
316    long getNativeAnimator() {
317        return mNativePtr.get();
318    }
319
320    // Called by native
321    private static void callOnFinished(WeakReference<RenderNodeAnimator> weakThis) {
322        RenderNodeAnimator animator = weakThis.get();
323        if (animator != null) {
324            animator.onFinished();
325        }
326    }
327
328    private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
329            int property, float finalValue);
330    private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,
331            long canvasProperty, float finalValue);
332    private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
333            long canvasProperty, int paintField, float finalValue);
334    private static native long nCreateRevealAnimator(WeakReference<RenderNodeAnimator> weakThis,
335            int x, int y, float startRadius, float endRadius);
336
337    private static native void nSetStartValue(long nativePtr, float startValue);
338    private static native void nSetDuration(long nativePtr, long duration);
339    private static native long nGetDuration(long nativePtr);
340    private static native void nSetStartDelay(long nativePtr, long startDelay);
341    private static native long nGetStartDelay(long nativePtr);
342    private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
343
344    private static native void nStart(long animPtr);
345    private static native void nEnd(long animPtr);
346}
347