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.phone.common.animation;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ValueAnimator;
22import android.view.View;
23import android.view.ViewPropertyAnimator;
24import android.view.animation.Interpolator;
25import android.view.animation.PathInterpolator;
26
27import java.lang.Float;
28
29public class AnimUtils {
30    public static final int DEFAULT_DURATION = -1;
31    public static final int NO_DELAY = 0;
32
33    public static final Interpolator EASE_IN = new PathInterpolator(0.0f, 0.0f, 0.2f, 1.0f);
34    public static final Interpolator EASE_OUT = new PathInterpolator(0.4f, 0.0f, 1.0f, 1.0f);
35    public static final Interpolator EASE_OUT_EASE_IN = new PathInterpolator(0.4f, 0, 0.2f, 1);
36
37    public static class AnimationCallback {
38        public void onAnimationEnd() {}
39        public void onAnimationCancel() {}
40    }
41
42    public static void crossFadeViews(View fadeIn, View fadeOut, int duration) {
43        fadeIn(fadeIn, duration);
44        fadeOut(fadeOut, duration);
45    }
46
47    public static void fadeOut(View fadeOut, int duration) {
48        fadeOut(fadeOut, duration, null);
49    }
50
51    public static void fadeOut(final View fadeOut, int durationMs,
52            final AnimationCallback callback) {
53        fadeOut.setAlpha(1);
54        final ViewPropertyAnimator animator = fadeOut.animate();
55        animator.cancel();
56        animator.alpha(0).withLayer().setListener(new AnimatorListenerAdapter() {
57            @Override
58            public void onAnimationEnd(Animator animation) {
59                fadeOut.setVisibility(View.GONE);
60                if (callback != null) {
61                    callback.onAnimationEnd();
62                }
63            }
64
65            @Override
66            public void onAnimationCancel(Animator animation) {
67                fadeOut.setVisibility(View.GONE);
68                fadeOut.setAlpha(0);
69                if (callback != null) {
70                    callback.onAnimationCancel();
71                }
72            }
73        });
74        if (durationMs != DEFAULT_DURATION) {
75            animator.setDuration(durationMs);
76        }
77        animator.start();
78    }
79
80    public static void fadeIn(View fadeIn, int durationMs) {
81        fadeIn(fadeIn, durationMs, NO_DELAY, null);
82    }
83
84    public static void fadeIn(final View fadeIn, int durationMs, int delay,
85            final AnimationCallback callback) {
86        fadeIn.setAlpha(0);
87        final ViewPropertyAnimator animator = fadeIn.animate();
88        animator.cancel();
89
90        animator.setStartDelay(delay);
91        animator.alpha(1).withLayer().setListener(new AnimatorListenerAdapter() {
92            @Override
93            public void onAnimationStart(Animator animation) {
94                fadeIn.setVisibility(View.VISIBLE);
95            }
96
97            @Override
98            public void onAnimationCancel(Animator animation) {
99                fadeIn.setAlpha(1);
100                if (callback != null) {
101                    callback.onAnimationCancel();
102                }
103            }
104
105            @Override
106            public void onAnimationEnd(Animator animation) {
107                if (callback != null) {
108                    callback.onAnimationEnd();
109                }
110            }
111        });
112        if (durationMs != DEFAULT_DURATION) {
113            animator.setDuration(durationMs);
114        }
115        animator.start();
116    }
117
118    /**
119     * Scales in the view from scale of 0 to actual dimensions.
120     * @param view The view to scale.
121     * @param durationMs The duration of the scaling in milliseconds.
122     * @param startDelayMs The delay to applying the scaling in milliseconds.
123     */
124    public static void scaleIn(final View view, int durationMs, int startDelayMs) {
125        AnimatorListenerAdapter listener = (new AnimatorListenerAdapter() {
126            @Override
127            public void onAnimationStart(Animator animation) {
128                view.setVisibility(View.VISIBLE);
129            }
130
131            @Override
132            public void onAnimationCancel(Animator animation) {
133                view.setScaleX(1);
134                view.setScaleY(1);
135            }
136        });
137        scaleInternal(view, 0 /* startScaleValue */, 1 /* endScaleValue */, durationMs,
138                startDelayMs, listener, EASE_IN);
139    }
140
141
142    /**
143     * Scales out the view from actual dimensions to 0.
144     * @param view The view to scale.
145     * @param durationMs The duration of the scaling in milliseconds.
146     */
147    public static void scaleOut(final View view, int durationMs) {
148        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
149            @Override
150            public void onAnimationEnd(Animator animation) {
151                view.setVisibility(View.GONE);
152            }
153
154            @Override
155            public void onAnimationCancel(Animator animation) {
156                view.setVisibility(View.GONE);
157                view.setScaleX(0);
158                view.setScaleY(0);
159            }
160        };
161
162        scaleInternal(view, 1 /* startScaleValue */, 0 /* endScaleValue */, durationMs,
163                NO_DELAY, listener, EASE_OUT);
164    }
165
166    private static void scaleInternal(final View view, int startScaleValue, int endScaleValue,
167            int durationMs, int startDelay, AnimatorListenerAdapter listener,
168            Interpolator interpolator) {
169        view.setScaleX(startScaleValue);
170        view.setScaleY(startScaleValue);
171
172        final ViewPropertyAnimator animator = view.animate();
173        animator.cancel();
174
175        animator.setInterpolator(interpolator)
176            .scaleX(endScaleValue)
177            .scaleY(endScaleValue)
178            .setListener(listener)
179            .withLayer();
180
181        if (durationMs != DEFAULT_DURATION) {
182            animator.setDuration(durationMs);
183        }
184        animator.setStartDelay(startDelay);
185
186        animator.start();
187    }
188
189    /**
190     * Animates a view to the new specified dimensions.
191     * @param view The view to change the dimensions of.
192     * @param newWidth The new width of the view.
193     * @param newHeight The new height of the view.
194     */
195    public static void changeDimensions(final View view, final int newWidth, final int newHeight) {
196        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
197
198        final int oldWidth = view.getWidth();
199        final int oldHeight = view.getHeight();
200        final int deltaWidth = newWidth - oldWidth;
201        final int deltaHeight = newHeight - oldHeight;
202
203        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
204            @Override
205            public void onAnimationUpdate(ValueAnimator animator) {
206                Float value = (Float) animator.getAnimatedValue();
207
208                view.getLayoutParams().width = (int) (value * deltaWidth + oldWidth);
209                view.getLayoutParams().height = (int) (value * deltaHeight + oldHeight);
210                view.requestLayout();
211            }
212        });
213        animator.start();
214    }
215}
216