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.misc.Utilities;
     37 import com.android.systemui.recents.model.Task;
     38 
     39 
     40 /**
     41  * The task thumbnail view.  It implements an image view that allows for animating the dim and
     42  * alpha of the thumbnail image.
     43  */
     44 public class TaskViewThumbnail extends View {
     45 
     46     RecentsConfiguration mConfig;
     47 
     48     // Drawing
     49     float mDimAlpha;
     50     Matrix mScaleMatrix = new Matrix();
     51     Paint mDrawPaint = new Paint();
     52     RectF mBitmapRect = new RectF();
     53     RectF mLayoutRect = new RectF();
     54     BitmapShader mBitmapShader;
     55     LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
     56 
     57     // Thumbnail alpha
     58     float mThumbnailAlpha;
     59     ValueAnimator mThumbnailAlphaAnimator;
     60     ValueAnimator.AnimatorUpdateListener mThumbnailAlphaUpdateListener
     61             = new ValueAnimator.AnimatorUpdateListener() {
     62         @Override
     63         public void onAnimationUpdate(ValueAnimator animation) {
     64             mThumbnailAlpha = (float) animation.getAnimatedValue();
     65             updateThumbnailPaintFilter();
     66         }
     67     };
     68 
     69     // Task bar clipping, the top of this thumbnail can be clipped against the opaque header
     70     // bar that overlaps this thumbnail
     71     View mTaskBar;
     72     Rect mClipRect = new Rect();
     73 
     74     // Visibility optimization, if the thumbnail height is less than the height of the header
     75     // bar for the task view, then just mark this thumbnail view as invisible
     76     boolean mInvisible;
     77 
     78     public TaskViewThumbnail(Context context) {
     79         this(context, null);
     80     }
     81 
     82     public TaskViewThumbnail(Context context, AttributeSet attrs) {
     83         this(context, attrs, 0);
     84     }
     85 
     86     public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr) {
     87         this(context, attrs, defStyleAttr, 0);
     88     }
     89 
     90     public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     91         super(context, attrs, defStyleAttr, defStyleRes);
     92         mConfig = RecentsConfiguration.getInstance();
     93         mDrawPaint.setColorFilter(mLightingColorFilter);
     94         mDrawPaint.setFilterBitmap(true);
     95         mDrawPaint.setAntiAlias(true);
     96     }
     97 
     98     @Override
     99     protected void onFinishInflate() {
    100         mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
    101         updateThumbnailPaintFilter();
    102     }
    103 
    104     @Override
    105     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    106         super.onLayout(changed, left, top, right, bottom);
    107         if (changed) {
    108             mLayoutRect.set(0, 0, getWidth(), getHeight());
    109             updateThumbnailScale();
    110         }
    111     }
    112 
    113     @Override
    114     protected void onDraw(Canvas canvas) {
    115         if (mInvisible) {
    116             return;
    117         }
    118         // Draw the thumbnail with the rounded corners
    119         canvas.drawRoundRect(0, 0, getWidth(), getHeight(),
    120                 mConfig.taskViewRoundedCornerRadiusPx,
    121                 mConfig.taskViewRoundedCornerRadiusPx, mDrawPaint);
    122     }
    123 
    124     /** Sets the thumbnail to a given bitmap. */
    125     void setThumbnail(Bitmap bm) {
    126         if (bm != null) {
    127             mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP,
    128                     Shader.TileMode.CLAMP);
    129             mDrawPaint.setShader(mBitmapShader);
    130             mBitmapRect.set(0, 0, bm.getWidth(), bm.getHeight());
    131             updateThumbnailScale();
    132         } else {
    133             mBitmapShader = null;
    134             mDrawPaint.setShader(null);
    135         }
    136         updateThumbnailPaintFilter();
    137     }
    138 
    139     /** Updates the paint to draw the thumbnail. */
    140     void updateThumbnailPaintFilter() {
    141         if (mInvisible) {
    142             return;
    143         }
    144         int mul = (int) ((1.0f - mDimAlpha) * mThumbnailAlpha * 255);
    145         int add = (int) ((1.0f - mDimAlpha) * (1 - mThumbnailAlpha) * 255);
    146         if (mBitmapShader != null) {
    147             mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul));
    148             mLightingColorFilter.setColorAdd(Color.argb(0, add, add, add));
    149             mDrawPaint.setColorFilter(mLightingColorFilter);
    150             mDrawPaint.setColor(0xffffffff);
    151         } else {
    152             int grey = mul + add;
    153             mDrawPaint.setColorFilter(null);
    154             mDrawPaint.setColor(Color.argb(255, grey, grey, grey));
    155         }
    156         invalidate();
    157     }
    158 
    159     /** Updates the thumbnail shader's scale transform. */
    160     void updateThumbnailScale() {
    161         if (mBitmapShader != null) {
    162             mScaleMatrix.setRectToRect(mBitmapRect, mLayoutRect, Matrix.ScaleToFit.FILL);
    163             mBitmapShader.setLocalMatrix(mScaleMatrix);
    164         }
    165     }
    166 
    167     /** Updates the clip rect based on the given task bar. */
    168     void updateClipToTaskBar(View taskBar) {
    169         mTaskBar = taskBar;
    170         int top = (int) Math.max(0, taskBar.getTranslationY() +
    171                 taskBar.getMeasuredHeight() - 1);
    172         mClipRect.set(0, top, getMeasuredWidth(), getMeasuredHeight());
    173         setClipBounds(mClipRect);
    174     }
    175 
    176     /** Updates the visibility of the the thumbnail. */
    177     void updateThumbnailVisibility(int clipBottom) {
    178         boolean invisible = mTaskBar != null && (getHeight() - clipBottom) <= mTaskBar.getHeight();
    179         if (invisible != mInvisible) {
    180             mInvisible = invisible;
    181             if (!mInvisible) {
    182                 updateThumbnailPaintFilter();
    183             }
    184             invalidate();
    185         }
    186     }
    187 
    188     /**
    189      * Sets the dim alpha, only used when we are not using hardware layers.
    190      * (see RecentsConfiguration.useHardwareLayers)
    191      */
    192     public void setDimAlpha(float dimAlpha) {
    193         mDimAlpha = dimAlpha;
    194         updateThumbnailPaintFilter();
    195     }
    196 
    197     /** Binds the thumbnail view to the task */
    198     void rebindToTask(Task t) {
    199         if (t.thumbnail != null) {
    200             setThumbnail(t.thumbnail);
    201         } else {
    202             setThumbnail(null);
    203         }
    204     }
    205 
    206     /** Unbinds the thumbnail view from the task */
    207     void unbindFromTask() {
    208         setThumbnail(null);
    209     }
    210 
    211     /** Handles focus changes. */
    212     void onFocusChanged(boolean focused) {
    213         if (focused) {
    214             if (Float.compare(getAlpha(), 1f) != 0) {
    215                 startFadeAnimation(1f, 0, 150, null);
    216             }
    217         } else {
    218             if (Float.compare(getAlpha(), mConfig.taskViewThumbnailAlpha) != 0) {
    219                 startFadeAnimation(mConfig.taskViewThumbnailAlpha, 0, 150, null);
    220             }
    221         }
    222     }
    223 
    224     /**
    225      * Prepares for the enter recents animation, this gets called before the the view
    226      * is first visible and will be followed by a startEnterRecentsAnimation() call.
    227      */
    228     void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask) {
    229         if (isTaskViewLaunchTargetTask) {
    230             mThumbnailAlpha = 1f;
    231         } else {
    232             mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
    233         }
    234         updateThumbnailPaintFilter();
    235     }
    236 
    237     /** Animates this task thumbnail as it enters Recents. */
    238     void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
    239         startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay,
    240                 mConfig.taskViewEnterFromAppDuration, postAnimRunnable);
    241     }
    242 
    243     /** Animates this task thumbnail as it exits Recents. */
    244     void startLaunchTaskAnimation(Runnable postAnimRunnable) {
    245         startFadeAnimation(1f, 0, mConfig.taskViewExitToAppDuration, postAnimRunnable);
    246     }
    247 
    248     /** Starts a new thumbnail alpha animation. */
    249     void startFadeAnimation(float finalAlpha, int delay, int duration, final Runnable postAnimRunnable) {
    250         Utilities.cancelAnimationWithoutCallbacks(mThumbnailAlphaAnimator);
    251         mThumbnailAlphaAnimator = ValueAnimator.ofFloat(mThumbnailAlpha, finalAlpha);
    252         mThumbnailAlphaAnimator.setStartDelay(delay);
    253         mThumbnailAlphaAnimator.setDuration(duration);
    254         mThumbnailAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
    255         mThumbnailAlphaAnimator.addUpdateListener(mThumbnailAlphaUpdateListener);
    256         if (postAnimRunnable != null) {
    257             mThumbnailAlphaAnimator.addListener(new AnimatorListenerAdapter() {
    258                 @Override
    259                 public void onAnimationEnd(Animator animation) {
    260                     postAnimRunnable.run();
    261                 }
    262             });
    263         }
    264         mThumbnailAlphaAnimator.start();
    265     }
    266 }
    267