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
This commit is contained in:
@@ -15,5 +15,5 @@
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#61FFFFFF" />
|
||||
<corners android:radius="8dp"/>
|
||||
<corners android:radius="@dimen/recents_grid_task_view_rounded_corners_radius"/>
|
||||
</shape>
|
||||
@@ -18,7 +18,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="true">
|
||||
<com.android.systemui.recents.views.TaskViewThumbnail
|
||||
<com.android.systemui.recents.views.grid.GridTaskViewThumbnail
|
||||
android:id="@+id/task_view_thumbnail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
@@ -22,5 +22,6 @@
|
||||
<dimen name="recents_grid_task_view_header_height">44dp</dimen>
|
||||
<dimen name="recents_grid_task_view_header_button_padding">8dp</dimen>
|
||||
<dimen name="recents_grid_task_view_focused_frame_thickness">8dp</dimen>
|
||||
<dimen name="recents_grid_task_view_rounded_corners_radius">8dp</dimen>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user