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