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 */
16package android.support.v4.view;
17
18import android.view.View;
19import android.view.animation.Interpolator;
20
21import java.lang.ref.WeakReference;
22import java.util.WeakHashMap;
23
24public class ViewPropertyAnimatorCompat {
25    private static final String TAG = "ViewAnimatorCompat";
26    private WeakReference<View> mView;
27    private Runnable mStartAction = null;
28    private Runnable mEndAction = null;
29    private int mOldLayerType = -1;
30    // HACK ALERT! Choosing this id knowing that the framework does not use it anywhere
31    // internally and apps should use ids higher than it
32    static final int LISTENER_TAG_ID = 0x7e000000;
33
34
35    ViewPropertyAnimatorCompat(View view) {
36        mView = new WeakReference<View>(view);
37    }
38
39    interface ViewPropertyAnimatorCompatImpl {
40        public void setDuration(ViewPropertyAnimatorCompat vpa, View view, long value);
41        public long getDuration(ViewPropertyAnimatorCompat vpa, View view);
42        public void setInterpolator(ViewPropertyAnimatorCompat vpa, View view, Interpolator value);
43        public Interpolator getInterpolator(ViewPropertyAnimatorCompat vpa, View view);
44        public void setStartDelay(ViewPropertyAnimatorCompat vpa, View view, long value);
45        public long getStartDelay(ViewPropertyAnimatorCompat vpa, View view);
46        public void alpha(ViewPropertyAnimatorCompat vpa, View view, float value);
47        public void alphaBy(ViewPropertyAnimatorCompat vpa, View view, float value);
48        public void rotation(ViewPropertyAnimatorCompat vpa, View view, float value);
49        public void rotationBy(ViewPropertyAnimatorCompat vpa, View view, float value);
50        public void rotationX(ViewPropertyAnimatorCompat vpa, View view, float value);
51        public void rotationXBy(ViewPropertyAnimatorCompat vpa, View view, float value);
52        public void rotationY(ViewPropertyAnimatorCompat vpa, View view, float value);
53        public void rotationYBy(ViewPropertyAnimatorCompat vpa, View view, float value);
54        public void scaleX(ViewPropertyAnimatorCompat vpa, View view, float value);
55        public void scaleXBy(ViewPropertyAnimatorCompat vpa, View view, float value);
56        public void scaleY(ViewPropertyAnimatorCompat vpa, View view, float value);
57        public void scaleYBy(ViewPropertyAnimatorCompat vpa, View view, float value);
58        public void cancel(ViewPropertyAnimatorCompat vpa, View view);
59        public void x(ViewPropertyAnimatorCompat vpa, View view, float value);
60        public void xBy(ViewPropertyAnimatorCompat vpa, View view, float value);
61        public void y(ViewPropertyAnimatorCompat vpa, View view, float value);
62        public void yBy(ViewPropertyAnimatorCompat vpa, View view, float value);
63        public void translationX(ViewPropertyAnimatorCompat vpa, View view, float value);
64        public void translationXBy(ViewPropertyAnimatorCompat vpa, View view, float value);
65        public void translationY(ViewPropertyAnimatorCompat vpa, View view, float value);
66        public void translationYBy(ViewPropertyAnimatorCompat vpa, View view, float value);
67        public void start(ViewPropertyAnimatorCompat vpa, View view);
68        public void withLayer(ViewPropertyAnimatorCompat vpa, View view);
69        public void withStartAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable);
70        public void withEndAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable);
71        public void setListener(ViewPropertyAnimatorCompat vpa, View view,
72                ViewPropertyAnimatorListener listener);
73        public void setUpdateListener(ViewPropertyAnimatorCompat vpa, View view,
74                ViewPropertyAnimatorUpdateListener listener);
75    };
76
77    static class BaseViewPropertyAnimatorCompatImpl implements ViewPropertyAnimatorCompatImpl {
78        WeakHashMap<View, Runnable> mStarterMap = null;
79
80        @Override
81        public void setDuration(ViewPropertyAnimatorCompat vpa, View view, long value) {
82            // noop on versions prior to ICS
83        }
84
85        @Override
86        public void alpha(ViewPropertyAnimatorCompat vpa, View view, float value) {
87            // noop on versions prior to ICS
88            postStartMessage(vpa, view);
89        }
90
91        @Override
92        public void translationX(ViewPropertyAnimatorCompat vpa, View view, float value) {
93            // noop on versions prior to ICS
94            postStartMessage(vpa, view);
95        }
96
97        @Override
98        public void translationY(ViewPropertyAnimatorCompat vpa, View view, float value) {
99            // noop on versions prior to ICS
100            postStartMessage(vpa, view);
101        }
102
103        @Override
104        public void withEndAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable) {
105            vpa.mEndAction = runnable;
106            postStartMessage(vpa, view);
107        }
108
109        @Override
110        public long getDuration(ViewPropertyAnimatorCompat vpa, View view) {
111            return 0;
112        }
113
114        @Override
115        public void setInterpolator(ViewPropertyAnimatorCompat vpa, View view, Interpolator value) {
116            // noop on versions prior to ICS
117        }
118
119        @Override
120        public Interpolator getInterpolator(ViewPropertyAnimatorCompat vpa, View view) {
121            return null;
122        }
123
124        @Override
125        public void setStartDelay(ViewPropertyAnimatorCompat vpa, View view, long value) {
126            // noop on versions prior to ICS
127        }
128
129        @Override
130        public long getStartDelay(ViewPropertyAnimatorCompat vpa, View view) {
131            return 0;
132        }
133
134        @Override
135        public void alphaBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
136            // noop on versions prior to ICS
137            postStartMessage(vpa, view);
138        }
139
140        @Override
141        public void rotation(ViewPropertyAnimatorCompat vpa, View view, float value) {
142            // noop on versions prior to ICS
143            postStartMessage(vpa, view);
144        }
145
146        @Override
147        public void rotationBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
148            // noop on versions prior to ICS
149            postStartMessage(vpa, view);
150        }
151
152        @Override
153        public void rotationX(ViewPropertyAnimatorCompat vpa, View view, float value) {
154            // noop on versions prior to ICS
155            postStartMessage(vpa, view);
156        }
157
158        @Override
159        public void rotationXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
160            // noop on versions prior to ICS
161            postStartMessage(vpa, view);
162        }
163
164        @Override
165        public void rotationY(ViewPropertyAnimatorCompat vpa, View view, float value) {
166            // noop on versions prior to ICS
167            postStartMessage(vpa, view);
168        }
169
170        @Override
171        public void rotationYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
172            // noop on versions prior to ICS
173            postStartMessage(vpa, view);
174        }
175
176        @Override
177        public void scaleX(ViewPropertyAnimatorCompat vpa, View view, float value) {
178            // noop on versions prior to ICS
179            postStartMessage(vpa, view);
180        }
181
182        @Override
183        public void scaleXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
184            // noop on versions prior to ICS
185            postStartMessage(vpa, view);
186        }
187
188        @Override
189        public void scaleY(ViewPropertyAnimatorCompat vpa, View view, float value) {
190            // noop on versions prior to ICS
191            postStartMessage(vpa, view);
192        }
193
194        @Override
195        public void scaleYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
196            // noop on versions prior to ICS
197            postStartMessage(vpa, view);
198        }
199
200        @Override
201        public void cancel(ViewPropertyAnimatorCompat vpa, View view) {
202            // noop on versions prior to ICS
203            postStartMessage(vpa, view);
204        }
205
206        @Override
207        public void x(ViewPropertyAnimatorCompat vpa, View view, float value) {
208            // noop on versions prior to ICS
209            postStartMessage(vpa, view);
210        }
211
212        @Override
213        public void xBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
214            // noop on versions prior to ICS
215            postStartMessage(vpa, view);
216        }
217
218        @Override
219        public void y(ViewPropertyAnimatorCompat vpa, View view, float value) {
220            // noop on versions prior to ICS
221            postStartMessage(vpa, view);
222        }
223
224        @Override
225        public void yBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
226            // noop on versions prior to ICS
227            postStartMessage(vpa, view);
228        }
229
230        @Override
231        public void translationXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
232            // noop on versions prior to ICS
233            postStartMessage(vpa, view);
234        }
235
236        @Override
237        public void translationYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
238            // noop on versions prior to ICS
239            postStartMessage(vpa, view);
240        }
241
242        @Override
243        public void start(ViewPropertyAnimatorCompat vpa, View view) {
244            removeStartMessage(view);
245            startAnimation(vpa, view);
246        }
247
248        @Override
249        public void withLayer(ViewPropertyAnimatorCompat vpa, View view) {
250            // noop on versions prior to ICS
251        }
252
253        @Override
254        public void withStartAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable) {
255            vpa.mStartAction = runnable;
256            postStartMessage(vpa, view);
257        }
258
259        @Override
260        public void setListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorListener listener) {
261            view.setTag(LISTENER_TAG_ID, listener);
262        }
263
264        @Override
265        public void setUpdateListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorUpdateListener listener) {
266            // noop
267        }
268
269        private void startAnimation(ViewPropertyAnimatorCompat vpa, View view) {
270            Object listenerTag = view.getTag(LISTENER_TAG_ID);
271            ViewPropertyAnimatorListener listener = null;
272            if (listenerTag instanceof ViewPropertyAnimatorListener) {
273                listener = (ViewPropertyAnimatorListener) listenerTag;
274            }
275            Runnable startAction = vpa.mStartAction;
276            Runnable endAction = vpa.mEndAction;
277            if (startAction != null) {
278                startAction.run();
279            }
280            if (listener != null) {
281                listener.onAnimationStart(view);
282                listener.onAnimationEnd(view);
283            }
284            if (endAction != null) {
285                endAction.run();
286            }
287            if (mStarterMap != null) {
288                mStarterMap.remove(view);
289            }
290        }
291
292        class Starter implements Runnable {
293            WeakReference<View> mViewRef;
294            ViewPropertyAnimatorCompat mVpa;
295
296            private Starter(ViewPropertyAnimatorCompat vpa, View view) {
297                mViewRef = new WeakReference<View>(view);
298                mVpa = vpa;
299            }
300
301            @Override
302            public void run() {
303                startAnimation(mVpa, mViewRef.get());
304            }
305        };
306
307        private void removeStartMessage(View view) {
308            Runnable starter = null;
309            if (mStarterMap != null) {
310                starter = mStarterMap.get(view);
311                if (starter != null) {
312                    view.removeCallbacks(starter);
313                }
314            }
315        }
316
317        private void postStartMessage(ViewPropertyAnimatorCompat vpa, View view) {
318            Runnable starter = null;
319            if (mStarterMap != null) {
320                starter = mStarterMap.get(view);
321            }
322            if (starter == null) {
323                starter = new Starter(vpa, view);
324                if (mStarterMap == null) {
325                    mStarterMap = new WeakHashMap<View, Runnable>();
326                }
327                mStarterMap.put(view, starter);
328            }
329            view.removeCallbacks(starter);
330            view.post(starter);
331        }
332
333    }
334
335    static class ICSViewPropertyAnimatorCompatImpl extends BaseViewPropertyAnimatorCompatImpl {
336        WeakHashMap<View, Integer> mLayerMap = null;
337
338        @Override
339        public void setDuration(ViewPropertyAnimatorCompat vpa, View view, long value) {
340            ViewPropertyAnimatorCompatICS.setDuration(view, value);
341        }
342
343        @Override
344        public void alpha(ViewPropertyAnimatorCompat vpa, View view, float value) {
345            ViewPropertyAnimatorCompatICS.alpha(view, value);
346        }
347
348        @Override
349        public void translationX(ViewPropertyAnimatorCompat vpa, View view, float value) {
350            ViewPropertyAnimatorCompatICS.translationX(view, value);
351        }
352
353        @Override
354        public void translationY(ViewPropertyAnimatorCompat vpa, View view, float value) {
355            ViewPropertyAnimatorCompatICS.translationY(view, value);
356        }
357
358        @Override
359        public long getDuration(ViewPropertyAnimatorCompat vpa, View view) {
360            return ViewPropertyAnimatorCompatICS.getDuration(view);
361        }
362
363        @Override
364        public void setInterpolator(ViewPropertyAnimatorCompat vpa, View view, Interpolator value) {
365            ViewPropertyAnimatorCompatICS.setInterpolator(view, value);
366        }
367
368        @Override
369        public void setStartDelay(ViewPropertyAnimatorCompat vpa, View view, long value) {
370            ViewPropertyAnimatorCompatICS.setStartDelay(view, value);
371        }
372
373        @Override
374        public long getStartDelay(ViewPropertyAnimatorCompat vpa, View view) {
375            return ViewPropertyAnimatorCompatICS.getStartDelay(view);
376        }
377
378        @Override
379        public void alphaBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
380            ViewPropertyAnimatorCompatICS.alphaBy(view, value);
381        }
382
383        @Override
384        public void rotation(ViewPropertyAnimatorCompat vpa, View view, float value) {
385            ViewPropertyAnimatorCompatICS.rotation(view, value);
386        }
387
388        @Override
389        public void rotationBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
390            ViewPropertyAnimatorCompatICS.rotationBy(view, value);
391        }
392
393        @Override
394        public void rotationX(ViewPropertyAnimatorCompat vpa, View view, float value) {
395            ViewPropertyAnimatorCompatICS.rotationX(view, value);
396        }
397
398        @Override
399        public void rotationXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
400            ViewPropertyAnimatorCompatICS.rotationXBy(view, value);
401        }
402
403        @Override
404        public void rotationY(ViewPropertyAnimatorCompat vpa, View view, float value) {
405            ViewPropertyAnimatorCompatICS.rotationY(view, value);
406        }
407
408        @Override
409        public void rotationYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
410            ViewPropertyAnimatorCompatICS.rotationYBy(view, value);
411        }
412
413        @Override
414        public void scaleX(ViewPropertyAnimatorCompat vpa, View view, float value) {
415            ViewPropertyAnimatorCompatICS.scaleX(view, value);
416        }
417
418        @Override
419        public void scaleXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
420            ViewPropertyAnimatorCompatICS.scaleXBy(view, value);
421        }
422
423        @Override
424        public void scaleY(ViewPropertyAnimatorCompat vpa, View view, float value) {
425            ViewPropertyAnimatorCompatICS.scaleY(view, value);
426        }
427
428        @Override
429        public void scaleYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
430            ViewPropertyAnimatorCompatICS.scaleYBy(view, value);
431        }
432
433        @Override
434        public void cancel(ViewPropertyAnimatorCompat vpa, View view) {
435            ViewPropertyAnimatorCompatICS.cancel(view);
436        }
437
438        @Override
439        public void x(ViewPropertyAnimatorCompat vpa, View view, float value) {
440            ViewPropertyAnimatorCompatICS.x(view, value);
441        }
442
443        @Override
444        public void xBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
445            ViewPropertyAnimatorCompatICS.xBy(view, value);
446        }
447
448        @Override
449        public void y(ViewPropertyAnimatorCompat vpa, View view, float value) {
450            ViewPropertyAnimatorCompatICS.y(view, value);
451        }
452
453        @Override
454        public void yBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
455            ViewPropertyAnimatorCompatICS.yBy(view, value);
456        }
457
458        @Override
459        public void translationXBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
460            ViewPropertyAnimatorCompatICS.translationXBy(view, value);
461        }
462
463        @Override
464        public void translationYBy(ViewPropertyAnimatorCompat vpa, View view, float value) {
465            ViewPropertyAnimatorCompatICS.translationYBy(view, value);
466        }
467
468        @Override
469        public void start(ViewPropertyAnimatorCompat vpa, View view) {
470            ViewPropertyAnimatorCompatICS.start(view);
471        }
472
473        @Override
474        public void setListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorListener listener) {
475            view.setTag(LISTENER_TAG_ID, listener);
476            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
477        }
478
479        @Override
480        public void withEndAction(ViewPropertyAnimatorCompat vpa, View view, final Runnable runnable) {
481            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
482            vpa.mEndAction = runnable;
483        }
484
485        @Override
486        public void withStartAction(ViewPropertyAnimatorCompat vpa, View view, final Runnable runnable) {
487            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
488            vpa.mStartAction = runnable;
489        }
490
491        @Override
492        public void withLayer(ViewPropertyAnimatorCompat vpa, View view) {
493            vpa.mOldLayerType = ViewCompat.getLayerType(view);
494            ViewPropertyAnimatorCompatICS.setListener(view, new MyVpaListener(vpa));
495        }
496
497        static class MyVpaListener implements ViewPropertyAnimatorListener {
498
499            ViewPropertyAnimatorCompat mVpa;
500
501            MyVpaListener(ViewPropertyAnimatorCompat vpa) {
502                mVpa = vpa;
503            }
504
505            @Override
506            public void onAnimationStart(View view) {
507                if (mVpa.mOldLayerType >= 0) {
508                    ViewCompat.setLayerType(view, ViewCompat.LAYER_TYPE_HARDWARE, null);
509                }
510                if (mVpa.mStartAction != null) {
511                    mVpa.mStartAction.run();
512                }
513                Object listenerTag = view.getTag(LISTENER_TAG_ID);
514                ViewPropertyAnimatorListener listener = null;
515                if (listenerTag instanceof ViewPropertyAnimatorListener) {
516                    listener = (ViewPropertyAnimatorListener) listenerTag;
517                }
518                if (listener != null) {
519                    listener.onAnimationStart(view);
520                }
521            }
522
523            @Override
524            public void onAnimationEnd(View view) {
525                if (mVpa.mOldLayerType >= 0) {
526                    ViewCompat.setLayerType(view, mVpa.mOldLayerType, null);
527                    mVpa.mOldLayerType = -1;
528                }
529                if (mVpa.mEndAction != null) {
530                    mVpa.mEndAction.run();
531                }
532                Object listenerTag = view.getTag(LISTENER_TAG_ID);
533                ViewPropertyAnimatorListener listener = null;
534                if (listenerTag instanceof ViewPropertyAnimatorListener) {
535                    listener = (ViewPropertyAnimatorListener) listenerTag;
536                }
537                if (listener != null) {
538                    listener.onAnimationEnd(view);
539                }
540            }
541
542            @Override
543            public void onAnimationCancel(View view) {
544                Object listenerTag = view.getTag(LISTENER_TAG_ID);
545                ViewPropertyAnimatorListener listener = null;
546                if (listenerTag instanceof ViewPropertyAnimatorListener) {
547                    listener = (ViewPropertyAnimatorListener) listenerTag;
548                }
549                if (listener != null) {
550                    listener.onAnimationCancel(view);
551                }
552            }
553        };
554    }
555
556    static class JBViewPropertyAnimatorCompatImpl extends ICSViewPropertyAnimatorCompatImpl {
557
558        @Override
559        public void setListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorListener listener) {
560            ViewPropertyAnimatorCompatJB.setListener(view, listener);
561        }
562
563        @Override
564        public void withStartAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable) {
565            ViewPropertyAnimatorCompatJB.withStartAction(view, runnable);
566        }
567
568        @Override
569        public void withEndAction(ViewPropertyAnimatorCompat vpa, View view, Runnable runnable) {
570            ViewPropertyAnimatorCompatJB.withEndAction(view, runnable);
571        }
572
573        @Override
574        public void withLayer(ViewPropertyAnimatorCompat vpa, View view) {
575            ViewPropertyAnimatorCompatJB.withLayer(view);
576        }
577    }
578
579    static class JBMr2ViewPropertyAnimatorCompatImpl extends JBViewPropertyAnimatorCompatImpl {
580
581        @Override
582        public Interpolator getInterpolator(ViewPropertyAnimatorCompat vpa, View view) {
583            return (Interpolator) ViewPropertyAnimatorCompatJellybeanMr2.getInterpolator(view);
584        }
585    }
586
587    static class KitKatViewPropertyAnimatorCompatImpl extends JBMr2ViewPropertyAnimatorCompatImpl {
588        @Override
589        public void setUpdateListener(ViewPropertyAnimatorCompat vpa, View view, ViewPropertyAnimatorUpdateListener listener) {
590            ViewPropertyAnimatorCompatKK.setUpdateListener(view, listener);
591        }
592    }
593
594    static final ViewPropertyAnimatorCompatImpl IMPL;
595    static {
596        final int version = android.os.Build.VERSION.SDK_INT;
597        if (version >= 19) {
598            IMPL = new KitKatViewPropertyAnimatorCompatImpl();
599        } else if (version >= 18) {
600            IMPL = new JBMr2ViewPropertyAnimatorCompatImpl();
601        } else if (version >= 16) {
602            IMPL = new JBViewPropertyAnimatorCompatImpl();
603        } else if (version >= 14) {
604            IMPL = new ICSViewPropertyAnimatorCompatImpl();
605        } else {
606            IMPL = new BaseViewPropertyAnimatorCompatImpl();
607        }
608    }
609
610    /**
611     * Sets the duration for the underlying animator that animates the requested properties.
612     * By default, the animator uses the default value for ValueAnimator. Calling this method
613     * will cause the declared value to be used instead.
614     *
615     * <p>Prior to API 14, this method will do nothing.</p>
616     *
617     * @param value The length of ensuing property animations, in milliseconds. The value
618     * cannot be negative.
619     * @return This object, allowing calls to methods in this class to be chained.
620     */
621    public ViewPropertyAnimatorCompat setDuration(long value) {
622        View view;
623        if ((view = mView.get()) != null) {
624            IMPL.setDuration(this, view, value);
625        }
626        return this;
627    }
628
629    /**
630     * This method will cause the View's <code>alpha</code> property to be animated to the
631     * specified value. Animations already running on the property will be canceled.
632     *
633     * <p>Prior to API 14, this method will do nothing.</p>
634     *
635     * @param value The value to be animated to.
636     * @return This object, allowing calls to methods in this class to be chained.
637     */
638    public ViewPropertyAnimatorCompat alpha(float value) {
639        View view;
640        if ((view = mView.get()) != null) {
641            IMPL.alpha(this, view, value);
642        }
643        return this;
644    }
645
646    /**
647     * This method will cause the View's <code>alpha</code> property to be animated by the
648     * specified value. Animations already running on the property will be canceled.
649     *
650     * <p>Prior to API 14, this method will do nothing.</p>
651     *
652     * @param value The amount to be animated by, as an offset from the current value.
653     * @return This object, allowing calls to methods in this class to be chained.
654     */
655    public ViewPropertyAnimatorCompat alphaBy(float value) {
656        View view;
657        if ((view = mView.get()) != null) {
658            IMPL.alphaBy(this, view, value);
659        }
660        return this;
661    }
662
663    /**
664     * This method will cause the View's <code>translationX</code> property to be animated to the
665     * specified value. Animations already running on the property will be canceled.
666     *
667     * <p>Prior to API 14, this method will do nothing.</p>
668     *
669     * @param value The value to be animated to.
670     * @return This object, allowing calls to methods in this class to be chained.
671     */
672    public ViewPropertyAnimatorCompat translationX(float value) {
673        View view;
674        if ((view = mView.get()) != null) {
675            IMPL.translationX(this, view, value);
676        }
677        return this;
678    }
679
680    /**
681     * This method will cause the View's <code>translationY</code> property to be animated to the
682     * specified value. Animations already running on the property will be canceled.
683     *
684     * <p>Prior to API 14, this method will do nothing.</p>
685     *
686     * @param value The value to be animated to.
687     * @return This object, allowing calls to methods in this class to be chained.
688     */
689    public ViewPropertyAnimatorCompat translationY(float value) {
690        View view;
691        if ((view = mView.get()) != null) {
692            IMPL.translationY(this, view, value);
693        }
694        return this;
695    }
696
697    /**
698     * Specifies an action to take place when the next animation ends. The action is only
699     * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
700     * that animation, the runnable will not run.
701     * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
702     * choreographing ViewPropertyAnimator animations with other animations or actions
703     * in the application.
704     *
705     * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
706     * <pre>
707     *     Runnable endAction = new Runnable() {
708     *         public void run() {
709     *             view.animate().x(0);
710     *         }
711     *     };
712     *     view.animate().x(200).withEndAction(endAction);
713     * </pre>
714     *
715     * <p>Prior to API 14, this method will run the action immediately.</p>
716     *
717     * <p>For API 14 and 15, this method will run by setting
718     * a listener on the ViewPropertyAnimatorCompat object and running the action
719     * in that listener's {@link ViewPropertyAnimatorListener#onAnimationEnd(View)} method.</p>
720     *
721     * @param runnable The action to run when the next animation ends.
722     * @return This object, allowing calls to methods in this class to be chained.
723     */
724    public ViewPropertyAnimatorCompat withEndAction(Runnable runnable) {
725        View view;
726        if ((view = mView.get()) != null) {
727            IMPL.withEndAction(this, view, runnable);
728        }
729        return this;
730    }
731
732    /**
733     * Returns the current duration of property animations. If the duration was set on this
734     * object, that value is returned. Otherwise, the default value of the underlying Animator
735     * is returned.
736     *
737     * <p>Prior to API 14, this method will return 0.</p>
738     *
739     * @see #setDuration(long)
740     * @return The duration of animations, in milliseconds.
741     */
742    public long getDuration() {
743        View view;
744        if ((view = mView.get()) != null) {
745            return IMPL.getDuration(this, view);
746        } else {
747            return 0;
748        }
749    }
750
751    /**
752     * Sets the interpolator for the underlying animator that animates the requested properties.
753     * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
754     * will cause the declared object to be used instead.
755     *
756     * <p>Prior to API 14, this method will do nothing.</p>
757     *
758     * @param value The TimeInterpolator to be used for ensuing property animations.
759     * @return This object, allowing calls to methods in this class to be chained.
760     */
761    public ViewPropertyAnimatorCompat setInterpolator(Interpolator value) {
762        View view;
763        if ((view = mView.get()) != null) {
764            IMPL.setInterpolator(this, view, value);
765        }
766        return this;
767    }
768
769    /**
770     * Returns the timing interpolator that this animation uses.
771     *
772     * <p>Prior to API 14, this method will return null.</p>
773     *
774     * @return The timing interpolator for this animation.
775     */
776    public Interpolator getInterpolator() {
777        View view;
778        if ((view = mView.get()) != null) {
779            return IMPL.getInterpolator(this, view);
780        }
781        else return null;
782    }
783
784    /**
785     * Sets the startDelay for the underlying animator that animates the requested properties.
786     * By default, the animator uses the default value for ValueAnimator. Calling this method
787     * will cause the declared value to be used instead.
788     *
789     * <p>Prior to API 14, this method will do nothing.</p>
790     *
791     * @param value The delay of ensuing property animations, in milliseconds. The value
792     * cannot be negative.
793     * @return This object, allowing calls to methods in this class to be chained.
794     */
795    public ViewPropertyAnimatorCompat setStartDelay(long value) {
796        View view;
797        if ((view = mView.get()) != null) {
798            IMPL.setStartDelay(this, view, value);
799        }
800        return this;
801    }
802
803    /**
804     * Returns the current startDelay of property animations. If the startDelay was set on this
805     * object, that value is returned. Otherwise, the default value of the underlying Animator
806     * is returned.
807     *
808     * <p>Prior to API 14, this method will return 0.</p>
809     *
810     * @see #setStartDelay(long)
811     * @return The startDelay of animations, in milliseconds.
812     */
813    public long getStartDelay() {
814        View view;
815        if ((view = mView.get()) != null) {
816            return IMPL.getStartDelay(this, view);
817        } else {
818            return 0;
819        }
820    }
821
822    /**
823     * This method will cause the View's <code>rotation</code> property to be animated to the
824     * specified value. Animations already running on the property will be canceled.
825     *
826     * <p>Prior to API 14, this method will do nothing.</p>
827     *
828     * @param value The value to be animated to.
829     * @return This object, allowing calls to methods in this class to be chained.
830     */
831    public ViewPropertyAnimatorCompat rotation(float value) {
832        View view;
833        if ((view = mView.get()) != null) {
834            IMPL.rotation(this, view, value);
835        }
836        return this;
837    }
838
839    /**
840     * This method will cause the View's <code>rotation</code> property to be animated by the
841     * specified value. Animations already running on the property will be canceled.
842     *
843     * <p>Prior to API 14, this method will do nothing.</p>
844     *
845     * @param value The amount to be animated by, as an offset from the current value.
846     * @return This object, allowing calls to methods in this class to be chained.
847     */
848    public ViewPropertyAnimatorCompat rotationBy(float value) {
849        View view;
850        if ((view = mView.get()) != null) {
851            IMPL.rotationBy(this, view, value);
852        }
853        return this;
854    }
855
856    /**
857     * This method will cause the View's <code>rotationX</code> property to be animated to the
858     * specified value. Animations already running on the property will be canceled.
859     *
860     * <p>Prior to API 14, this method will do nothing.</p>
861     *
862     * @param value The value to be animated to.
863     * @return This object, allowing calls to methods in this class to be chained.
864     */
865    public ViewPropertyAnimatorCompat rotationX(float value) {
866        View view;
867        if ((view = mView.get()) != null) {
868            IMPL.rotationX(this, view, value);
869        }
870        return this;
871    }
872
873    /**
874     * This method will cause the View's <code>rotationX</code> property to be animated by the
875     * specified value. Animations already running on the property will be canceled.
876     *
877     * <p>Prior to API 14, this method will do nothing.</p>
878     *
879     * @param value The amount to be animated by, as an offset from the current value.
880     * @return This object, allowing calls to methods in this class to be chained.
881     */
882    public ViewPropertyAnimatorCompat rotationXBy(float value) {
883        View view;
884        if ((view = mView.get()) != null) {
885            IMPL.rotationXBy(this, view, value);
886        }
887        return this;
888    }
889
890    /**
891     * This method will cause the View's <code>rotationY</code> property to be animated to the
892     * specified value. Animations already running on the property will be canceled.
893     *
894     * <p>Prior to API 14, this method will do nothing.</p>
895     *
896     * @param value The value to be animated to.
897     * @return This object, allowing calls to methods in this class to be chained.
898     */
899    public ViewPropertyAnimatorCompat rotationY(float value) {
900        View view;
901        if ((view = mView.get()) != null) {
902            IMPL.rotationY(this, view, value);
903        }
904        return this;
905    }
906
907    /**
908     * This method will cause the View's <code>rotationY</code> property to be animated by the
909     * specified value. Animations already running on the property will be canceled.
910     *
911     * <p>Prior to API 14, this method will do nothing.</p>
912     *
913     * @param value The amount to be animated by, as an offset from the current value.
914     * @return This object, allowing calls to methods in this class to be chained.
915     */
916    public ViewPropertyAnimatorCompat rotationYBy(float value) {
917        View view;
918        if ((view = mView.get()) != null) {
919            IMPL.rotationYBy(this, view, value);
920        }
921        return this;
922    }
923
924    /**
925     * This method will cause the View's <code>scaleX</code> property to be animated to the
926     * specified value. Animations already running on the property will be canceled.
927     *
928     * <p>Prior to API 14, this method will do nothing.</p>
929     *
930     * @param value The value to be animated to.
931     * @return This object, allowing calls to methods in this class to be chained.
932     */
933    public ViewPropertyAnimatorCompat scaleX(float value) {
934        View view;
935        if ((view = mView.get()) != null) {
936            IMPL.scaleX(this, view, value);
937        }
938        return this;
939    }
940
941    /**
942     * This method will cause the View's <code>scaleX</code> property to be animated by the
943     * specified value. Animations already running on the property will be canceled.
944     *
945     * <p>Prior to API 14, this method will do nothing.</p>
946     *
947     * @param value The amount to be animated by, as an offset from the current value.
948     * @return This object, allowing calls to methods in this class to be chained.
949     */
950    public ViewPropertyAnimatorCompat scaleXBy(float value) {
951        View view;
952        if ((view = mView.get()) != null) {
953            IMPL.scaleXBy(this, view, value);
954        }
955        return this;
956    }
957
958    /**
959     * This method will cause the View's <code>scaleY</code> property to be animated to the
960     * specified value. Animations already running on the property will be canceled.
961     *
962     * <p>Prior to API 14, this method will do nothing.</p>
963     *
964     * @param value The value to be animated to.
965     * @return This object, allowing calls to methods in this class to be chained.
966     */
967    public ViewPropertyAnimatorCompat scaleY(float value) {
968        View view;
969        if ((view = mView.get()) != null) {
970            IMPL.scaleY(this, view, value);
971        }
972        return this;
973    }
974
975    /**
976     * This method will cause the View's <code>scaleY</code> property to be animated by the
977     * specified value. Animations already running on the property will be canceled.
978     *
979     * <p>Prior to API 14, this method will do nothing.</p>
980     *
981     * @param value The amount to be animated by, as an offset from the current value.
982     * @return This object, allowing calls to methods in this class to be chained.
983     */
984    public ViewPropertyAnimatorCompat scaleYBy(float value) {
985        View view;
986        if ((view = mView.get()) != null) {
987            IMPL.scaleYBy(this, view, value);
988        }
989        return this;
990    }
991
992    /**
993     * Cancels all property animations that are currently running or pending.
994     */
995    public void cancel() {
996        View view;
997        if ((view = mView.get()) != null) {
998            IMPL.cancel(this, view);
999        }
1000    }
1001
1002    /**
1003     * This method will cause the View's <code>x</code> property to be animated to the
1004     * specified value. Animations already running on the property will be canceled.
1005     *
1006     * <p>Prior to API 14, this method will do nothing.</p>
1007     *
1008     * @param value The value to be animated to.
1009     * @return This object, allowing calls to methods in this class to be chained.
1010     */
1011    public ViewPropertyAnimatorCompat x(float value) {
1012        View view;
1013        if ((view = mView.get()) != null) {
1014            IMPL.x(this, view, value);
1015        }
1016        return this;
1017    }
1018
1019    /**
1020     * This method will cause the View's <code>x</code> property to be animated by the
1021     * specified value. Animations already running on the property will be canceled.
1022     *
1023     * <p>Prior to API 14, this method will do nothing.</p>
1024     *
1025     * @param value The amount to be animated by, as an offset from the current value.
1026     * @return This object, allowing calls to methods in this class to be chained.
1027     */
1028    public ViewPropertyAnimatorCompat xBy(float value) {
1029        View view;
1030        if ((view = mView.get()) != null) {
1031            IMPL.xBy(this, view, value);
1032        }
1033        return this;
1034    }
1035
1036    /**
1037     * This method will cause the View's <code>y</code> property to be animated to the
1038     * specified value. Animations already running on the property will be canceled.
1039     *
1040     * <p>Prior to API 14, this method will do nothing.</p>
1041     *
1042     * @param value The value to be animated to.
1043     * @return This object, allowing calls to methods in this class to be chained.
1044     */
1045    public ViewPropertyAnimatorCompat y(float value) {
1046        View view;
1047        if ((view = mView.get()) != null) {
1048            IMPL.y(this, view, value);
1049        }
1050        return this;
1051    }
1052
1053    /**
1054     * This method will cause the View's <code>y</code> property to be animated by the
1055     * specified value. Animations already running on the property will be canceled.
1056     *
1057     * <p>Prior to API 14, this method will do nothing.</p>
1058     *
1059     * @param value The amount to be animated by, as an offset from the current value.
1060     * @return This object, allowing calls to methods in this class to be chained.
1061     */
1062    public ViewPropertyAnimatorCompat yBy(float value) {
1063        View view;
1064        if ((view = mView.get()) != null) {
1065            IMPL.yBy(this, view, value);
1066        }
1067        return this;
1068    }
1069
1070    /**
1071     * This method will cause the View's <code>translationX</code> property to be animated by the
1072     * specified value. Animations already running on the property will be canceled.
1073     *
1074     * <p>Prior to API 14, this method will do nothing.</p>
1075     *
1076     * @param value The amount to be animated by, as an offset from the current value.
1077     * @return This object, allowing calls to methods in this class to be chained.
1078     */
1079    public ViewPropertyAnimatorCompat translationXBy(float value) {
1080        View view;
1081        if ((view = mView.get()) != null) {
1082            IMPL.translationXBy(this, view, value);
1083        }
1084        return this;
1085    }
1086
1087    /**
1088     * This method will cause the View's <code>translationY</code> property to be animated by the
1089     * specified value. Animations already running on the property will be canceled.
1090     *
1091     * <p>Prior to API 14, this method will do nothing.</p>
1092     *
1093     * @param value The amount to be animated by, as an offset from the current value.
1094     * @return This object, allowing calls to methods in this class to be chained.
1095     */
1096    public ViewPropertyAnimatorCompat translationYBy(float value) {
1097        View view;
1098        if ((view = mView.get()) != null) {
1099            IMPL.translationYBy(this, view, value);
1100        }
1101        return this;
1102    }
1103
1104    /**
1105     * Starts the currently pending property animations immediately. Calling <code>start()</code>
1106     * is optional because all animations start automatically at the next opportunity. However,
1107     * if the animations are needed to start immediately and synchronously (not at the time when
1108     * the next event is processed by the hierarchy, which is when the animations would begin
1109     * otherwise), then this method can be used.
1110     *
1111     * <p>Prior to API 14, this method will do nothing.</p>
1112     */
1113    public void start() {
1114        View view;
1115        if ((view = mView.get()) != null) {
1116            IMPL.start(this, view);
1117        }
1118    }
1119
1120    /**
1121     * The View associated with this ViewPropertyAnimator will have its
1122     * {@link ViewCompat#setLayerType(View, int, android.graphics.Paint) layer type} set to
1123     * {@link ViewCompat#LAYER_TYPE_HARDWARE} for the duration of the next animation.
1124     * As stated in the documentation for {@link ViewCompat#LAYER_TYPE_HARDWARE},
1125     * the actual type of layer used internally depends on the runtime situation of the
1126     * view. If the activity and this view are hardware-accelerated, then the layer will be
1127     * accelerated as well. If the activity or the view is not accelerated, then the layer will
1128     * effectively be the same as {@link ViewCompat#LAYER_TYPE_SOFTWARE}.
1129     *
1130     * <p>This state is not persistent, either on the View or on this ViewPropertyAnimator: the
1131     * layer type of the View will be restored when the animation ends to what it was when this
1132     * method was called, and this setting on ViewPropertyAnimator is only valid for the next
1133     * animation. Note that calling this method and then independently setting the layer type of
1134     * the View (by a direct call to
1135     * {@link ViewCompat#setLayerType(View, int, android.graphics.Paint)}) will result in some
1136     * inconsistency, including having the layer type restored to its pre-withLayer()
1137     * value when the animation ends.</p>
1138     *
1139     * <p>Prior to API 14, this method will do nothing.</p>
1140     *
1141     * <p>For API 14 and 15, this method will run by setting
1142     * a listener on the ViewPropertyAnimatorCompat object, setting a hardware layer in
1143     * the listener's {@link ViewPropertyAnimatorListener#onAnimationStart(View)} method,
1144     * and then restoring the orignal layer type in the listener's
1145     * {@link ViewPropertyAnimatorListener#onAnimationEnd(View)} method.</p>
1146     *
1147     * @see View#setLayerType(int, android.graphics.Paint)
1148     * @return This object, allowing calls to methods in this class to be chained.
1149     */
1150    public ViewPropertyAnimatorCompat withLayer() {
1151        View view;
1152        if ((view = mView.get()) != null) {
1153            IMPL.withLayer(this, view);
1154        }
1155        return this;
1156    }
1157
1158    /**
1159     * Specifies an action to take place when the next animation runs. If there is a
1160     * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
1161     * action will run after that startDelay expires, when the actual animation begins.
1162     * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
1163     * choreographing ViewPropertyAnimator animations with other animations or actions
1164     * in the application.
1165     *
1166     * <p>Prior to API 14, this method will run the action immediately.</p>
1167     *
1168     * <p>For API 14 and 15, this method will run by setting
1169     * a listener on the ViewPropertyAnimatorCompat object and running the action
1170     * in that listener's {@link ViewPropertyAnimatorListener#onAnimationStart(View)} method.</p>
1171     *
1172     * @param runnable The action to run when the next animation starts.
1173     * @return This object, allowing calls to methods in this class to be chained.
1174     */
1175    public ViewPropertyAnimatorCompat withStartAction(Runnable runnable) {
1176        View view;
1177        if ((view = mView.get()) != null) {
1178            IMPL.withStartAction(this, view, runnable);
1179        }
1180        return this;
1181    }
1182
1183    /**
1184     * Sets a listener for events in the underlying Animators that run the property
1185     * animations.
1186     *
1187     * <p>Prior to API 14, this method will do nothing.</p>
1188     *
1189     * @param listener The listener to be called with AnimatorListener events. A value of
1190     * <code>null</code> removes any existing listener.
1191     * @return This object, allowing calls to methods in this class to be chained.
1192     */
1193    public ViewPropertyAnimatorCompat setListener(ViewPropertyAnimatorListener listener) {
1194        View view;
1195        if ((view = mView.get()) != null) {
1196            IMPL.setListener(this, view, listener);
1197        }
1198        return this;
1199    }
1200
1201    /**
1202     * Sets a listener for update events in the underlying Animator that runs
1203     * the property animations.
1204     *
1205     * <p>Prior to API 19, this method will do nothing.</p>
1206     *
1207     * @param listener The listener to be called with update events. A value of
1208     * <code>null</code> removes any existing listener.
1209     * @return This object, allowing calls to methods in this class to be chained.
1210     */
1211    public ViewPropertyAnimatorCompat setUpdateListener(
1212            ViewPropertyAnimatorUpdateListener listener) {
1213        View view;
1214        if ((view = mView.get()) != null) {
1215            IMPL.setUpdateListener(this, view, listener);
1216        }
1217        return this;
1218    }
1219}
1220