Fading the edges of the thumbnail if the size is different than the view size
Change-Id: I7bfb9d55ccbf4fa0338bc962632cfeac37cd69be
diff --git a/quickstep/res/drawable/task_thumbnail_background.xml b/quickstep/res/drawable/task_thumbnail_background.xml
deleted file mode 100644
index f1f48ac..0000000
--- a/quickstep/res/drawable/task_thumbnail_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
- <corners android:radius="2dp" />
-</shape>
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 839d934..91b6aa3 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,23 +13,20 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.quickstep.TaskView
- xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.quickstep.TaskView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:elevation="4dp">
<com.android.quickstep.TaskThumbnailView
android:id="@+id/snapshot"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginTop="@dimen/task_thumbnail_top_margin"
- android:scaleType="matrix"
- android:background="@drawable/task_thumbnail_background"
- android:elevation="4dp" />
+ android:layout_marginTop="@dimen/task_thumbnail_top_margin" />
+
<ImageView
android:id="@+id/icon"
android:layout_width="@dimen/task_thumbnail_icon_size"
android:layout_height="@dimen/task_thumbnail_icon_size"
- android:layout_gravity="top|center_horizontal"
- android:elevation="5dp"/>
+ android:layout_gravity="top|center_horizontal" />
</com.android.quickstep.TaskView>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 222a3f4..076f0a3 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -19,6 +19,9 @@
<dimen name="task_thumbnail_top_margin">24dp</dimen>
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<dimen name="task_menu_background_radius">12dp</dimen>
+ <dimen name="task_corner_radius">2dp</dimen>
+ <dimen name="task_fade_length">20dp</dimen>
+
<dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
<dimen name="quickstep_fling_min_velocity">250dp</dimen>
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 9c757bf..605c83c 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -72,7 +72,7 @@
for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
final TaskView taskView = (TaskView) getChildAt(i);
if (taskView.getTask().key.id == taskId) {
- taskView.getThumbnail().setThumbnail(snapshot);
+ taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot);
return;
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
index 473681f..87dec67 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
@@ -22,35 +22,43 @@
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ComposeShader;
import android.graphics.LightingColorFilter;
+import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
-import android.widget.FrameLayout;
+import android.view.View;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
/**
* A task in the Recents view.
*/
-public class TaskThumbnailView extends FrameLayout {
+public class TaskThumbnailView extends View {
+
+ private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256];
+
+ private final float mCornerRadius;
+ private final float mFadeLength;
+
+ private final Paint mPaint = new Paint();
+
+ private final Matrix mMatrix = new Matrix();
+ private final Rect mThumbnailRect = new Rect();
private ThumbnailData mThumbnailData;
-
- private Rect mThumbnailRect = new Rect();
- private float mThumbnailScale;
-
- private Matrix mMatrix = new Matrix();
- private Paint mDrawPaint = new Paint();
- protected Paint mBgFillPaint = new Paint();
protected BitmapShader mBitmapShader;
+ private float mThumbnailScale;
private float mDimAlpha = 1f;
- private LightingColorFilter mLightingColorFilter = new LightingColorFilter(Color.WHITE, 0);
public TaskThumbnailView(Context context) {
this(context, null);
@@ -62,32 +70,34 @@
public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- setWillNotDraw(false);
- setClipToOutline(true);
+ mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
+ mFadeLength = getResources().getDimension(R.dimen.task_fade_length);
}
/**
* Updates this thumbnail.
*/
- public void setThumbnail(ThumbnailData thumbnailData) {
+ public void setThumbnail(Task task, ThumbnailData thumbnailData) {
+ mPaint.setColor(task == null ? Color.BLACK : task.colorBackground | 0xFF000000);
+
if (thumbnailData != null && thumbnailData.thumbnail != null) {
Bitmap bm = thumbnailData.thumbnail;
bm.prepareToDraw();
mThumbnailScale = thumbnailData.scale;
mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
- mDrawPaint.setShader(mBitmapShader);
+ mPaint.setShader(mBitmapShader);
mThumbnailRect.set(0, 0,
bm.getWidth() - thumbnailData.insets.left - thumbnailData.insets.right,
bm.getHeight() - thumbnailData.insets.top - thumbnailData.insets.bottom);
mThumbnailData = thumbnailData;
updateThumbnailMatrix();
- updateThumbnailPaintFilter();
} else {
mBitmapShader = null;
- mDrawPaint.setShader(null);
- mThumbnailRect.setEmpty();
mThumbnailData = null;
+ mPaint.setShader(null);
+ mThumbnailRect.setEmpty();
}
+ updateThumbnailPaintFilter();
}
/**
@@ -100,43 +110,17 @@
@Override
protected void onDraw(Canvas canvas) {
- int viewWidth = getMeasuredWidth();
- int viewHeight = getMeasuredHeight();
- int thumbnailWidth = Math.min(viewWidth,
- (int) (mThumbnailRect.width() * mThumbnailScale));
- int thumbnailHeight = Math.min(viewHeight,
- (int) (mThumbnailRect.height() * mThumbnailScale));
-
- 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.drawRect(Math.max(0, thumbnailWidth), 0, viewWidth, viewHeight,
- mBgFillPaint);
- }
- if (thumbnailHeight < viewHeight) {
- // Landscape thumbnail on a portrait task view
- canvas.drawRect(0, Math.max(0, thumbnailHeight), viewWidth, viewHeight,
- mBgFillPaint);
- }
-
- // Draw the thumbnail
- canvas.drawRect(0, 0, thumbnailWidth, thumbnailHeight, mDrawPaint);
- } else {
- canvas.drawRect(0, 0, viewWidth, viewHeight, mBgFillPaint);
- }
+ canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
+ mCornerRadius, mCornerRadius, mPaint);
}
private void updateThumbnailPaintFilter() {
int mul = (int) (mDimAlpha * 255);
if (mBitmapShader != null) {
- mLightingColorFilter = new LightingColorFilter(Color.argb(255, mul, mul, mul), 0);
- mDrawPaint.setColorFilter(mLightingColorFilter);
- mDrawPaint.setColor(0xFFffffff);
- mBgFillPaint.setColorFilter(mLightingColorFilter);
+ mPaint.setColorFilter(getLightingColorFilter(mul));
} else {
- mDrawPaint.setColorFilter(null);
- mDrawPaint.setColor(Color.argb(255, mul, mul, mul));
+ mPaint.setColorFilter(null);
+ mPaint.setColor(Color.argb(255, mul, mul, mul));
}
invalidate();
}
@@ -170,6 +154,26 @@
mMatrix.setTranslate(-mThumbnailData.insets.left, -mThumbnailData.insets.top);
mMatrix.postScale(mThumbnailScale, mThumbnailScale);
mBitmapShader.setLocalMatrix(mMatrix);
+
+ float bitmapHeight = Math.max(mThumbnailRect.height() * mThumbnailScale, 0);
+ Shader shader = mBitmapShader;
+ if (bitmapHeight < getMeasuredHeight()) {
+ int color = mPaint.getColor();
+ LinearGradient fade = new LinearGradient(
+ 0, bitmapHeight - mFadeLength, 0, bitmapHeight,
+ color & 0x00FFFFFF, color, Shader.TileMode.CLAMP);
+ shader = new ComposeShader(fade, shader, Mode.DST_OVER);
+ }
+
+ float bitmapWidth = Math.max(mThumbnailRect.width() * mThumbnailScale, 0);
+ if (bitmapWidth < getMeasuredWidth()) {
+ int color = mPaint.getColor();
+ LinearGradient fade = new LinearGradient(
+ bitmapWidth - mFadeLength, 0, bitmapWidth, 0,
+ color & 0x00FFFFFF, color, Shader.TileMode.CLAMP);
+ shader = new ComposeShader(fade, shader, Mode.DST_OVER);
+ }
+ mPaint.setShader(shader);
}
invalidate();
}
@@ -179,4 +183,17 @@
super.onSizeChanged(w, h, oldw, oldh);
updateThumbnailMatrix();
}
+
+ private static LightingColorFilter getLightingColorFilter(int dimColor) {
+ if (dimColor < 0) {
+ dimColor = 0;
+ } else if (dimColor > 255) {
+ dimColor = 255;
+ }
+ if (sDimFilterCache[dimColor] == null) {
+ sDimFilterCache[dimColor] =
+ new LightingColorFilter(Color.argb(255, dimColor, dimColor, dimColor), 0);
+ }
+ return sDimFilterCache[dimColor];
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index 5c15a76..0e999f8 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -16,13 +16,20 @@
package com.android.quickstep;
+import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
+import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
+
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.app.ActivityOptions;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Property;
+import android.view.View;
+import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -40,9 +47,6 @@
import java.util.ArrayList;
import java.util.List;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
-
/**
* A task in the Recents view.
*/
@@ -90,9 +94,8 @@
public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- setOnClickListener((view) -> {
- launchTask(true /* animate */);
- });
+ setOnClickListener((view) -> launchTask(true /* animate */));
+ setOutlineProvider(new TaskOutlineProvider(getResources()));
}
@Override
@@ -155,14 +158,14 @@
@Override
public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
- mSnapshotView.setThumbnail(thumbnailData);
+ mSnapshotView.setThumbnail(task, thumbnailData);
mIconView.setImageDrawable(task.icon);
mIconView.setOnLongClickListener(icon -> TaskMenuView.showForTask(this));
}
@Override
public void onTaskDataUnloaded() {
- mSnapshotView.setThumbnail(null);
+ mSnapshotView.setThumbnail(null, null);
mIconView.setImageDrawable(null);
mIconView.setOnLongClickListener(null);
}
@@ -216,4 +219,22 @@
scrollState.prevPageExtraWidth = 0;
return SCROLL_TYPE_TASK;
}
+
+
+ private static final class TaskOutlineProvider extends ViewOutlineProvider {
+
+ private final int mMarginTop;
+ private final float mRadius;
+
+ TaskOutlineProvider(Resources res) {
+ mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+ mRadius = res.getDimension(R.dimen.task_corner_radius);
+ }
+
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(0, mMarginTop, view.getWidth(),
+ view.getHeight(), mRadius);
+ }
+ }
}