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