1/*
2 * Copyright (C) 2012 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.launcher3;
18
19import android.animation.Animator;
20import android.animation.AnimatorSet;
21import android.animation.ObjectAnimator;
22import android.animation.PropertyValuesHolder;
23import android.animation.ValueAnimator;
24import android.annotation.TargetApi;
25import android.os.Build;
26import android.view.View;
27import android.view.ViewAnimationUtils;
28import android.view.ViewTreeObserver;
29
30import com.android.launcher3.util.UiThreadCircularReveal;
31
32import java.util.HashSet;
33import java.util.WeakHashMap;
34
35public class LauncherAnimUtils {
36    static WeakHashMap<Animator, Object> sAnimators = new WeakHashMap<Animator, Object>();
37    static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() {
38        public void onAnimationStart(Animator animation) {
39            sAnimators.put(animation, null);
40        }
41
42        public void onAnimationRepeat(Animator animation) {
43        }
44
45        public void onAnimationEnd(Animator animation) {
46            sAnimators.remove(animation);
47        }
48
49        public void onAnimationCancel(Animator animation) {
50            sAnimators.remove(animation);
51        }
52    };
53
54    public static void cancelOnDestroyActivity(Animator a) {
55        a.addListener(sEndAnimListener);
56    }
57
58    // Helper method. Assumes a draw is pending, and that if the animation's duration is 0
59    // it should be cancelled
60    public static void startAnimationAfterNextDraw(final Animator animator, final View view) {
61        view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
62                private boolean mStarted = false;
63                public void onDraw() {
64                    if (mStarted) return;
65                    mStarted = true;
66                    // Use this as a signal that the animation was cancelled
67                    if (animator.getDuration() == 0) {
68                        return;
69                    }
70                    animator.start();
71
72                    final ViewTreeObserver.OnDrawListener listener = this;
73                    view.post(new Runnable() {
74                            public void run() {
75                                view.getViewTreeObserver().removeOnDrawListener(listener);
76                            }
77                        });
78                }
79            });
80    }
81
82    public static void onDestroyActivity() {
83        HashSet<Animator> animators = new HashSet<Animator>(sAnimators.keySet());
84        for (Animator a : animators) {
85            if (a.isRunning()) {
86                a.cancel();
87            }
88            sAnimators.remove(a);
89        }
90    }
91
92    public static AnimatorSet createAnimatorSet() {
93        AnimatorSet anim = new AnimatorSet();
94        cancelOnDestroyActivity(anim);
95        return anim;
96    }
97
98    public static ValueAnimator ofFloat(View target, float... values) {
99        ValueAnimator anim = new ValueAnimator();
100        anim.setFloatValues(values);
101        cancelOnDestroyActivity(anim);
102        return anim;
103    }
104
105    public static ObjectAnimator ofFloat(View target, String propertyName, float... values) {
106        ObjectAnimator anim = new ObjectAnimator();
107        anim.setTarget(target);
108        anim.setPropertyName(propertyName);
109        anim.setFloatValues(values);
110        cancelOnDestroyActivity(anim);
111        new FirstFrameAnimatorHelper(anim, target);
112        return anim;
113    }
114
115    public static ObjectAnimator ofPropertyValuesHolder(View target,
116            PropertyValuesHolder... values) {
117        ObjectAnimator anim = new ObjectAnimator();
118        anim.setTarget(target);
119        anim.setValues(values);
120        cancelOnDestroyActivity(anim);
121        new FirstFrameAnimatorHelper(anim, target);
122        return anim;
123    }
124
125    public static ObjectAnimator ofPropertyValuesHolder(Object target,
126            View view, PropertyValuesHolder... values) {
127        ObjectAnimator anim = new ObjectAnimator();
128        anim.setTarget(target);
129        anim.setValues(values);
130        cancelOnDestroyActivity(anim);
131        new FirstFrameAnimatorHelper(anim, view);
132        return anim;
133    }
134
135    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
136    public static ValueAnimator createCircularReveal(View view, int centerX,
137            int centerY, float startRadius, float endRadius) {
138        ValueAnimator anim = UiThreadCircularReveal.createCircularReveal(view, centerX,
139                centerY, startRadius, endRadius);
140        new FirstFrameAnimatorHelper(anim, view);
141        return anim;
142    }
143}
144