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