1de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/* 2de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * Copyright (C) 2014 The Android Open Source Project 3de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * 4de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * Licensed under the Apache License, Version 2.0 (the "License"); 5de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * you may not use this file except in compliance with the License. 6de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * You may obtain a copy of the License at 7de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * 8de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * http://www.apache.org/licenses/LICENSE-2.0 9de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * 10de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * Unless required by applicable law or agreed to in writing, software 11de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * distributed under the License is distributed on an "AS IS" BASIS, 12de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * See the License for the specific language governing permissions and 14de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * limitations under the License. 15de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar */ 16de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 17de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarpackage com.android.systemui.recents.views; 18de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 19de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.content.Context; 20de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.content.res.Configuration; 21de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.content.res.Resources; 22de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.Bitmap; 23de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.BitmapShader; 24de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.Canvas; 25de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.Color; 26de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.ColorMatrix; 27de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.ColorMatrixColorFilter; 28de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.LightingColorFilter; 29de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.Matrix; 30de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.Paint; 31de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.Rect; 32de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.graphics.Shader; 33de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.util.AttributeSet; 34de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.view.View; 35de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport android.view.ViewDebug; 36de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 37de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport com.android.systemui.R; 38de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport com.android.systemui.recents.events.EventBus; 39de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent; 40de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport com.android.systemui.recents.misc.Utilities; 41de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport com.android.systemui.recents.model.Task; 42de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport com.android.systemui.recents.model.ThumbnailData; 43de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarimport java.io.PrintWriter; 44de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 45de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 46de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/** 47de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * The task thumbnail view. It implements an image view that allows for animating the dim and 48de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * alpha of the thumbnail image. 49de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar */ 50de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarpublic class TaskViewThumbnail extends View { 51de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 52de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private static final ColorMatrix TMP_FILTER_COLOR_MATRIX = new ColorMatrix(); 53de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private static final ColorMatrix TMP_BRIGHTNESS_COLOR_MATRIX = new ColorMatrix(); 54de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 55de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private Task mTask; 56de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 57de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private int mDisplayOrientation = Configuration.ORIENTATION_UNDEFINED; 58de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private Rect mDisplayRect = new Rect(); 59de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 60de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar // Drawing 61de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar @ViewDebug.ExportedProperty(category="recents") 62de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar protected Rect mTaskViewRect = new Rect(); 63de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar @ViewDebug.ExportedProperty(category="recents") 64de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar protected Rect mThumbnailRect = new Rect(); 65de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar @ViewDebug.ExportedProperty(category="recents") 66de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar protected float mThumbnailScale; 67de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private float mFullscreenThumbnailScale = 1f; 68de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar /** The height, in pixels, of the task view's title bar. */ 69de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private int mTitleBarHeight; 70de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private boolean mSizeToFit = false; 71de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private boolean mOverlayHeaderOnThumbnailActionBar = true; 72de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private ThumbnailData mThumbnailData; 73de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 74de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar protected int mCornerRadius; 75de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar @ViewDebug.ExportedProperty(category="recents") 76de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private float mDimAlpha; 77de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private Matrix mMatrix = new Matrix(); 78de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private Paint mDrawPaint = new Paint(); 79de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar protected Paint mLockedPaint = new Paint(); 80de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar protected Paint mBgFillPaint = new Paint(); 81de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar protected BitmapShader mBitmapShader; 82de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar protected boolean mUserLocked = false; 83de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0); 84de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 85de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar // Clip the top of the thumbnail against the opaque header bar that overlaps this view 86de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private View mTaskBar; 87de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 88de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar // Visibility optimization, if the thumbnail height is less than the height of the header 89de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar // bar for the task view, then just mark this thumbnail view as invisible 90de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar @ViewDebug.ExportedProperty(category="recents") 91de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private boolean mInvisible; 92de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 93de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar @ViewDebug.ExportedProperty(category="recents") 94de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar private boolean mDisabledInSafeMode; 95de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 96de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar public TaskViewThumbnail(Context context) { 97de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar this(context, null); 98de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar } 99de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 100de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar public TaskViewThumbnail(Context context, AttributeSet attrs) { 101de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar this(context, attrs, 0); 102de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar } 103de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 104de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr) { 105de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar this(context, attrs, defStyleAttr, 0); 106de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar } 107de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 108de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 109de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar super(context, attrs, defStyleAttr, defStyleRes); 110de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar mDrawPaint.setColorFilter(mLightingColorFilter); 111de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar mDrawPaint.setFilterBitmap(true); 112de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar mDrawPaint.setAntiAlias(true); 113de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar Resources res = getResources(); 114de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar mCornerRadius = res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); 115de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar mBgFillPaint.setColor(Color.WHITE); 116de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar mLockedPaint.setColor(Color.WHITE); 117de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar mTitleBarHeight = res.getDimensionPixelSize(R.dimen.recents_grid_task_view_header_height); 118de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar } 119de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 120de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar /** 121de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * Called when the task view frame changes, allowing us to move the contents of the header 122de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar * to match the frame changes. 123de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar */ 124de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar public void onTaskViewSizeChanged(int width, int height) { 125de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar // Return early if the bounds have not changed 126de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar if (mTaskViewRect.width() == width && mTaskViewRect.height() == height) { 127de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar return; 128de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar } 129de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 130de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar mTaskViewRect.set(0, 0, width, height); 131de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar setLeftTopRightBottom(0, 0, width, height); 132de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar updateThumbnailMatrix(); 133de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar } 134de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 135de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar @Override 136de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar protected void onDraw(Canvas canvas) { 137de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar if (mInvisible) { 138de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar return; 139de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar } 140de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 141de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar int viewWidth = mTaskViewRect.width(); 142de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar int viewHeight = mTaskViewRect.height(); 143de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar int thumbnailWidth = Math.min(viewWidth, 144de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar (int) (mThumbnailRect.width() * mThumbnailScale)); 145de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar int thumbnailHeight = Math.min(viewHeight, 146de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar (int) (mThumbnailRect.height() * mThumbnailScale)); 147de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 148de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar if (mUserLocked) { 149de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius, 150 mLockedPaint); 151 } else if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) { 152 int topOffset = 0; 153 if (mTaskBar != null && mOverlayHeaderOnThumbnailActionBar) { 154 topOffset = mTaskBar.getHeight() - mCornerRadius; 155 } 156 157 // Draw the background, there will be some small overdraw with the thumbnail 158 if (thumbnailWidth < viewWidth) { 159 // Portrait thumbnail on a landscape task view 160 canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), topOffset, 161 viewWidth, viewHeight, 162 mCornerRadius, mCornerRadius, mBgFillPaint); 163 } 164 if (thumbnailHeight < viewHeight) { 165 // Landscape thumbnail on a portrait task view 166 canvas.drawRoundRect(0, Math.max(topOffset, thumbnailHeight - mCornerRadius), 167 viewWidth, viewHeight, 168 mCornerRadius, mCornerRadius, mBgFillPaint); 169 } 170 171 // Draw the thumbnail 172 canvas.drawRoundRect(0, topOffset, thumbnailWidth, thumbnailHeight, 173 mCornerRadius, mCornerRadius, mDrawPaint); 174 } else { 175 canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius, 176 mBgFillPaint); 177 } 178 } 179 180 /** Sets the thumbnail to a given bitmap. */ 181 void setThumbnail(ThumbnailData thumbnailData) { 182 if (thumbnailData != null && thumbnailData.thumbnail != null) { 183 Bitmap bm = thumbnailData.thumbnail; 184 bm.prepareToDraw(); 185 mFullscreenThumbnailScale = thumbnailData.scale; 186 mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 187 mDrawPaint.setShader(mBitmapShader); 188 mThumbnailRect.set(0, 0, 189 bm.getWidth() - thumbnailData.insets.left - thumbnailData.insets.right, 190 bm.getHeight() - thumbnailData.insets.top - thumbnailData.insets.bottom); 191 mThumbnailData = thumbnailData; 192 updateThumbnailMatrix(); 193 updateThumbnailPaintFilter(); 194 } else { 195 mBitmapShader = null; 196 mDrawPaint.setShader(null); 197 mThumbnailRect.setEmpty(); 198 mThumbnailData = null; 199 } 200 } 201 202 /** Updates the paint to draw the thumbnail. */ 203 void updateThumbnailPaintFilter() { 204 if (mInvisible) { 205 return; 206 } 207 int mul = (int) ((1.0f - mDimAlpha) * 255); 208 if (mBitmapShader != null) { 209 if (mDisabledInSafeMode) { 210 // Brightness: C-new = C-old*(1-amount) + amount 211 TMP_FILTER_COLOR_MATRIX.setSaturation(0); 212 float scale = 1f - mDimAlpha; 213 float[] mat = TMP_BRIGHTNESS_COLOR_MATRIX.getArray(); 214 mat[0] = scale; 215 mat[6] = scale; 216 mat[12] = scale; 217 mat[4] = mDimAlpha * 255f; 218 mat[9] = mDimAlpha * 255f; 219 mat[14] = mDimAlpha * 255f; 220 TMP_FILTER_COLOR_MATRIX.preConcat(TMP_BRIGHTNESS_COLOR_MATRIX); 221 ColorMatrixColorFilter filter = new ColorMatrixColorFilter(TMP_FILTER_COLOR_MATRIX); 222 mDrawPaint.setColorFilter(filter); 223 mBgFillPaint.setColorFilter(filter); 224 mLockedPaint.setColorFilter(filter); 225 } else { 226 mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul)); 227 mDrawPaint.setColorFilter(mLightingColorFilter); 228 mDrawPaint.setColor(0xFFffffff); 229 mBgFillPaint.setColorFilter(mLightingColorFilter); 230 mLockedPaint.setColorFilter(mLightingColorFilter); 231 } 232 } else { 233 int grey = mul; 234 mDrawPaint.setColorFilter(null); 235 mDrawPaint.setColor(Color.argb(255, grey, grey, grey)); 236 } 237 if (!mInvisible) { 238 invalidate(); 239 } 240 } 241 242 /** 243 * Updates the scale of the bitmap relative to this view. 244 */ 245 public void updateThumbnailMatrix() { 246 mThumbnailScale = 1f; 247 if (mBitmapShader != null && mThumbnailData != null) { 248 // We consider this a stack task if it is not freeform (ie. has no bounds) or has been 249 // dragged into the stack from the freeform workspace 250 boolean isStackTask = !mTask.isFreeformTask() || mTask.bounds == null; 251 int xOffset, yOffset = 0; 252 if (mTaskViewRect.isEmpty()) { 253 // If we haven't measured , skip the thumbnail drawing and only draw the background 254 // color 255 mThumbnailScale = 0f; 256 } else if (mSizeToFit) { 257 // Make sure we fill the entire space regardless of the orientation. 258 float viewAspectRatio = (float) mTaskViewRect.width() / 259 (float) (mTaskViewRect.height() - mTitleBarHeight); 260 float thumbnailAspectRatio = 261 (float) mThumbnailRect.width() / (float) mThumbnailRect.height(); 262 if (viewAspectRatio > thumbnailAspectRatio) { 263 mThumbnailScale = 264 (float) mTaskViewRect.width() / (float) mThumbnailRect.width(); 265 } else { 266 mThumbnailScale = (float) (mTaskViewRect.height() - mTitleBarHeight) 267 / (float) mThumbnailRect.height(); 268 } 269 } else if (isStackTask) { 270 float invThumbnailScale = 1f / mFullscreenThumbnailScale; 271 if (mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT) { 272 if (mThumbnailData.orientation == Configuration.ORIENTATION_PORTRAIT) { 273 // If we are in the same orientation as the screenshot, just scale it to the 274 // width of the task view 275 mThumbnailScale = (float) mTaskViewRect.width() / mThumbnailRect.width(); 276 } else { 277 // Scale the landscape thumbnail up to app size, then scale that to the task 278 // view size to match other portrait screenshots 279 mThumbnailScale = invThumbnailScale * 280 ((float) mTaskViewRect.width() / mDisplayRect.width()); 281 } 282 } else { 283 // Otherwise, scale the screenshot to fit 1:1 in the current orientation 284 mThumbnailScale = invThumbnailScale; 285 } 286 } else { 287 // Otherwise, if this is a freeform task with task bounds, then scale the thumbnail 288 // to fit the entire bitmap into the task bounds 289 mThumbnailScale = Math.min( 290 (float) mTaskViewRect.width() / mThumbnailRect.width(), 291 (float) mTaskViewRect.height() / mThumbnailRect.height()); 292 } 293 mMatrix.setTranslate(-mThumbnailData.insets.left * mFullscreenThumbnailScale, 294 -mThumbnailData.insets.top * mFullscreenThumbnailScale); 295 mMatrix.postScale(mThumbnailScale, mThumbnailScale); 296 mBitmapShader.setLocalMatrix(mMatrix); 297 } 298 if (!mInvisible) { 299 invalidate(); 300 } 301 } 302 303 /** Sets whether the thumbnail should be resized to fit the task view in all orientations. */ 304 public void setSizeToFit(boolean flag) { 305 mSizeToFit = flag; 306 } 307 308 /** 309 * Sets whether the header should overlap (and hide) the action bar in the thumbnail, or 310 * be stacked just above it. 311 */ 312 public void setOverlayHeaderOnThumbnailActionBar(boolean flag) { 313 mOverlayHeaderOnThumbnailActionBar = flag; 314 } 315 316 /** Updates the clip rect based on the given task bar. */ 317 void updateClipToTaskBar(View taskBar) { 318 mTaskBar = taskBar; 319 invalidate(); 320 } 321 322 /** Updates the visibility of the the thumbnail. */ 323 void updateThumbnailVisibility(int clipBottom) { 324 boolean invisible = mTaskBar != null && (getHeight() - clipBottom) <= mTaskBar.getHeight(); 325 if (invisible != mInvisible) { 326 mInvisible = invisible; 327 if (!mInvisible) { 328 updateThumbnailPaintFilter(); 329 } 330 } 331 } 332 333 /** 334 * Sets the dim alpha, only used when we are not using hardware layers. 335 * (see RecentsConfiguration.useHardwareLayers) 336 */ 337 public void setDimAlpha(float dimAlpha) { 338 mDimAlpha = dimAlpha; 339 updateThumbnailPaintFilter(); 340 } 341 342 /** 343 * Returns the {@link Paint} used to draw a task screenshot, or {@link #mLockedPaint} if the 344 * thumbnail shouldn't be drawn because it belongs to a locked user. 345 */ 346 protected Paint getDrawPaint() { 347 if (mUserLocked) { 348 return mLockedPaint; 349 } 350 return mDrawPaint; 351 } 352 353 /** 354 * Binds the thumbnail view to the task. 355 */ 356 void bindToTask(Task t, boolean disabledInSafeMode, int displayOrientation, Rect displayRect) { 357 mTask = t; 358 mDisabledInSafeMode = disabledInSafeMode; 359 mDisplayOrientation = displayOrientation; 360 mDisplayRect.set(displayRect); 361 if (t.colorBackground != 0) { 362 mBgFillPaint.setColor(t.colorBackground); 363 } 364 if (t.colorPrimary != 0) { 365 mLockedPaint.setColor(t.colorPrimary); 366 } 367 mUserLocked = t.isLocked; 368 EventBus.getDefault().register(this); 369 } 370 371 /** 372 * Called when the bound task's data has loaded and this view should update to reflect the 373 * changes. 374 */ 375 void onTaskDataLoaded(ThumbnailData thumbnailData) { 376 setThumbnail(thumbnailData); 377 } 378 379 /** Unbinds the thumbnail view from the task */ 380 void unbindFromTask() { 381 mTask = null; 382 setThumbnail(null); 383 EventBus.getDefault().unregister(this); 384 } 385 386 public final void onBusEvent(TaskSnapshotChangedEvent event) { 387 if (mTask == null || event.taskId != mTask.key.id || event.thumbnailData == null 388 || event.thumbnailData.thumbnail == null) { 389 return; 390 } 391 setThumbnail(event.thumbnailData); 392 } 393 394 public void dump(String prefix, PrintWriter writer) { 395 writer.print(prefix); writer.print("TaskViewThumbnail"); 396 writer.print(" mTaskViewRect="); writer.print(Utilities.dumpRect(mTaskViewRect)); 397 writer.print(" mThumbnailRect="); writer.print(Utilities.dumpRect(mThumbnailRect)); 398 writer.print(" mThumbnailScale="); writer.print(mThumbnailScale); 399 writer.print(" mDimAlpha="); writer.print(mDimAlpha); 400 writer.println(); 401 } 402} 403