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