1 /*
2  * Copyright (C) 2013 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.phone;
18 
19 import android.animation.TimeInterpolator;
20 import android.app.ActivityManager;
21 import android.content.Context;
22 import android.content.res.Resources;
23 import android.graphics.Canvas;
24 import android.graphics.Color;
25 import android.graphics.ColorFilter;
26 import android.graphics.PixelFormat;
27 import android.graphics.Rect;
28 import android.graphics.drawable.Drawable;
29 import android.os.SystemClock;
30 import android.util.Log;
31 import android.view.View;
32 import android.view.animation.LinearInterpolator;
33 
34 import com.android.systemui.R;
35 
36 public class BarTransitions {
37     private static final boolean DEBUG = false;
38     private static final boolean DEBUG_COLORS = false;
39 
40     public static final boolean HIGH_END = ActivityManager.isHighEndGfx();
41 
42     public static final int MODE_OPAQUE = 0;
43     public static final int MODE_SEMI_TRANSPARENT = 1;
44     public static final int MODE_TRANSLUCENT = 2;
45     public static final int MODE_LIGHTS_OUT = 3;
46     public static final int MODE_TRANSPARENT = 4;
47     public static final int MODE_WARNING = 5;
48     public static final int MODE_LIGHTS_OUT_TRANSPARENT = 6;
49 
50     public static final int LIGHTS_IN_DURATION = 250;
51     public static final int LIGHTS_OUT_DURATION = 750;
52     public static final int BACKGROUND_DURATION = 200;
53 
54     private final String mTag;
55     private final View mView;
56     private final BarBackgroundDrawable mBarBackground;
57 
58     private int mMode;
59 
BarTransitions(View view, int gradientResourceId)60     public BarTransitions(View view, int gradientResourceId) {
61         mTag = "BarTransitions." + view.getClass().getSimpleName();
62         mView = view;
63         mBarBackground = new BarBackgroundDrawable(mView.getContext(), gradientResourceId);
64         if (HIGH_END) {
65             mView.setBackground(mBarBackground);
66         }
67     }
68 
getMode()69     public int getMode() {
70         return mMode;
71     }
72 
transitionTo(int mode, boolean animate)73     public void transitionTo(int mode, boolean animate) {
74         // low-end devices do not support translucent modes, fallback to opaque
75         if (!HIGH_END && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
76                 || mode == MODE_TRANSPARENT)) {
77             mode = MODE_OPAQUE;
78         }
79         if (!HIGH_END && (mode == MODE_LIGHTS_OUT_TRANSPARENT)) {
80             mode = MODE_LIGHTS_OUT;
81         }
82         if (mMode == mode) return;
83         int oldMode = mMode;
84         mMode = mode;
85         if (DEBUG) Log.d(mTag, String.format("%s -> %s animate=%s",
86                 modeToString(oldMode), modeToString(mode),  animate));
87         onTransition(oldMode, mMode, animate);
88     }
89 
onTransition(int oldMode, int newMode, boolean animate)90     protected void onTransition(int oldMode, int newMode, boolean animate) {
91         if (HIGH_END) {
92             applyModeBackground(oldMode, newMode, animate);
93         }
94     }
95 
applyModeBackground(int oldMode, int newMode, boolean animate)96     protected void applyModeBackground(int oldMode, int newMode, boolean animate) {
97         if (DEBUG) Log.d(mTag, String.format("applyModeBackground oldMode=%s newMode=%s animate=%s",
98                 modeToString(oldMode), modeToString(newMode), animate));
99         mBarBackground.applyModeBackground(oldMode, newMode, animate);
100     }
101 
modeToString(int mode)102     public static String modeToString(int mode) {
103         if (mode == MODE_OPAQUE) return "MODE_OPAQUE";
104         if (mode == MODE_SEMI_TRANSPARENT) return "MODE_SEMI_TRANSPARENT";
105         if (mode == MODE_TRANSLUCENT) return "MODE_TRANSLUCENT";
106         if (mode == MODE_LIGHTS_OUT) return "MODE_LIGHTS_OUT";
107         if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT";
108         if (mode == MODE_WARNING) return "MODE_WARNING";
109         if (mode == MODE_LIGHTS_OUT_TRANSPARENT) return "MODE_LIGHTS_OUT_TRANSPARENT";
110         throw new IllegalArgumentException("Unknown mode " + mode);
111     }
112 
finishAnimations()113     public void finishAnimations() {
114         mBarBackground.finishAnimation();
115     }
116 
isLightsOut(int mode)117     protected boolean isLightsOut(int mode) {
118         return mode == MODE_LIGHTS_OUT || mode == MODE_LIGHTS_OUT_TRANSPARENT;
119     }
120 
121     private static class BarBackgroundDrawable extends Drawable {
122         private final int mOpaque;
123         private final int mSemiTransparent;
124         private final int mTransparent;
125         private final int mWarning;
126         private final Drawable mGradient;
127         private final TimeInterpolator mInterpolator;
128 
129         private int mMode = -1;
130         private boolean mAnimating;
131         private long mStartTime;
132         private long mEndTime;
133 
134         private int mGradientAlpha;
135         private int mColor;
136 
137         private int mGradientAlphaStart;
138         private int mColorStart;
139 
BarBackgroundDrawable(Context context, int gradientResourceId)140         public BarBackgroundDrawable(Context context, int gradientResourceId) {
141             final Resources res = context.getResources();
142             if (DEBUG_COLORS) {
143                 mOpaque = 0xff0000ff;
144                 mSemiTransparent = 0x7f0000ff;
145                 mTransparent = 0x2f0000ff;
146                 mWarning = 0xffff0000;
147             } else {
148                 mOpaque = context.getColor(R.color.system_bar_background_opaque);
149                 mSemiTransparent = context.getColor(R.color.system_bar_background_semi_transparent);
150                 mTransparent = context.getColor(R.color.system_bar_background_transparent);
151                 mWarning = context.getColor(com.android.internal.R.color.battery_saver_mode_color);
152             }
153             mGradient = context.getDrawable(gradientResourceId);
154             mInterpolator = new LinearInterpolator();
155         }
156 
157         @Override
setAlpha(int alpha)158         public void setAlpha(int alpha) {
159             // noop
160         }
161 
162         @Override
setColorFilter(ColorFilter colorFilter)163         public void setColorFilter(ColorFilter colorFilter) {
164             // noop
165         }
166 
167         @Override
onBoundsChange(Rect bounds)168         protected void onBoundsChange(Rect bounds) {
169             super.onBoundsChange(bounds);
170             mGradient.setBounds(bounds);
171         }
172 
applyModeBackground(int oldMode, int newMode, boolean animate)173         public void applyModeBackground(int oldMode, int newMode, boolean animate) {
174             if (mMode == newMode) return;
175             mMode = newMode;
176             mAnimating = animate;
177             if (animate) {
178                 long now = SystemClock.elapsedRealtime();
179                 mStartTime = now;
180                 mEndTime = now + BACKGROUND_DURATION;
181                 mGradientAlphaStart = mGradientAlpha;
182                 mColorStart = mColor;
183             }
184             invalidateSelf();
185         }
186 
187         @Override
getOpacity()188         public int getOpacity() {
189             return PixelFormat.TRANSLUCENT;
190         }
191 
finishAnimation()192         public void finishAnimation() {
193             if (mAnimating) {
194                 mAnimating = false;
195                 invalidateSelf();
196             }
197         }
198 
199         @Override
draw(Canvas canvas)200         public void draw(Canvas canvas) {
201             int targetGradientAlpha = 0, targetColor = 0;
202             if (mMode == MODE_WARNING) {
203                 targetColor = mWarning;
204             } else if (mMode == MODE_TRANSLUCENT) {
205                 targetColor = mSemiTransparent;
206             } else if (mMode == MODE_SEMI_TRANSPARENT) {
207                 targetColor = mSemiTransparent;
208             } else if (mMode == MODE_TRANSPARENT || mMode == MODE_LIGHTS_OUT_TRANSPARENT) {
209                 targetColor = mTransparent;
210             } else {
211                 targetColor = mOpaque;
212             }
213             if (!mAnimating) {
214                 mColor = targetColor;
215                 mGradientAlpha = targetGradientAlpha;
216             } else {
217                 final long now = SystemClock.elapsedRealtime();
218                 if (now >= mEndTime) {
219                     mAnimating = false;
220                     mColor = targetColor;
221                     mGradientAlpha = targetGradientAlpha;
222                 } else {
223                     final float t = (now - mStartTime) / (float)(mEndTime - mStartTime);
224                     final float v = Math.max(0, Math.min(mInterpolator.getInterpolation(t), 1));
225                     mGradientAlpha = (int)(v * targetGradientAlpha + mGradientAlphaStart * (1 - v));
226                     mColor = Color.argb(
227                           (int)(v * Color.alpha(targetColor) + Color.alpha(mColorStart) * (1 - v)),
228                           (int)(v * Color.red(targetColor) + Color.red(mColorStart) * (1 - v)),
229                           (int)(v * Color.green(targetColor) + Color.green(mColorStart) * (1 - v)),
230                           (int)(v * Color.blue(targetColor) + Color.blue(mColorStart) * (1 - v)));
231                 }
232             }
233             if (mGradientAlpha > 0) {
234                 mGradient.setAlpha(mGradientAlpha);
235                 mGradient.draw(canvas);
236             }
237             if (Color.alpha(mColor) > 0) {
238                 canvas.drawColor(mColor);
239             }
240             if (mAnimating) {
241                 invalidateSelf();  // keep going
242             }
243         }
244     }
245 }
246