TaskViewThumbnail.java revision bf5dbf1c151eb64f4068f233e72b0a867348bf8c
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
17package com.android.systemui.recents.views;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ValueAnimator;
22import android.content.Context;
23import android.graphics.Bitmap;
24import android.graphics.BitmapShader;
25import android.graphics.Canvas;
26import android.graphics.Color;
27import android.graphics.LightingColorFilter;
28import android.graphics.Matrix;
29import android.graphics.Paint;
30import android.graphics.Rect;
31import android.graphics.RectF;
32import android.graphics.Shader;
33import android.util.AttributeSet;
34import android.view.View;
35import com.android.systemui.recents.RecentsConfiguration;
36import com.android.systemui.recents.model.Task;
37
38
39/** The task thumbnail view */
40public 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