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