From 90f4f5290b971aefcf7cab306b3e95168ed53585 Mon Sep 17 00:00:00 2001 From: Jiaquan He Date: Mon, 9 Jan 2017 15:50:35 -0800 Subject: [PATCH] 2D Recents: round task thumbnails properly. Test: Checked that on local sw600dp devices, task views are rounded with 8dp. Also checked that Recents works properly on phones. Bug: 32101881 Change-Id: I6f7a09a12c3e3f1f7270bed1ae25b291fadfb8f2 --- ..._grid_task_view_focus_frame_background.xml | 2 +- .../res/layout/recents_grid_task_view.xml | 2 +- packages/SystemUI/res/values/dimens_grid.xml | 1 + .../recents/views/FakeShadowDrawable.java | 7 +- .../systemui/recents/views/TaskStackView.java | 5 +- .../recents/views/TaskViewHeader.java | 4 +- .../recents/views/TaskViewThumbnail.java | 14 +- .../views/grid/GridTaskViewThumbnail.java | 185 ++++++++++++++++++ .../views/grid/TaskGridLayoutAlgorithm.java | 6 +- 9 files changed, 210 insertions(+), 16 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java diff --git a/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml index a85beb8b68c88..ea03a50e44600 100644 --- a/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml +++ b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml @@ -15,5 +15,5 @@ --> - + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/recents_grid_task_view.xml b/packages/SystemUI/res/layout/recents_grid_task_view.xml index 53bec70bd096c..1c9b9ac5f5f23 100644 --- a/packages/SystemUI/res/layout/recents_grid_task_view.xml +++ b/packages/SystemUI/res/layout/recents_grid_task_view.xml @@ -18,7 +18,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true"> - diff --git a/packages/SystemUI/res/values/dimens_grid.xml b/packages/SystemUI/res/values/dimens_grid.xml index 0b9836ffcebb8..5858443f6d8d4 100644 --- a/packages/SystemUI/res/values/dimens_grid.xml +++ b/packages/SystemUI/res/values/dimens_grid.xml @@ -22,5 +22,6 @@ 44dp 8dp 8dp + 8dp diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java index d64a676005134..79a774f7fba06 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java @@ -30,6 +30,7 @@ import android.graphics.drawable.Drawable; import android.util.Log; import com.android.systemui.R; +import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsConfiguration; /** @@ -90,8 +91,10 @@ class FakeShadowDrawable extends Drawable { mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); mCornerShadowPaint.setStyle(Paint.Style.FILL); mCornerShadowPaint.setDither(true); - mCornerRadius = resources.getDimensionPixelSize( - R.dimen.recents_task_view_rounded_corners_radius); + mCornerRadius = Recents.getConfiguration().isGridEnabled ? + resources.getDimensionPixelSize( + R.dimen.recents_grid_task_view_rounded_corners_radius) : + resources.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); mCardBounds = new RectF(); mEdgeShadowPaint = new Paint(mCornerShadowPaint); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 3cd681c27a93e..c621918929bc5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -266,8 +266,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm); mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller); mAnimationHelper = new TaskStackAnimationHelper(context, this); - mTaskCornerRadiusPx = res.getDimensionPixelSize( - R.dimen.recents_task_view_rounded_corners_radius); + mTaskCornerRadiusPx = Recents.getConfiguration().isGridEnabled ? + res.getDimensionPixelSize(R.dimen.recents_grid_task_view_rounded_corners_radius) : + res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); mDividerSize = ssp.getDockedDividerSize(context); mDisplayOrientation = Utilities.getAppConfiguration(mContext).orientation; mDisplayRect = ssp.getDisplayRect(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java index c0cc83fa0243a..0777163293d93 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -201,7 +201,9 @@ public class TaskViewHeader extends FrameLayout Resources res = context.getResources(); mLightDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_light); mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark); - mCornerRadius = res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); + mCornerRadius = Recents.getConfiguration().isGridEnabled ? + res.getDimensionPixelSize(R.dimen.recents_grid_task_view_rounded_corners_radius) : + res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); mHighlightHeight = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight); mTaskBarViewLightTextColor = context.getColor(R.color.recents_task_bar_light_text_color); mTaskBarViewDarkTextColor = context.getColor(R.color.recents_task_bar_dark_text_color); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java index 9069e5aa54cf8..83e2eb124bf78 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -58,11 +58,11 @@ public class TaskViewThumbnail extends View { // Drawing @ViewDebug.ExportedProperty(category="recents") - private Rect mTaskViewRect = new Rect(); + protected Rect mTaskViewRect = new Rect(); @ViewDebug.ExportedProperty(category="recents") - private Rect mThumbnailRect = new Rect(); + protected Rect mThumbnailRect = new Rect(); @ViewDebug.ExportedProperty(category="recents") - private float mThumbnailScale; + protected float mThumbnailScale; private float mFullscreenThumbnailScale; /** The height, in pixels, of the task view's title bar. */ private int mTitleBarHeight; @@ -70,13 +70,13 @@ public class TaskViewThumbnail extends View { private boolean mOverlayHeaderOnThumbnailActionBar = true; private ActivityManager.TaskThumbnailInfo mThumbnailInfo; - private int mCornerRadius; + protected int mCornerRadius; @ViewDebug.ExportedProperty(category="recents") private float mDimAlpha; private Matrix mScaleMatrix = new Matrix(); - private Paint mDrawPaint = new Paint(); - private Paint mBgFillPaint = new Paint(); - private BitmapShader mBitmapShader; + protected Paint mDrawPaint = new Paint(); + protected Paint mBgFillPaint = new Paint(); + protected BitmapShader mBitmapShader; private LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0); // Clip the top of the thumbnail against the opaque header bar that overlaps this view diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java new file mode 100644 index 0000000000000..afc0033eb81c6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents.views.grid; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Path; +import android.util.AttributeSet; + +import com.android.systemui.R; +import com.android.systemui.recents.views.TaskViewThumbnail; + +public class GridTaskViewThumbnail extends TaskViewThumbnail { + + private Path mThumbnailOutline; + private Path mRestBackgroundOutline; + private Path mFullBackgroundOutline; + // True if either this view's size or thumbnail scale has changed and mThumbnailOutline should + // be updated. + private boolean mUpdateThumbnailOutline = true; + + public GridTaskViewThumbnail(Context context) { + this(context, null); + } + + public GridTaskViewThumbnail(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public GridTaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public GridTaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + mCornerRadius = getResources().getDimensionPixelSize( + R.dimen.recents_grid_task_view_rounded_corners_radius); + } + + /** + * Called when the task view frame changes, allowing us to move the contents of the header + * to match the frame changes. + */ + public void onTaskViewSizeChanged(int width, int height) { + mUpdateThumbnailOutline = true; + super.onTaskViewSizeChanged(width, height); + } + + /** + * Updates the scale of the bitmap relative to this view. + */ + public void updateThumbnailScale() { + mUpdateThumbnailOutline = true; + super.updateThumbnailScale(); + } + + private void updateThumbnailOutline() { + final int titleHeight = getResources().getDimensionPixelSize( + R.dimen.recents_grid_task_view_header_height); + final int viewWidth = mTaskViewRect.width(); + final int viewHeight = mTaskViewRect.height() - titleHeight; + final int thumbnailWidth = Math.min(viewWidth, + (int) (mThumbnailRect.width() * mThumbnailScale)); + final int thumbnailHeight = Math.min(viewHeight, + (int) (mThumbnailRect.height() * mThumbnailScale)); + // Draw the thumbnail, we only round the bottom corners: + // + // outerLeft outerRight + // <-----------------------> mRestBackgroundOutline + // _________________________ (thumbnailWidth < viewWidth) + // |_______________________| outerTop A ____ B + // | | ↑ | | + // | | | | | + // | | | | | + // | | | | | C + // \_______________________/ ↓ |__/ + // mCornerRadius outerBottom E D + // + // mRestBackgroundOutline (thumbnailHeight < viewHeight) + // A _________________________ B + // | | C + // F \_______________________/ + // E D + final int outerLeft = 0; + final int outerTop = 0; + final int outerRight = outerLeft + thumbnailWidth; + final int outerBottom = outerTop + thumbnailHeight; + mThumbnailOutline = new Path(); + mThumbnailOutline.moveTo(outerLeft, outerTop); + mThumbnailOutline.lineTo(outerRight, outerTop); + mThumbnailOutline.lineTo(outerRight, outerBottom - mCornerRadius); + mThumbnailOutline.arcTo(outerRight - 2 * mCornerRadius, outerBottom - 2 * mCornerRadius, + outerRight, outerBottom, 0, 90, false); + mThumbnailOutline.lineTo(outerLeft + mCornerRadius, outerBottom); + mThumbnailOutline.arcTo(outerLeft, outerBottom - 2 * mCornerRadius, + outerLeft + 2 * mCornerRadius, outerBottom, 90, 90, false); + mThumbnailOutline.lineTo(outerLeft, outerTop); + mThumbnailOutline.close(); + + if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) { + if (thumbnailWidth < viewWidth) { + final int l = Math.max(0, outerRight - mCornerRadius); + final int r = outerRight; + final int t = outerTop; + final int b = outerBottom; + mRestBackgroundOutline = new Path(); + mRestBackgroundOutline.moveTo(l, t); // A + mRestBackgroundOutline.lineTo(r, t); // B + mRestBackgroundOutline.lineTo(r, b - mCornerRadius); // C + mRestBackgroundOutline.arcTo(r - 2 * mCornerRadius, b - 2 * mCornerRadius, r, b, + 0, 90, false); // D + mRestBackgroundOutline.lineTo(l, b); // E + mRestBackgroundOutline.lineTo(l, t); // A + mRestBackgroundOutline.close(); + + } + if (thumbnailHeight < viewHeight) { + final int l = outerLeft; + final int r = outerRight; + final int t = Math.max(0, thumbnailHeight - mCornerRadius); + final int b = outerBottom; + mRestBackgroundOutline = new Path(); + mRestBackgroundOutline.moveTo(l, t); // A + mRestBackgroundOutline.lineTo(r, t); // B + mRestBackgroundOutline.lineTo(r, b - mCornerRadius); // C + mRestBackgroundOutline.arcTo(r - 2 * mCornerRadius, b - 2 * mCornerRadius, r, b, + 0, 90, false); // D + mRestBackgroundOutline.lineTo(l + mCornerRadius, b); // E + mRestBackgroundOutline.arcTo(l, b - 2 * mCornerRadius, l + 2 * mCornerRadius, b, + 90, 90, false); // F + mRestBackgroundOutline.lineTo(l, t); // A + mRestBackgroundOutline.close(); + + } + } else { + mFullBackgroundOutline = mThumbnailOutline; + } + } + + @Override + protected void onDraw(Canvas canvas) { + final int titleHeight = getResources().getDimensionPixelSize( + R.dimen.recents_grid_task_view_header_height); + final int viewWidth = mTaskViewRect.width(); + final int viewHeight = mTaskViewRect.height() - titleHeight; + final int thumbnailWidth = Math.min(viewWidth, + (int) (mThumbnailRect.width() * mThumbnailScale)); + final int thumbnailHeight = Math.min(viewHeight, + (int) (mThumbnailRect.height() * mThumbnailScale)); + + if (mUpdateThumbnailOutline) { + updateThumbnailOutline(); + mUpdateThumbnailOutline = false; + } + if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) { + // Draw the background, there will be some small overdraw with the thumbnail + if (thumbnailWidth < viewWidth) { + // Portrait thumbnail on a landscape task view + canvas.drawPath(mRestBackgroundOutline, mBgFillPaint); + } + if (thumbnailHeight < viewHeight) { + // Landscape thumbnail on a portrait task view + canvas.drawPath(mRestBackgroundOutline, mBgFillPaint); + } + canvas.drawPath(mThumbnailOutline, mDrawPaint); + } else { + canvas.drawPath(mFullBackgroundOutline, mBgFillPaint); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java index 78c26dd64986a..02d1cc14fc417 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java @@ -105,11 +105,13 @@ public class TaskGridLayoutAlgorithm { if (maxTaskHeight >= maxTaskWidth / mAppAspectRatio + mTitleBarHeight) { // Width bound. taskWidth = maxTaskWidth; - taskHeight = (int) (maxTaskWidth / mAppAspectRatio + mTitleBarHeight); + // Here we should round the height to the nearest integer. + taskHeight = (int) (maxTaskWidth / mAppAspectRatio + mTitleBarHeight + 0.5); } else { // Height bound. taskHeight = maxTaskHeight; - taskWidth = (int) ((taskHeight - mTitleBarHeight) * mAppAspectRatio); + // Here we should round the width to the nearest integer. + taskWidth = (int) ((taskHeight - mTitleBarHeight) * mAppAspectRatio + 0.5); } size.set(0, 0, taskWidth, taskHeight);