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.launcher3.util;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ValueAnimator;
22 import android.animation.ValueAnimator.AnimatorUpdateListener;
23 import android.content.Context;
24 import android.view.View;
25 import android.view.accessibility.AccessibilityManager;
26 
27 import java.util.Arrays;
28 
29 /**
30  * A utility class which divides the alpha for a view across multiple states.
31  */
32 public class MultiStateAlphaController {
33 
34     private final View mTargetView;
35     private final float[] mAlphas;
36     private final AccessibilityManager mAm;
37     private int mZeroAlphaListenerCount = 0;
38 
MultiStateAlphaController(View view, int stateCount)39     public MultiStateAlphaController(View view, int stateCount) {
40         mTargetView = view;
41         mAlphas = new float[stateCount];
42         Arrays.fill(mAlphas, 1);
43 
44         mAm = (AccessibilityManager) view.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
45     }
46 
setAlphaAtIndex(float alpha, int index)47     public void setAlphaAtIndex(float alpha, int index) {
48         mAlphas[index] = alpha;
49         updateAlpha();
50     }
51 
updateAlpha()52     private void updateAlpha() {
53         // Only update the alpha if no zero-alpha animation is running.
54         if (mZeroAlphaListenerCount > 0) {
55             return;
56         }
57         float finalAlpha = 1;
58         for (float a : mAlphas) {
59             finalAlpha = finalAlpha * a;
60         }
61         mTargetView.setAlpha(finalAlpha);
62         mTargetView.setVisibility(finalAlpha > 0 ? View.VISIBLE
63                 : (mAm.isEnabled() ? View.GONE : View.INVISIBLE));
64     }
65 
66     /**
67      * Returns an animator which changes the alpha at the index {@param index}
68      * to {@param finalAlpha}. Alphas at other index are not affected.
69      */
animateAlphaAtIndex(float finalAlpha, final int index)70     public Animator animateAlphaAtIndex(float finalAlpha, final int index) {
71         final ValueAnimator anim;
72 
73         if (Float.compare(finalAlpha, mAlphas[index]) == 0) {
74             // Return a dummy animator to avoid null checks.
75             anim = ValueAnimator.ofFloat(0, 0);
76         } else {
77             ValueAnimator animator = ValueAnimator.ofFloat(mAlphas[index], finalAlpha);
78             animator.addUpdateListener(new AnimatorUpdateListener() {
79                 @Override
80                 public void onAnimationUpdate(ValueAnimator valueAnimator) {
81                     float value = (Float) valueAnimator.getAnimatedValue();
82                     setAlphaAtIndex(value, index);
83                 }
84             });
85             anim = animator;
86         }
87 
88         if (Float.compare(finalAlpha, 0f) == 0) {
89             // In case when any channel is animating to 0, and the current alpha is also 0, do not
90             // update alpha of the target view while the animation is running.
91             // We special case '0' because if any channel is set to 0, values of other
92             // channels do not matter.
93             anim.addListener(new ZeroAlphaAnimatorListener());
94         }
95         return anim;
96     }
97 
98     private class ZeroAlphaAnimatorListener extends AnimatorListenerAdapter {
99 
100         private boolean mStartedAtZero = false;
101 
102         @Override
onAnimationStart(Animator animation)103         public void onAnimationStart(Animator animation) {
104             mStartedAtZero = Float.compare(mTargetView.getAlpha(), 0f) == 0;
105             if (mStartedAtZero) {
106                 mZeroAlphaListenerCount++;
107                 mTargetView.setAlpha(0);
108             }
109         }
110 
111         @Override
onAnimationEnd(Animator animation)112         public void onAnimationEnd(Animator animation) {
113             if (mStartedAtZero) {
114                 mZeroAlphaListenerCount--;
115                 updateAlpha();
116             }
117         }
118     }
119 }
120