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
17package com.android.systemui.recents.views.grid;
18
19import android.content.Context;
20import android.graphics.Canvas;
21import android.graphics.Path;
22import android.util.AttributeSet;
23
24import com.android.systemui.R;
25import com.android.systemui.recents.views.TaskViewThumbnail;
26
27public 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
35    public GridTaskViewThumbnail(Context context) {
36        this(context, null);
37    }
38
39    public GridTaskViewThumbnail(Context context, AttributeSet attrs) {
40        this(context, attrs, 0);
41    }
42
43    public GridTaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr) {
44        this(context, attrs, defStyleAttr, 0);
45    }
46
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     */
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     */
66    public void updateThumbnailMatrix() {
67        mUpdateThumbnailOutline = true;
68        super.updateThumbnailMatrix();
69    }
70
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
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