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