1 /*
2  * Copyright (C) 2016 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.systemui.statusbar;
18 
19 import android.view.View;
20 
21 import com.android.systemui.Interpolators;
22 import com.android.systemui.statusbar.stack.StackStateAnimator;
23 
24 /**
25  * A helper to fade views in and out.
26  */
27 public class CrossFadeHelper {
28     public static final long ANIMATION_DURATION_LENGTH = 210;
29 
fadeOut(final View view, final Runnable endRunnable)30     public static void fadeOut(final View view, final Runnable endRunnable) {
31         fadeOut(view, ANIMATION_DURATION_LENGTH, 0, endRunnable);
32     }
33 
fadeOut(final View view, long duration, int delay, final Runnable endRunnable)34     public static void fadeOut(final View view, long duration, int delay,
35             final Runnable endRunnable) {
36         view.animate().cancel();
37         view.animate()
38                 .alpha(0f)
39                 .setDuration(duration)
40                 .setInterpolator(Interpolators.ALPHA_OUT)
41                 .setStartDelay(delay)
42                 .withEndAction(new Runnable() {
43                     @Override
44                     public void run() {
45                         if (endRunnable != null) {
46                             endRunnable.run();
47                         }
48                         view.setVisibility(View.INVISIBLE);
49                     }
50                 });
51         if (view.hasOverlappingRendering()) {
52             view.animate().withLayer();
53         }
54     }
55 
fadeOut(View view, float fadeOutAmount)56     public static void fadeOut(View view, float fadeOutAmount) {
57         fadeOut(view, fadeOutAmount, true /* remap */);
58     }
59 
60     /**
61      * Fade out a view by a given progress amount
62      * @param view the view to fade out
63      * @param fadeOutAmount how much the view is faded out. 0 means not at all and 1 means fully
64      *                      faded out
65      * @param remap whether the fade amount should be remapped to the shorter duration
66      * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
67      * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
68      *
69      * @see #fadeIn(View, float, boolean)
70      */
fadeOut(View view, float fadeOutAmount, boolean remap)71     public static void fadeOut(View view, float fadeOutAmount, boolean remap) {
72         view.animate().cancel();
73         if (fadeOutAmount == 1.0f) {
74             view.setVisibility(View.INVISIBLE);
75         } else if (view.getVisibility() == View.INVISIBLE) {
76             view.setVisibility(View.VISIBLE);
77         }
78         if (remap) {
79             fadeOutAmount = mapToFadeDuration(fadeOutAmount);
80         }
81         float alpha = Interpolators.ALPHA_OUT.getInterpolation(1.0f - fadeOutAmount);
82         view.setAlpha(alpha);
83         updateLayerType(view, alpha);
84     }
85 
mapToFadeDuration(float fadeOutAmount)86     private static float mapToFadeDuration(float fadeOutAmount) {
87         // Assuming a linear interpolator, we can easily map it to our new duration
88         float endPoint = (float) ANIMATION_DURATION_LENGTH
89                 / (float) StackStateAnimator.ANIMATION_DURATION_STANDARD;
90         return Math.min(fadeOutAmount / endPoint, 1.0f);
91     }
92 
updateLayerType(View view, float alpha)93     private static void updateLayerType(View view, float alpha) {
94         if (view.hasOverlappingRendering() && alpha > 0.0f && alpha < 1.0f) {
95             view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
96         } else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE) {
97             view.setLayerType(View.LAYER_TYPE_NONE, null);
98         }
99     }
100 
fadeIn(final View view)101     public static void fadeIn(final View view) {
102         fadeIn(view, ANIMATION_DURATION_LENGTH, 0);
103     }
104 
fadeIn(final View view, long duration, int delay)105     public static void fadeIn(final View view, long duration, int delay) {
106         view.animate().cancel();
107         if (view.getVisibility() == View.INVISIBLE) {
108             view.setAlpha(0.0f);
109             view.setVisibility(View.VISIBLE);
110         }
111         view.animate()
112                 .alpha(1f)
113                 .setDuration(duration)
114                 .setStartDelay(delay)
115                 .setInterpolator(Interpolators.ALPHA_IN)
116                 .withEndAction(null);
117         if (view.hasOverlappingRendering()) {
118             view.animate().withLayer();
119         }
120     }
121 
fadeIn(View view, float fadeInAmount)122     public static void fadeIn(View view, float fadeInAmount) {
123         fadeIn(view, fadeInAmount, true /* remap */);
124     }
125 
126     /**
127      * Fade in a view by a given progress amount
128      * @param view the view to fade in
129      * @param fadeInAmount how much the view is faded in. 0 means not at all and 1 means fully
130      *                     faded in.
131      * @param remap whether the fade amount should be remapped to the shorter duration
132      * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
133      * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
134      *
135      * @see #fadeOut(View, float, boolean)
136      */
fadeIn(View view, float fadeInAmount, boolean remap)137     public static void fadeIn(View view, float fadeInAmount, boolean remap) {
138         view.animate().cancel();
139         if (view.getVisibility() == View.INVISIBLE) {
140             view.setVisibility(View.VISIBLE);
141         }
142         if (remap) {
143             fadeInAmount = mapToFadeDuration(fadeInAmount);
144         }
145         float alpha = Interpolators.ALPHA_IN.getInterpolation(fadeInAmount);
146         view.setAlpha(alpha);
147         updateLayerType(view, alpha);
148     }
149 }
150