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