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 
17 package com.android.deskclock;
18 
19 import android.animation.ArgbEvaluator;
20 import android.animation.ObjectAnimator;
21 import android.animation.PropertyValuesHolder;
22 import android.animation.ValueAnimator;
23 import android.graphics.drawable.Drawable;
24 import android.support.v4.graphics.drawable.DrawableCompat;
25 import android.util.Property;
26 import android.view.View;
27 import android.view.animation.Interpolator;
28 import android.widget.ImageView;
29 
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 
33 public class AnimatorUtils {
34 
35     public static final long ANIM_DURATION_SHORT = 266L;  // 8/30 frames long
36 
37     public static final Interpolator DECELERATE_ACCELERATE_INTERPOLATOR = new Interpolator() {
38         @Override
39         public float getInterpolation(float x) {
40             return 0.5f + 4.0f * (x - 0.5f) * (x - 0.5f) * (x - 0.5f);
41         }
42     };
43 
44     public static final Property<View, Integer> BACKGROUND_ALPHA =
45             new Property<View, Integer>(Integer.class, "background.alpha") {
46         @Override
47         public Integer get(View view) {
48             return view.getBackground().getAlpha();
49         }
50 
51         @Override
52         public void set(View view, Integer value) {
53             view.getBackground().setAlpha(value);
54         }
55     };
56 
57     public static final Property<ImageView, Integer> DRAWABLE_ALPHA =
58             new Property<ImageView, Integer>(Integer.class, "drawable.alpha") {
59         @Override
60         public Integer get(ImageView view) {
61             return view.getDrawable().getAlpha();
62         }
63 
64         @Override
65         public void set(ImageView view, Integer value) {
66             view.getDrawable().setAlpha(value);
67         }
68     };
69 
70     public static final Property<ImageView, Integer> DRAWABLE_TINT =
71             new Property<ImageView, Integer>(Integer.class, "drawable.tint") {
72         @Override
73         public Integer get(ImageView view) {
74             return null;
75         }
76 
77         @Override
78         public void set(ImageView view, Integer value) {
79             // Ensure the drawable is wrapped using DrawableCompat.
80             final Drawable drawable = view.getDrawable();
81             final Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
82             if (wrappedDrawable != drawable) {
83                 view.setImageDrawable(wrappedDrawable);
84             }
85             // Set the new tint value via DrawableCompat.
86             DrawableCompat.setTint(wrappedDrawable, value);
87         }
88     };
89 
90     public static final ArgbEvaluator ARGB_EVALUATOR = new ArgbEvaluator();
91 
92     private static Method sAnimateValue;
93     private static boolean sTryAnimateValue = true;
94 
setAnimatedFraction(ValueAnimator animator, float fraction)95     public static void setAnimatedFraction(ValueAnimator animator, float fraction) {
96         if (Utils.isLMR1OrLater()) {
97             animator.setCurrentFraction(fraction);
98             return;
99         }
100 
101         if (sTryAnimateValue) {
102             // try to set the animated fraction directly so that it isn't affected by the
103             // internal animator scale or time (b/17938711)
104             try {
105                 if (sAnimateValue == null) {
106                     sAnimateValue = ValueAnimator.class
107                             .getDeclaredMethod("animateValue", float.class);
108                     sAnimateValue.setAccessible(true);
109                 }
110 
111                 sAnimateValue.invoke(animator, fraction);
112                 return;
113             } catch (NoSuchMethodException | InvocationTargetException
114                     | IllegalAccessException e) {
115                 // something went wrong, don't try that again
116                 LogUtils.e("Unable to use animateValue directly", e);
117                 sTryAnimateValue = false;
118             }
119         }
120 
121         // if that doesn't work then just fall back to setting the current play time
122         animator.setCurrentPlayTime(Math.round(fraction * animator.getDuration()));
123     }
124 
reverse(ValueAnimator... animators)125     public static void reverse(ValueAnimator... animators) {
126         for (ValueAnimator animator : animators) {
127             final float fraction = animator.getAnimatedFraction();
128             if (fraction > 0.0f) {
129                 animator.reverse();
130                 setAnimatedFraction(animator, 1.0f - fraction);
131             }
132         }
133     }
134 
cancel(ValueAnimator... animators)135     public static void cancel(ValueAnimator... animators) {
136         for (ValueAnimator animator : animators) {
137             animator.cancel();
138         }
139     }
140 
getScaleAnimator(View view, float... values)141     public static ValueAnimator getScaleAnimator(View view, float... values) {
142         return ObjectAnimator.ofPropertyValuesHolder(view,
143                 PropertyValuesHolder.ofFloat(View.SCALE_X, values),
144                 PropertyValuesHolder.ofFloat(View.SCALE_Y, values));
145     }
146 }
147