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