• 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.annotation.IntDef;
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.PorterDuff.Mode;
29 import android.graphics.PorterDuffColorFilter;
30 import android.graphics.Rect;
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.app.animation.Interpolators;
37 import com.android.settingslib.Utils;
38 import com.android.systemui.res.R;
39 
40 import java.lang.annotation.Retention;
41 import java.lang.annotation.RetentionPolicy;
42 
43 public class BarTransitions {
44     private static final boolean DEBUG = false;
45     private static final boolean DEBUG_COLORS = false;
46 
47     public static final int MODE_TRANSPARENT = 0;
48     public static final int MODE_SEMI_TRANSPARENT = 1;
49     public static final int MODE_TRANSLUCENT = 2;
50     public static final int MODE_LIGHTS_OUT = 3;
51     public static final int MODE_OPAQUE = 4;
52     public static final int MODE_WARNING = 5;
53     public static final int MODE_LIGHTS_OUT_TRANSPARENT = 6;
54 
55     @IntDef(flag = true, prefix = { "MODE_" }, value = {
56             MODE_OPAQUE,
57             MODE_SEMI_TRANSPARENT,
58             MODE_TRANSLUCENT,
59             MODE_LIGHTS_OUT,
60             MODE_TRANSPARENT,
61             MODE_WARNING,
62             MODE_LIGHTS_OUT_TRANSPARENT
63     })
64     @Retention(RetentionPolicy.SOURCE)
65     public @interface TransitionMode {}
66 
67     public static final int LIGHTS_IN_DURATION = 250;
68     public static final int LIGHTS_OUT_DURATION = 1500;
69     public static final int BACKGROUND_DURATION = 200;
70 
71     private final String mTag;
72     private final View mView;
73     protected final BarBackgroundDrawable mBarBackground;
74 
75     private @TransitionMode int mMode;
76     private boolean mAlwaysOpaque = false;
77 
BarTransitions(View view, int gradientResourceId)78     public BarTransitions(View view, int gradientResourceId) {
79         mTag = "BarTransitions." + view.getClass().getSimpleName();
80         mView = view;
81         mBarBackground = new BarBackgroundDrawable(mView.getContext(), gradientResourceId);
82         mView.setBackground(mBarBackground);
83     }
84 
destroy()85     public void destroy() {
86         // To be overridden
87     }
88 
getMode()89     public int getMode() {
90         return mMode;
91     }
92 
setAutoDim(boolean autoDim)93     public void setAutoDim(boolean autoDim) {
94         // Default is don't care.
95     }
96 
97     /**
98      * @param alwaysOpaque if {@code true}, the bar's background will always be opaque, regardless
99      *         of what mode it is currently set to.
100      */
setAlwaysOpaque(boolean alwaysOpaque)101     public void setAlwaysOpaque(boolean alwaysOpaque) {
102         mAlwaysOpaque = alwaysOpaque;
103     }
104 
isAlwaysOpaque()105     public boolean isAlwaysOpaque() {
106         // Low-end devices do not support translucent modes, fallback to opaque
107         return mAlwaysOpaque;
108     }
109 
transitionTo(int mode, boolean animate)110     public void transitionTo(int mode, boolean animate) {
111         if (isAlwaysOpaque() && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
112                 || mode == MODE_TRANSPARENT)) {
113             mode = MODE_OPAQUE;
114         }
115         if (isAlwaysOpaque() && (mode == MODE_LIGHTS_OUT_TRANSPARENT)) {
116             mode = MODE_LIGHTS_OUT;
117         }
118         if (mMode == mode) return;
119         int oldMode = mMode;
120         mMode = mode;
121         if (DEBUG) Log.d(mTag, String.format("%s -> %s animate=%s",
122                 modeToString(oldMode), modeToString(mode),  animate));
123         onTransition(oldMode, mMode, animate);
124     }
125 
onTransition(int oldMode, int newMode, boolean animate)126     protected void onTransition(int oldMode, int newMode, boolean animate) {
127         applyModeBackground(oldMode, newMode, animate);
128     }
129 
applyModeBackground(int oldMode, int newMode, boolean animate)130     protected void applyModeBackground(int oldMode, int newMode, boolean animate) {
131         if (DEBUG) Log.d(mTag, String.format("applyModeBackground oldMode=%s newMode=%s animate=%s",
132                 modeToString(oldMode), modeToString(newMode), animate));
133         mBarBackground.applyModeBackground(oldMode, newMode, animate);
134     }
135 
modeToString(int mode)136     public static String modeToString(int mode) {
137         if (mode == MODE_OPAQUE) return "MODE_OPAQUE";
138         if (mode == MODE_SEMI_TRANSPARENT) return "MODE_SEMI_TRANSPARENT";
139         if (mode == MODE_TRANSLUCENT) return "MODE_TRANSLUCENT";
140         if (mode == MODE_LIGHTS_OUT) return "MODE_LIGHTS_OUT";
141         if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT";
142         if (mode == MODE_WARNING) return "MODE_WARNING";
143         if (mode == MODE_LIGHTS_OUT_TRANSPARENT) return "MODE_LIGHTS_OUT_TRANSPARENT";
144         throw new IllegalArgumentException("Unknown mode " + mode);
145     }
146 
finishAnimations()147     public void finishAnimations() {
148         mBarBackground.finishAnimation();
149     }
150 
isLightsOut(int mode)151     protected boolean isLightsOut(int mode) {
152         return mode == MODE_LIGHTS_OUT || mode == MODE_LIGHTS_OUT_TRANSPARENT;
153     }
154 
155     protected static class BarBackgroundDrawable extends Drawable {
156         private final int mOpaque;
157         private final int mSemiTransparent;
158         private final int mTransparent;
159         private final int mWarning;
160         private final Drawable mGradient;
161 
162         private int mMode = -1;
163         private boolean mAnimating;
164         private long mStartTime;
165         private long mEndTime;
166 
167         private int mGradientAlpha;
168         private int mColor;
169         private float mOverrideAlpha = 1f;
170         private PorterDuffColorFilter mTintFilter;
171         private Paint mPaint = new Paint();
172 
173         private int mGradientAlphaStart;
174         private int mColorStart;
175         private Rect mFrame;
176 
177 
BarBackgroundDrawable(Context context, int gradientResourceId)178         public BarBackgroundDrawable(Context context, int gradientResourceId) {
179             final Resources res = context.getResources();
180             if (DEBUG_COLORS) {
181                 mOpaque = 0xff0000ff;
182                 mSemiTransparent = 0x7f0000ff;
183                 mTransparent = 0x2f0000ff;
184                 mWarning = 0xffff0000;
185             } else {
186                 mOpaque = context.getColor(R.color.system_bar_background_opaque);
187                 mSemiTransparent = context.getColor(
188                         com.android.internal.R.color.system_bar_background_semi_transparent);
189                 mTransparent = context.getColor(R.color.system_bar_background_transparent);
190                 mWarning = Utils.getColorAttrDefaultColor(context, android.R.attr.colorError);
191             }
192             mGradient = context.getDrawable(gradientResourceId);
193         }
194 
setFrame(Rect frame)195         public void setFrame(Rect frame) {
196             mFrame = frame;
197         }
198 
setOverrideAlpha(float overrideAlpha)199         public void setOverrideAlpha(float overrideAlpha) {
200             mOverrideAlpha = overrideAlpha;
201             invalidateSelf();
202         }
203 
getOverrideAlpha()204         public float getOverrideAlpha() {
205             return mOverrideAlpha;
206         }
207 
getColor()208         public int getColor() {
209             return mColor;
210         }
211 
getFrame()212         public Rect getFrame() {
213             return mFrame;
214         }
215 
216         @Override
setAlpha(int alpha)217         public void setAlpha(int alpha) {
218             // noop
219         }
220 
221         @Override
setColorFilter(ColorFilter colorFilter)222         public void setColorFilter(ColorFilter colorFilter) {
223             // noop
224         }
225 
226         @Override
setTint(int color)227         public void setTint(int color) {
228             PorterDuff.Mode targetMode = mTintFilter == null ? Mode.SRC_IN :
229                 mTintFilter.getMode();
230             if (mTintFilter == null || mTintFilter.getColor() != color) {
231                 mTintFilter = new PorterDuffColorFilter(color, targetMode);
232             }
233             invalidateSelf();
234         }
235 
236         @Override
setTintMode(Mode tintMode)237         public void setTintMode(Mode tintMode) {
238             int targetColor = mTintFilter == null ? 0 : mTintFilter.getColor();
239             if (mTintFilter == null || mTintFilter.getMode() != tintMode) {
240                 mTintFilter = new PorterDuffColorFilter(targetColor, tintMode);
241             }
242             invalidateSelf();
243         }
244 
245         @Override
onBoundsChange(Rect bounds)246         protected void onBoundsChange(Rect bounds) {
247             super.onBoundsChange(bounds);
248             mGradient.setBounds(bounds);
249         }
250 
applyModeBackground(int oldMode, int newMode, boolean animate)251         public void applyModeBackground(int oldMode, int newMode, boolean animate) {
252             if (mMode == newMode) return;
253             mMode = newMode;
254             mAnimating = animate;
255             if (animate) {
256                 long now = SystemClock.elapsedRealtime();
257                 mStartTime = now;
258                 mEndTime = now + BACKGROUND_DURATION;
259                 mGradientAlphaStart = mGradientAlpha;
260                 mColorStart = mColor;
261             }
262             invalidateSelf();
263         }
264 
265         @Override
getOpacity()266         public int getOpacity() {
267             return PixelFormat.TRANSLUCENT;
268         }
269 
finishAnimation()270         public void finishAnimation() {
271             if (mAnimating) {
272                 mAnimating = false;
273                 invalidateSelf();
274             }
275         }
276 
277         @Override
draw(Canvas canvas)278         public void draw(Canvas canvas) {
279             int targetGradientAlpha = 0, targetColor = 0;
280             if (mMode == MODE_WARNING) {
281                 targetColor = mWarning;
282             } else if (mMode == MODE_TRANSLUCENT) {
283                 targetColor = mSemiTransparent;
284             } else if (mMode == MODE_SEMI_TRANSPARENT) {
285                 targetColor = mSemiTransparent;
286             } else if (mMode == MODE_TRANSPARENT || mMode == MODE_LIGHTS_OUT_TRANSPARENT) {
287                 targetColor = mTransparent;
288             } else {
289                 targetColor = mOpaque;
290             }
291 
292             if (!mAnimating) {
293                 mColor = targetColor;
294                 mGradientAlpha = targetGradientAlpha;
295             } else {
296                 final long now = SystemClock.elapsedRealtime();
297                 if (now >= mEndTime) {
298                     mAnimating = false;
299                     mColor = targetColor;
300                     mGradientAlpha = targetGradientAlpha;
301                 } else {
302                     final float t = (now - mStartTime) / (float)(mEndTime - mStartTime);
303                     final float v = Math.max(0, Math.min(
304                             Interpolators.LINEAR.getInterpolation(t), 1));
305                     mGradientAlpha = (int)(v * targetGradientAlpha + mGradientAlphaStart * (1 - v));
306                     mColor = Color.argb(
307                           (int)(v * Color.alpha(targetColor) + Color.alpha(mColorStart) * (1 - v)),
308                           (int)(v * Color.red(targetColor) + Color.red(mColorStart) * (1 - v)),
309                           (int)(v * Color.green(targetColor) + Color.green(mColorStart) * (1 - v)),
310                           (int)(v * Color.blue(targetColor) + Color.blue(mColorStart) * (1 - v)));
311                 }
312             }
313             if (mGradientAlpha > 0) {
314                 mGradient.setAlpha(mGradientAlpha);
315                 mGradient.draw(canvas);
316             }
317 
318             if (Color.alpha(mColor) > 0) {
319                 mPaint.setColor(mColor);
320                 if (mTintFilter != null) {
321                     mPaint.setColorFilter(mTintFilter);
322                 }
323                 mPaint.setAlpha((int) (Color.alpha(mColor) * mOverrideAlpha));
324                 if (mFrame != null) {
325                     canvas.drawRect(mFrame, mPaint);
326                 } else {
327                     canvas.drawPaint(mPaint);
328                 }
329             }
330             if (mAnimating) {
331                 invalidateSelf();  // keep going
332             }
333         }
334     }
335 }
336