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