• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.animation.Animator;
20 import android.view.View;
21 import android.view.ViewPropertyAnimator;
22 
23 import androidx.annotation.Nullable;
24 
25 import com.android.app.animation.Interpolators;
26 import com.android.systemui.res.R;
27 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
28 
29 /**
30  * A helper to fade views in and out.
31  */
32 public class CrossFadeHelper {
33     public static final long ANIMATION_DURATION_LENGTH = 210;
34 
fadeOut(final View view)35     public static void fadeOut(final View view) {
36         fadeOut(view, (Runnable) null);
37     }
38 
fadeOut(final View view, final Runnable endRunnable)39     public static void fadeOut(final View view, final Runnable endRunnable) {
40         fadeOut(view, ANIMATION_DURATION_LENGTH, 0, endRunnable);
41     }
42 
fadeOut(final View view, final Animator.AnimatorListener listener)43     public static void fadeOut(final View view, final Animator.AnimatorListener listener) {
44         fadeOut(view, ANIMATION_DURATION_LENGTH, 0, listener);
45     }
46 
fadeOut(final View view, long duration, int delay)47     public static void fadeOut(final View view, long duration, int delay) {
48         fadeOut(view, duration, delay, (Runnable) null);
49     }
50 
51     /**
52      * Perform a fade-out animation, invoking {@code endRunnable} when the animation ends. It will
53      * not be invoked if the animation is cancelled.
54      *
55      * @deprecated Use {@link #fadeOut(View, long, int, Animator.AnimatorListener)} instead.
56      */
57     @Deprecated
fadeOut(final View view, long duration, int delay, @Nullable final Runnable endRunnable)58     public static void fadeOut(final View view, long duration, int delay,
59             @Nullable final Runnable endRunnable) {
60         view.animate().cancel();
61         view.animate()
62                 .alpha(0f)
63                 .setDuration(duration)
64                 .setInterpolator(Interpolators.ALPHA_OUT)
65                 .setStartDelay(delay)
66                 .withEndAction(() -> {
67                     if (endRunnable != null) {
68                         endRunnable.run();
69                     }
70                     if (view.getVisibility() != View.GONE) {
71                         view.setVisibility(View.INVISIBLE);
72                     }
73                 });
74         if (view.hasOverlappingRendering()) {
75             view.animate().withLayer();
76         }
77     }
78 
fadeOut(final View view, long duration, int delay, @Nullable final Animator.AnimatorListener listener)79     public static void fadeOut(final View view, long duration, int delay,
80             @Nullable final Animator.AnimatorListener listener) {
81         view.animate().cancel();
82         ViewPropertyAnimator animator = view.animate()
83                 .alpha(0f)
84                 .setDuration(duration)
85                 .setInterpolator(Interpolators.ALPHA_OUT)
86                 .setStartDelay(delay)
87                 .withEndAction(() -> {
88                     if (view.getVisibility() != View.GONE) {
89                         view.setVisibility(View.INVISIBLE);
90                     }
91                 });
92         if (listener != null) {
93             animator.setListener(listener);
94         }
95         if (view.hasOverlappingRendering()) {
96             view.animate().withLayer();
97         }
98     }
99 
fadeOut(View view, float fadeOutAmount)100     public static void fadeOut(View view, float fadeOutAmount) {
101         fadeOut(view, fadeOutAmount, true /* remap */);
102     }
103 
104     /**
105      * Fade out a view by a given progress amount
106      * @param view the view to fade out
107      * @param fadeOutAmount how much the view is faded out. 0 means not at all and 1 means fully
108      *                      faded out
109      * @param remap whether the fade amount should be remapped to the shorter duration
110      * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
111      * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
112      *
113      * @see #fadeIn(View, float, boolean)
114      */
fadeOut(View view, float fadeOutAmount, boolean remap)115     public static void fadeOut(View view, float fadeOutAmount, boolean remap) {
116         view.animate().cancel();
117         if (fadeOutAmount == 1.0f && view.getVisibility() != View.GONE) {
118             view.setVisibility(View.INVISIBLE);
119         } else if (view.getVisibility() == View.INVISIBLE) {
120             view.setVisibility(View.VISIBLE);
121         }
122         if (remap) {
123             fadeOutAmount = mapToFadeDuration(fadeOutAmount);
124         }
125         float alpha = Interpolators.ALPHA_OUT.getInterpolation(1.0f - fadeOutAmount);
126         view.setAlpha(alpha);
127         updateLayerType(view, alpha);
128     }
129 
mapToFadeDuration(float fadeOutAmount)130     private static float mapToFadeDuration(float fadeOutAmount) {
131         // Assuming a linear interpolator, we can easily map it to our new duration
132         float endPoint = (float) ANIMATION_DURATION_LENGTH
133                 / (float) StackStateAnimator.ANIMATION_DURATION_STANDARD;
134         return Math.min(fadeOutAmount / endPoint, 1.0f);
135     }
136 
updateLayerType(View view, float alpha)137     private static void updateLayerType(View view, float alpha) {
138         if (view.hasOverlappingRendering() && alpha > 0.0f && alpha < 1.0f) {
139             if (view.getLayerType() != View.LAYER_TYPE_HARDWARE) {
140                 view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
141                 view.setTag(R.id.cross_fade_layer_type_changed_tag, true);
142             }
143         } else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE
144                 && view.getTag(R.id.cross_fade_layer_type_changed_tag) != null) {
145             view.setLayerType(View.LAYER_TYPE_NONE, null);
146         }
147     }
148 
fadeIn(final View view)149     public static void fadeIn(final View view) {
150         fadeIn(view, ANIMATION_DURATION_LENGTH, 0);
151     }
152 
fadeIn(final View view, Runnable endRunnable)153     public static void fadeIn(final View view, Runnable endRunnable) {
154         fadeIn(view, ANIMATION_DURATION_LENGTH, /* delay= */ 0, endRunnable);
155     }
156 
fadeIn(final View view, Animator.AnimatorListener listener)157     public static void fadeIn(final View view, Animator.AnimatorListener listener) {
158         fadeIn(view, ANIMATION_DURATION_LENGTH, /* delay= */ 0, listener);
159     }
160 
fadeIn(final View view, long duration, int delay)161     public static void fadeIn(final View view, long duration, int delay) {
162         fadeIn(view, duration, delay, /* endRunnable= */ (Runnable) null);
163     }
164 
165     /**
166      * Perform a fade-in animation, invoking {@code endRunnable} when the animation ends. It will
167      * not be invoked if the animation is cancelled.
168      *
169      * @deprecated Use {@link #fadeIn(View, long, int, Animator.AnimatorListener)} instead.
170      */
171     @Deprecated
fadeIn(final View view, long duration, int delay, @Nullable Runnable endRunnable)172     public static void fadeIn(final View view, long duration, int delay,
173             @Nullable Runnable endRunnable) {
174         view.animate().cancel();
175         if (view.getVisibility() == View.INVISIBLE) {
176             view.setAlpha(0.0f);
177             view.setVisibility(View.VISIBLE);
178         }
179         view.animate()
180                 .alpha(1f)
181                 .setDuration(duration)
182                 .setStartDelay(delay)
183                 .setInterpolator(Interpolators.ALPHA_IN)
184                 .withEndAction(endRunnable);
185         if (view.hasOverlappingRendering() && view.getLayerType() != View.LAYER_TYPE_HARDWARE) {
186             view.animate().withLayer();
187         }
188     }
189 
fadeIn(final View view, long duration, int delay, @Nullable Animator.AnimatorListener listener)190     public static void fadeIn(final View view, long duration, int delay,
191             @Nullable Animator.AnimatorListener listener) {
192         view.animate().cancel();
193         if (view.getVisibility() == View.INVISIBLE) {
194             view.setAlpha(0.0f);
195             view.setVisibility(View.VISIBLE);
196         }
197         ViewPropertyAnimator animator = view.animate()
198                 .alpha(1f)
199                 .setDuration(duration)
200                 .setStartDelay(delay)
201                 .setInterpolator(Interpolators.ALPHA_IN);
202         if (listener != null) {
203             animator.setListener(listener);
204         }
205         if (view.hasOverlappingRendering() && view.getLayerType() != View.LAYER_TYPE_HARDWARE) {
206             view.animate().withLayer();
207         }
208     }
209 
fadeIn(View view, float fadeInAmount)210     public static void fadeIn(View view, float fadeInAmount) {
211         fadeIn(view, fadeInAmount, false /* remap */);
212     }
213 
214     /**
215      * Fade in a view by a given progress amount
216      * @param view the view to fade in
217      * @param fadeInAmount how much the view is faded in. 0 means not at all and 1 means fully
218      *                     faded in.
219      * @param remap whether the fade amount should be remapped to the shorter duration
220      * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
221      * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
222      *
223      * @see #fadeOut(View, float, boolean)
224      */
fadeIn(View view, float fadeInAmount, boolean remap)225     public static void fadeIn(View view, float fadeInAmount, boolean remap) {
226         view.animate().cancel();
227         if (view.getVisibility() == View.INVISIBLE) {
228             view.setVisibility(View.VISIBLE);
229         }
230         if (remap) {
231             fadeInAmount = mapToFadeDuration(fadeInAmount);
232         }
233         float alpha = Interpolators.ALPHA_IN.getInterpolation(fadeInAmount);
234         view.setAlpha(alpha);
235         updateLayerType(view, alpha);
236     }
237 }
238