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