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