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.settingslib.Utils; 37 import com.android.systemui.Interpolators; 38 import com.android.systemui.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 PorterDuffColorFilter mTintFilter; 170 private Paint mPaint = new Paint(); 171 172 private int mGradientAlphaStart; 173 private int mColorStart; 174 private Rect mFrame; 175 176 BarBackgroundDrawable(Context context, int gradientResourceId)177 public BarBackgroundDrawable(Context context, int gradientResourceId) { 178 final Resources res = context.getResources(); 179 if (DEBUG_COLORS) { 180 mOpaque = 0xff0000ff; 181 mSemiTransparent = 0x7f0000ff; 182 mTransparent = 0x2f0000ff; 183 mWarning = 0xffff0000; 184 } else { 185 mOpaque = context.getColor(R.color.system_bar_background_opaque); 186 mSemiTransparent = context.getColor( 187 com.android.internal.R.color.system_bar_background_semi_transparent); 188 mTransparent = context.getColor(R.color.system_bar_background_transparent); 189 mWarning = Utils.getColorAttrDefaultColor(context, android.R.attr.colorError); 190 } 191 mGradient = context.getDrawable(gradientResourceId); 192 } 193 setFrame(Rect frame)194 public void setFrame(Rect frame) { 195 mFrame = frame; 196 } 197 198 @Override setAlpha(int alpha)199 public void setAlpha(int alpha) { 200 // noop 201 } 202 203 @Override setColorFilter(ColorFilter colorFilter)204 public void setColorFilter(ColorFilter colorFilter) { 205 // noop 206 } 207 208 @Override setTint(int color)209 public void setTint(int color) { 210 PorterDuff.Mode targetMode = mTintFilter == null ? Mode.SRC_IN : 211 mTintFilter.getMode(); 212 if (mTintFilter == null || mTintFilter.getColor() != color) { 213 mTintFilter = new PorterDuffColorFilter(color, targetMode); 214 } 215 invalidateSelf(); 216 } 217 218 @Override setTintMode(Mode tintMode)219 public void setTintMode(Mode tintMode) { 220 int targetColor = mTintFilter == null ? 0 : mTintFilter.getColor(); 221 if (mTintFilter == null || mTintFilter.getMode() != tintMode) { 222 mTintFilter = new PorterDuffColorFilter(targetColor, tintMode); 223 } 224 invalidateSelf(); 225 } 226 227 @Override onBoundsChange(Rect bounds)228 protected void onBoundsChange(Rect bounds) { 229 super.onBoundsChange(bounds); 230 mGradient.setBounds(bounds); 231 } 232 applyModeBackground(int oldMode, int newMode, boolean animate)233 public void applyModeBackground(int oldMode, int newMode, boolean animate) { 234 if (mMode == newMode) return; 235 mMode = newMode; 236 mAnimating = animate; 237 if (animate) { 238 long now = SystemClock.elapsedRealtime(); 239 mStartTime = now; 240 mEndTime = now + BACKGROUND_DURATION; 241 mGradientAlphaStart = mGradientAlpha; 242 mColorStart = mColor; 243 } 244 invalidateSelf(); 245 } 246 247 @Override getOpacity()248 public int getOpacity() { 249 return PixelFormat.TRANSLUCENT; 250 } 251 finishAnimation()252 public void finishAnimation() { 253 if (mAnimating) { 254 mAnimating = false; 255 invalidateSelf(); 256 } 257 } 258 259 @Override draw(Canvas canvas)260 public void draw(Canvas canvas) { 261 int targetGradientAlpha = 0, targetColor = 0; 262 if (mMode == MODE_WARNING) { 263 targetColor = mWarning; 264 } else if (mMode == MODE_TRANSLUCENT) { 265 targetColor = mSemiTransparent; 266 } else if (mMode == MODE_SEMI_TRANSPARENT) { 267 targetColor = mSemiTransparent; 268 } else if (mMode == MODE_TRANSPARENT || mMode == MODE_LIGHTS_OUT_TRANSPARENT) { 269 targetColor = mTransparent; 270 } else { 271 targetColor = mOpaque; 272 } 273 274 if (!mAnimating) { 275 mColor = targetColor; 276 mGradientAlpha = targetGradientAlpha; 277 } else { 278 final long now = SystemClock.elapsedRealtime(); 279 if (now >= mEndTime) { 280 mAnimating = false; 281 mColor = targetColor; 282 mGradientAlpha = targetGradientAlpha; 283 } else { 284 final float t = (now - mStartTime) / (float)(mEndTime - mStartTime); 285 final float v = Math.max(0, Math.min( 286 Interpolators.LINEAR.getInterpolation(t), 1)); 287 mGradientAlpha = (int)(v * targetGradientAlpha + mGradientAlphaStart * (1 - v)); 288 mColor = Color.argb( 289 (int)(v * Color.alpha(targetColor) + Color.alpha(mColorStart) * (1 - v)), 290 (int)(v * Color.red(targetColor) + Color.red(mColorStart) * (1 - v)), 291 (int)(v * Color.green(targetColor) + Color.green(mColorStart) * (1 - v)), 292 (int)(v * Color.blue(targetColor) + Color.blue(mColorStart) * (1 - v))); 293 } 294 } 295 if (mGradientAlpha > 0) { 296 mGradient.setAlpha(mGradientAlpha); 297 mGradient.draw(canvas); 298 } 299 if (Color.alpha(mColor) > 0) { 300 mPaint.setColor(mColor); 301 if (mTintFilter != null) { 302 mPaint.setColorFilter(mTintFilter); 303 } 304 if (mFrame != null) { 305 canvas.drawRect(mFrame, mPaint); 306 } else { 307 canvas.drawPaint(mPaint); 308 } 309 } 310 if (mAnimating) { 311 invalidateSelf(); // keep going 312 } 313 } 314 } 315 } 316