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