Home | History | Annotate | Download | only in views
      1 /*
      2  * Copyright (C) 2014 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.recents.views;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.ValueAnimator;
     22 import android.content.Context;
     23 import android.graphics.Bitmap;
     24 import android.graphics.BitmapShader;
     25 import android.graphics.Canvas;
     26 import android.graphics.Color;
     27 import android.graphics.LightingColorFilter;
     28 import android.graphics.Matrix;
     29 import android.graphics.Paint;
     30 import android.graphics.Rect;
     31 import android.graphics.RectF;
     32 import android.graphics.Shader;
     33 import android.util.AttributeSet;
     34 import android.view.View;
     35 import com.android.systemui.recents.RecentsConfiguration;
     36 import com.android.systemui.recents.model.Task;
     37 
     38 
     39 /** The task thumbnail view */
     40 public class TaskViewThumbnail extends View {
     41 
     42     private final int mCornerRadius;
     43     private final Matrix mScaleMatrix = new Matrix();
     44     RecentsConfiguration mConfig;
     45 
     46     // Task bar clipping
     47     Rect mClipRect = new Rect();
     48     Paint mDrawPaint = new Paint();
     49     LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
     50     private final RectF mBitmapRect = new RectF();
     51     private final RectF mLayoutRect = new RectF();
     52     private BitmapShader mBitmapShader;
     53     private float mBitmapAlpha;
     54     private float mDimAlpha;
     55     private View mTaskBar;
     56     private boolean mInvisible;
     57     private ValueAnimator mAlphaAnimator;
     58     private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
     59             = new ValueAnimator.AnimatorUpdateListener() {
     60         @Override
     61         public void onAnimationUpdate(ValueAnimator animation) {
     62             mBitmapAlpha = (float) animation.getAnimatedValue();
     63             updateFilter();
     64         }
     65     };
     66 
     67     public TaskViewThumbnail(Context context) {
     68         this(context, null);
     69     }
     70 
     71     public TaskViewThumbnail(Context context, AttributeSet attrs) {
     72         this(context, attrs, 0);
     73     }
     74 
     75     public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr) {
     76         this(context, attrs, defStyleAttr, 0);
     77     }
     78 
     79     public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     80         super(context, attrs, defStyleAttr, defStyleRes);
     81         mConfig = RecentsConfiguration.getInstance();
     82         mCornerRadius = mConfig.taskViewRoundedCornerRadiusPx;
     83         mDrawPaint.setColorFilter(mLightingColorFilter);
     84         mDrawPaint.setFilterBitmap(true);
     85         mDrawPaint.setAntiAlias(true);
     86     }
     87 
     88     @Override
     89     protected void onDraw(Canvas canvas) {
     90         if (mInvisible) {
     91             return;
     92         }
     93         canvas.drawRoundRect(0,
     94                 0,
     95                 getWidth(),
     96                 getHeight(),
     97                 mCornerRadius,
     98                 mCornerRadius,
     99                 mDrawPaint);
    100     }
    101 
    102     @Override
    103     protected void onFinishInflate() {
    104         mBitmapAlpha = 0.9f;
    105         updateFilter();
    106     }
    107 
    108     private void updateFilter() {
    109         if (mInvisible) {
    110             return;
    111         }
    112         int mul = (int) ((1.0f - mDimAlpha) * mBitmapAlpha * 255);
    113         int add = (int) ((1.0f - mDimAlpha) * (1 - mBitmapAlpha) * 255);
    114         if (mBitmapShader != null) {
    115             mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
    116             mLightingColorFilter.setColorAdd(Color.argb(0, add, add, add));
    117             mDrawPaint.setColorFilter(mLightingColorFilter);
    118             mDrawPaint.setColor(0xffffffff);
    119         } else {
    120             mDrawPaint.setColorFilter(null);
    121             int grey = mul + add;
    122             mDrawPaint.setColor(Color.argb(255, grey, grey, grey));
    123         }
    124         invalidate();
    125     }
    126 
    127     /** Updates the clip rect based on the given task bar. */
    128     void enableTaskBarClip(View taskBar) {
    129         mTaskBar = taskBar;
    130         int top = (int) Math.max(0, taskBar.getTranslationY() +
    131                 taskBar.getMeasuredHeight() - 1);
    132         mClipRect.set(0, top, getMeasuredWidth(), getMeasuredHeight());
    133         setClipBounds(mClipRect);
    134     }
    135 
    136     void updateVisibility(int clipBottom) {
    137         boolean invisible = mTaskBar != null && getHeight() - clipBottom < mTaskBar.getHeight();
    138         if (invisible != mInvisible) {
    139             mInvisible = invisible;
    140             if (!mInvisible) {
    141                 updateFilter();
    142             }
    143             invalidate();
    144         }
    145     }
    146 
    147     /** Binds the thumbnail view to the screenshot. */
    148     boolean bindToScreenshot(Bitmap ss) {
    149         setImageBitmap(ss);
    150         return ss != null;
    151     }
    152 
    153     /** Unbinds the thumbnail view from the screenshot. */
    154     void unbindFromScreenshot() {
    155         setImageBitmap(null);
    156     }
    157 
    158     /** Binds the thumbnail view to the task */
    159     void rebindToTask(Task t) {
    160         if (t.thumbnail != null) {
    161             setImageBitmap(t.thumbnail);
    162         } else {
    163             setImageBitmap(null);
    164         }
    165     }
    166 
    167     public void setImageBitmap(Bitmap bm) {
    168         if (bm != null) {
    169             mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP,
    170                     Shader.TileMode.CLAMP);
    171             mDrawPaint.setShader(mBitmapShader);
    172             mBitmapRect.set(0, 0, bm.getWidth(), bm.getHeight());
    173             updateBitmapScale();
    174         } else {
    175             mBitmapShader = null;
    176             mDrawPaint.setShader(null);
    177         }
    178         updateFilter();
    179     }
    180 
    181     @Override
    182     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    183         super.onLayout(changed, left, top, right, bottom);
    184         if (changed) {
    185             mLayoutRect.set(0, 0, getWidth(), getHeight());
    186             updateBitmapScale();
    187         }
    188     }
    189 
    190     private void updateBitmapScale() {
    191         if (mBitmapShader != null) {
    192             mScaleMatrix.setRectToRect(mBitmapRect, mLayoutRect, Matrix.ScaleToFit.FILL);
    193             mBitmapShader.setLocalMatrix(mScaleMatrix);
    194         }
    195     }
    196 
    197     public void setDimAlpha(float dimAlpha) {
    198         mDimAlpha = dimAlpha;
    199         updateFilter();
    200     }
    201 
    202     /** Unbinds the thumbnail view from the task */
    203     void unbindFromTask() {
    204         setImageBitmap(null);
    205     }
    206 
    207     /** Handles focus changes. */
    208     void onFocusChanged(boolean focused) {
    209         if (focused) {
    210             if (Float.compare(getAlpha(), 1f) != 0) {
    211                 startFadeAnimation(1f, 0, 150, null);
    212             }
    213         } else {
    214             if (Float.compare(getAlpha(), mConfig.taskViewThumbnailAlpha) != 0) {
    215                 startFadeAnimation(mConfig.taskViewThumbnailAlpha, 0, 150, null);
    216             }
    217         }
    218     }
    219 
    220     /** Prepares for the enter recents animation. */
    221     void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask) {
    222         if (isTaskViewLaunchTargetTask) {
    223             mBitmapAlpha = 1f;
    224         } else {
    225             mBitmapAlpha = mConfig.taskViewThumbnailAlpha;
    226         }
    227         updateFilter();
    228     }
    229 
    230     /** Animates this task thumbnail as it enters recents */
    231     void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
    232         startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay,
    233                 mConfig.taskBarEnterAnimDuration, postAnimRunnable);
    234     }
    235 
    236     /** Animates this task thumbnail as it exits recents */
    237     void startLaunchTaskAnimation(Runnable postAnimRunnable) {
    238         startFadeAnimation(1f, 0, mConfig.taskBarExitAnimDuration, postAnimRunnable);
    239     }
    240 
    241     /** Animates the thumbnail alpha. */
    242     void startFadeAnimation(float finalAlpha, int delay, int duration, final Runnable postAnimRunnable) {
    243         if (mAlphaAnimator != null) {
    244             mAlphaAnimator.cancel();
    245         }
    246         mAlphaAnimator = ValueAnimator.ofFloat(mBitmapAlpha, finalAlpha);
    247         mAlphaAnimator.addUpdateListener(mAlphaUpdateListener);
    248         mAlphaAnimator.setStartDelay(delay);
    249         mAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
    250         mAlphaAnimator.setDuration(duration);
    251         mAlphaAnimator.start();
    252         if (postAnimRunnable != null) {
    253             mAlphaAnimator.addListener(new AnimatorListenerAdapter() {
    254                 public boolean mCancelled;
    255 
    256                 @Override
    257                 public void onAnimationCancel(Animator animation) {
    258                     mCancelled = true;
    259                 }
    260 
    261                 @Override
    262                 public void onAnimationEnd(Animator animation) {
    263                     if (!mCancelled) {
    264                         postAnimRunnable.run();
    265                     }
    266                 }
    267             });
    268         }
    269     }
    270 }
    271