Merge "Improving folder icon drawable" into tm-dev
This commit is contained in:
@@ -20,9 +20,13 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Path.Direction;
|
||||
import android.graphics.Picture;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
@@ -31,10 +35,11 @@ import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.folder.PreviewBackground;
|
||||
import com.android.launcher3.graphics.ShiftedBitmapDrawable;
|
||||
import com.android.launcher3.icons.BitmapRenderer;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
@@ -69,79 +74,104 @@ public class FolderAdaptiveIcon extends AdaptiveIconDrawable {
|
||||
return mBadge;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public static @Nullable FolderAdaptiveIcon createFolderAdaptiveIcon(
|
||||
ActivityContext activity, int folderId, Point dragViewSize) {
|
||||
ActivityContext activity, int folderId, Point size) {
|
||||
Preconditions.assertNonUiThread();
|
||||
if (!Utilities.ATLEAST_P) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create the actual drawable on the UI thread to avoid race conditions with
|
||||
// assume square
|
||||
if (size.x != size.y) {
|
||||
return null;
|
||||
}
|
||||
int requestedSize = size.x;
|
||||
|
||||
// Only use the size actually needed for drawing the folder icon
|
||||
int drawingSize = activity.getDeviceProfile().folderIconSizePx;
|
||||
int foregroundSize = Math.max(requestedSize, drawingSize);
|
||||
float shift = foregroundSize - requestedSize;
|
||||
|
||||
Picture background = new Picture();
|
||||
Picture foreground = new Picture();
|
||||
Picture badge = new Picture();
|
||||
|
||||
Canvas bgCanvas = background.beginRecording(requestedSize, requestedSize);
|
||||
Canvas badgeCanvas = badge.beginRecording(requestedSize, requestedSize);
|
||||
|
||||
Canvas fgCanvas = foreground.beginRecording(foregroundSize, foregroundSize);
|
||||
fgCanvas.translate(shift, shift);
|
||||
|
||||
// Do not clip the folder drawing since the icon previews extend outside the background.
|
||||
Path mask = new Path();
|
||||
mask.addRect(-shift, -shift, requestedSize + shift, requestedSize + shift,
|
||||
Direction.CCW);
|
||||
|
||||
// Initialize the actual draw commands on the UI thread to avoid race conditions with
|
||||
// FolderIcon draw pass
|
||||
try {
|
||||
return MAIN_EXECUTOR.submit(() -> {
|
||||
MAIN_EXECUTOR.submit(() -> {
|
||||
FolderIcon icon = activity.findFolderIcon(folderId);
|
||||
return icon == null ? null : createDrawableOnUiThread(icon, dragViewSize);
|
||||
|
||||
if (icon == null) {
|
||||
throw new IllegalArgumentException("Folder not found with id: " + folderId);
|
||||
}
|
||||
initLayersOnUiThread(icon, requestedSize, bgCanvas, fgCanvas, badgeCanvas);
|
||||
}).get();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to create folder icon", e);
|
||||
return null;
|
||||
} finally {
|
||||
background.endRecording();
|
||||
foreground.endRecording();
|
||||
badge.endRecording();
|
||||
}
|
||||
|
||||
// Only convert foreground to a bitmap as it can contain multiple draw commands. Other
|
||||
// layers either draw a nothing or a single draw call.
|
||||
Bitmap fgBitmap = Bitmap.createBitmap(foreground);
|
||||
Paint foregroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
// Do not use PictureDrawable as it moves the picture to the canvas bounds, whereas we want
|
||||
// to draw it at (0,0)
|
||||
return new FolderAdaptiveIcon(
|
||||
new BitmapRendererDrawable(c -> c.drawPicture(background)),
|
||||
new BitmapRendererDrawable(
|
||||
c -> c.drawBitmap(fgBitmap, -shift, -shift, foregroundPaint)),
|
||||
new BitmapRendererDrawable(c -> c.drawPicture(badge)),
|
||||
mask);
|
||||
}
|
||||
|
||||
private static FolderAdaptiveIcon createDrawableOnUiThread(FolderIcon icon,
|
||||
Point dragViewSize) {
|
||||
Preconditions.assertUIThread();
|
||||
|
||||
@UiThread
|
||||
private static void initLayersOnUiThread(FolderIcon icon, int size,
|
||||
Canvas backgroundCanvas, Canvas foregroundCanvas, Canvas badgeCanvas) {
|
||||
icon.getPreviewBounds(sTmpRect);
|
||||
|
||||
PreviewBackground bg = icon.getFolderBackground();
|
||||
|
||||
// assume square
|
||||
assert (dragViewSize.x == dragViewSize.y);
|
||||
final int previewSize = sTmpRect.width();
|
||||
|
||||
final int margin = (dragViewSize.x - previewSize) / 2;
|
||||
PreviewBackground bg = icon.getFolderBackground();
|
||||
final int margin = (size - previewSize) / 2;
|
||||
final float previewShiftX = -sTmpRect.left + margin;
|
||||
final float previewShiftY = -sTmpRect.top + margin;
|
||||
|
||||
// Initialize badge, which consists of the outline stroke, shadow and dot; these
|
||||
// must be rendered above the foreground
|
||||
Bitmap badgeBmp = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
|
||||
(canvas) -> {
|
||||
canvas.save();
|
||||
canvas.translate(previewShiftX, previewShiftY);
|
||||
bg.drawShadow(canvas);
|
||||
bg.drawBackgroundStroke(canvas);
|
||||
icon.drawDot(canvas);
|
||||
canvas.restore();
|
||||
});
|
||||
badgeCanvas.save();
|
||||
badgeCanvas.translate(previewShiftX, previewShiftY);
|
||||
icon.drawDot(badgeCanvas);
|
||||
badgeCanvas.restore();
|
||||
|
||||
// Initialize mask
|
||||
Path mask = new Path();
|
||||
Matrix m = new Matrix();
|
||||
m.setTranslate(previewShiftX, previewShiftY);
|
||||
bg.getClipPath().transform(m, mask);
|
||||
// Draw foreground
|
||||
foregroundCanvas.save();
|
||||
foregroundCanvas.translate(previewShiftX, previewShiftY);
|
||||
icon.getPreviewItemManager().draw(foregroundCanvas);
|
||||
foregroundCanvas.restore();
|
||||
|
||||
Bitmap previewBitmap = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
|
||||
(canvas) -> {
|
||||
canvas.save();
|
||||
canvas.translate(previewShiftX, previewShiftY);
|
||||
icon.getPreviewItemManager().draw(canvas);
|
||||
canvas.restore();
|
||||
});
|
||||
|
||||
Bitmap bgBitmap = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
|
||||
(canvas) -> {
|
||||
Paint p = new Paint();
|
||||
p.setColor(bg.getBgColor());
|
||||
|
||||
canvas.drawCircle(dragViewSize.x / 2f, dragViewSize.y / 2f, bg.getRadius(), p);
|
||||
});
|
||||
|
||||
ShiftedBitmapDrawable badge = new ShiftedBitmapDrawable(badgeBmp, 0, 0);
|
||||
ShiftedBitmapDrawable foreground = new ShiftedBitmapDrawable(previewBitmap, 0, 0);
|
||||
ShiftedBitmapDrawable background = new ShiftedBitmapDrawable(bgBitmap, 0, 0);
|
||||
|
||||
return new FolderAdaptiveIcon(background, foreground, badge, mask);
|
||||
// Draw background
|
||||
Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
backgroundPaint.setColor(bg.getBgColor());
|
||||
bg.drawShadow(backgroundCanvas);
|
||||
backgroundCanvas.drawCircle(size / 2f, size / 2f, bg.getRadius(), backgroundPaint);
|
||||
bg.drawBackgroundStroke(backgroundCanvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -174,4 +204,52 @@ public class FolderAdaptiveIcon extends AdaptiveIconDrawable {
|
||||
& mBadge.getChangingConfigurations();
|
||||
}
|
||||
}
|
||||
|
||||
private static class BitmapRendererDrawable extends Drawable {
|
||||
|
||||
private final BitmapRenderer mRenderer;
|
||||
|
||||
BitmapRendererDrawable(BitmapRenderer renderer) {
|
||||
mRenderer = renderer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
mRenderer.draw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int i) { }
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) { }
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstantState getConstantState() {
|
||||
return new MyConstantState(mRenderer);
|
||||
}
|
||||
|
||||
private static class MyConstantState extends ConstantState {
|
||||
private final BitmapRenderer mRenderer;
|
||||
|
||||
MyConstantState(BitmapRenderer renderer) {
|
||||
mRenderer = renderer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable() {
|
||||
return new BitmapRendererDrawable(mRenderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChangingConfigurations() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.launcher3.graphics;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
/**
|
||||
* A simple drawable which draws a bitmap at a fixed position irrespective of the bounds
|
||||
*/
|
||||
public class ShiftedBitmapDrawable extends Drawable {
|
||||
|
||||
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
||||
private final Bitmap mBitmap;
|
||||
private float mShiftX;
|
||||
private float mShiftY;
|
||||
|
||||
private final ConstantState mConstantState;
|
||||
|
||||
public ShiftedBitmapDrawable(Bitmap bitmap, float shiftX, float shiftY) {
|
||||
mBitmap = bitmap;
|
||||
mShiftX = shiftX;
|
||||
mShiftY = shiftY;
|
||||
|
||||
mConstantState = new MyConstantState(mBitmap, mShiftX, mShiftY);
|
||||
}
|
||||
|
||||
public float getShiftX() {
|
||||
return mShiftX;
|
||||
}
|
||||
|
||||
public float getShiftY() {
|
||||
return mShiftY;
|
||||
}
|
||||
|
||||
public void setShiftX(float shiftX) {
|
||||
mShiftX = shiftX;
|
||||
}
|
||||
|
||||
public void setShiftY(float shiftY) {
|
||||
mShiftY = shiftY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
canvas.drawBitmap(mBitmap, mShiftX, mShiftY, mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int i) { }
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) {
|
||||
mPaint.setColorFilter(colorFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstantState getConstantState() {
|
||||
return mConstantState;
|
||||
}
|
||||
|
||||
private static class MyConstantState extends ConstantState {
|
||||
private final Bitmap mBitmap;
|
||||
private float mShiftX;
|
||||
private float mShiftY;
|
||||
|
||||
MyConstantState(Bitmap bitmap, float shiftX, float shiftY) {
|
||||
mBitmap = bitmap;
|
||||
mShiftX = shiftX;
|
||||
mShiftY = shiftY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable() {
|
||||
return new ShiftedBitmapDrawable(mBitmap, mShiftX, mShiftY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChangingConfigurations() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,6 @@ import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.graphics.PreloadIconDrawable;
|
||||
import com.android.launcher3.icons.FastBitmapDrawable;
|
||||
@@ -413,8 +412,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||
@WorkerThread
|
||||
@SuppressWarnings("WrongThread")
|
||||
private static int getOffsetForIconBounds(Launcher l, Drawable drawable, RectF position) {
|
||||
if (!(drawable instanceof AdaptiveIconDrawable)
|
||||
|| (drawable instanceof FolderAdaptiveIcon)) {
|
||||
if (!(drawable instanceof AdaptiveIconDrawable)) {
|
||||
return 0;
|
||||
}
|
||||
int blurSizeOutline =
|
||||
|
||||
Reference in New Issue
Block a user