1 /* 2 * Copyright (C) 2017 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.grid; 18 19 import android.content.Context; 20 import android.graphics.Canvas; 21 import android.graphics.Path; 22 import android.util.AttributeSet; 23 24 import com.android.systemui.R; 25 import com.android.systemui.recents.views.TaskViewThumbnail; 26 27 public class GridTaskViewThumbnail extends TaskViewThumbnail { 28 29 private Path mThumbnailOutline; 30 private Path mRestBackgroundOutline; 31 // True if either this view's size or thumbnail scale has changed and mThumbnailOutline should 32 // be updated. 33 private boolean mUpdateThumbnailOutline = true; 34 GridTaskViewThumbnail(Context context)35 public GridTaskViewThumbnail(Context context) { 36 this(context, null); 37 } 38 GridTaskViewThumbnail(Context context, AttributeSet attrs)39 public GridTaskViewThumbnail(Context context, AttributeSet attrs) { 40 this(context, attrs, 0); 41 } 42 GridTaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr)43 public GridTaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr) { 44 this(context, attrs, defStyleAttr, 0); 45 } 46 GridTaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)47 public GridTaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, 48 int defStyleRes) { 49 super(context, attrs, defStyleAttr, defStyleRes); 50 mCornerRadius = getResources().getDimensionPixelSize( 51 R.dimen.recents_grid_task_view_rounded_corners_radius); 52 } 53 54 /** 55 * Called when the task view frame changes, allowing us to move the contents of the header 56 * to match the frame changes. 57 */ onTaskViewSizeChanged(int width, int height)58 public void onTaskViewSizeChanged(int width, int height) { 59 mUpdateThumbnailOutline = true; 60 super.onTaskViewSizeChanged(width, height); 61 } 62 63 /** 64 * Updates the scale of the bitmap relative to this view. 65 */ updateThumbnailMatrix()66 public void updateThumbnailMatrix() { 67 mUpdateThumbnailOutline = true; 68 super.updateThumbnailMatrix(); 69 } 70 updateThumbnailOutline()71 private void updateThumbnailOutline() { 72 final int titleHeight = getResources().getDimensionPixelSize( 73 R.dimen.recents_grid_task_view_header_height); 74 final int viewWidth = mTaskViewRect.width(); 75 final int viewHeight = mTaskViewRect.height() - titleHeight; 76 final int thumbnailWidth = Math.min(viewWidth, 77 (int) (mThumbnailRect.width() * mThumbnailScale)); 78 final int thumbnailHeight = Math.min(viewHeight, 79 (int) (mThumbnailRect.height() * mThumbnailScale)); 80 // Draw the thumbnail, we only round the bottom corners: 81 // 82 // outerLeft outerRight 83 // <-----------------------> mRestBackgroundOutline 84 // _________________________ (thumbnailWidth < viewWidth) 85 // |_______________________| outerTop A ____ B 86 // | | ↑ | | 87 // | | | | | 88 // | | | | | 89 // | | | | | C 90 // \_______________________/ ↓ |__/ 91 // mCornerRadius outerBottom E D 92 // 93 // mRestBackgroundOutline (thumbnailHeight < viewHeight) 94 // A _________________________ B 95 // | | C 96 // F \_______________________/ 97 // E D 98 final int outerLeft = 0; 99 final int outerTop = 0; 100 final int outerRight = outerLeft + thumbnailWidth; 101 final int outerBottom = outerTop + thumbnailHeight; 102 mThumbnailOutline = new Path(); 103 mThumbnailOutline.moveTo(outerLeft, outerTop); 104 mThumbnailOutline.lineTo(outerRight, outerTop); 105 mThumbnailOutline.lineTo(outerRight, outerBottom - mCornerRadius); 106 mThumbnailOutline.arcTo(outerRight - 2 * mCornerRadius, outerBottom - 2 * mCornerRadius, 107 outerRight, outerBottom, 0, 90, false); 108 mThumbnailOutline.lineTo(outerLeft + mCornerRadius, outerBottom); 109 mThumbnailOutline.arcTo(outerLeft, outerBottom - 2 * mCornerRadius, 110 outerLeft + 2 * mCornerRadius, outerBottom, 90, 90, false); 111 mThumbnailOutline.lineTo(outerLeft, outerTop); 112 mThumbnailOutline.close(); 113 114 if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) { 115 if (thumbnailWidth < viewWidth) { 116 final int l = Math.max(0, outerRight - mCornerRadius); 117 final int r = outerRight; 118 final int t = outerTop; 119 final int b = outerBottom; 120 mRestBackgroundOutline = new Path(); 121 mRestBackgroundOutline.moveTo(l, t); // A 122 mRestBackgroundOutline.lineTo(r, t); // B 123 mRestBackgroundOutline.lineTo(r, b - mCornerRadius); // C 124 mRestBackgroundOutline.arcTo(r - 2 * mCornerRadius, b - 2 * mCornerRadius, r, b, 125 0, 90, false); // D 126 mRestBackgroundOutline.lineTo(l, b); // E 127 mRestBackgroundOutline.lineTo(l, t); // A 128 mRestBackgroundOutline.close(); 129 130 } 131 if (thumbnailHeight < viewHeight) { 132 final int l = outerLeft; 133 final int r = outerRight; 134 final int t = Math.max(0, thumbnailHeight - mCornerRadius); 135 final int b = outerBottom; 136 mRestBackgroundOutline = new Path(); 137 mRestBackgroundOutline.moveTo(l, t); // A 138 mRestBackgroundOutline.lineTo(r, t); // B 139 mRestBackgroundOutline.lineTo(r, b - mCornerRadius); // C 140 mRestBackgroundOutline.arcTo(r - 2 * mCornerRadius, b - 2 * mCornerRadius, r, b, 141 0, 90, false); // D 142 mRestBackgroundOutline.lineTo(l + mCornerRadius, b); // E 143 mRestBackgroundOutline.arcTo(l, b - 2 * mCornerRadius, l + 2 * mCornerRadius, b, 144 90, 90, false); // F 145 mRestBackgroundOutline.lineTo(l, t); // A 146 mRestBackgroundOutline.close(); 147 } 148 } 149 } 150 151 @Override onDraw(Canvas canvas)152 protected void onDraw(Canvas canvas) { 153 final int titleHeight = getResources().getDimensionPixelSize( 154 R.dimen.recents_grid_task_view_header_height); 155 final int viewWidth = mTaskViewRect.width(); 156 final int viewHeight = mTaskViewRect.height() - titleHeight; 157 final int thumbnailWidth = Math.min(viewWidth, 158 (int) (mThumbnailRect.width() * mThumbnailScale)); 159 final int thumbnailHeight = Math.min(viewHeight, 160 (int) (mThumbnailRect.height() * mThumbnailScale)); 161 162 if (mUpdateThumbnailOutline) { 163 updateThumbnailOutline(); 164 mUpdateThumbnailOutline = false; 165 } 166 167 if (mUserLocked) { 168 canvas.drawPath(mThumbnailOutline, mLockedPaint); 169 } else if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) { 170 // Draw the background, there will be some small overdraw with the thumbnail 171 if (thumbnailWidth < viewWidth) { 172 // Portrait thumbnail on a landscape task view 173 canvas.drawPath(mRestBackgroundOutline, mBgFillPaint); 174 } 175 if (thumbnailHeight < viewHeight) { 176 // Landscape thumbnail on a portrait task view 177 canvas.drawPath(mRestBackgroundOutline, mBgFillPaint); 178 } 179 canvas.drawPath(mThumbnailOutline, getDrawPaint()); 180 } else { 181 canvas.drawPath(mThumbnailOutline, mBgFillPaint); 182 } 183 } 184 } 185