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