Merge "Optimizing some icon generation code in bubble" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2022-08-05 21:14:12 +00:00
committed by Android (Google) Code Review
3 changed files with 86 additions and 68 deletions

View File

@@ -19,14 +19,14 @@ package com.android.wm.shell.bubbles;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Color;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.ShadowGenerator;
import com.android.wm.shell.R;
/**
@@ -44,78 +44,77 @@ public class BubbleBadgeIconFactory extends BaseIconFactory {
* will include the workprofile indicator on the badge if appropriate.
*/
BitmapInfo getBadgeBitmap(Drawable userBadgedAppIcon, boolean isImportantConversation) {
ShadowGenerator shadowGenerator = new ShadowGenerator(mIconBitmapSize);
Bitmap userBadgedBitmap = createIconBitmap(userBadgedAppIcon, 1f, mIconBitmapSize);
if (userBadgedAppIcon instanceof AdaptiveIconDrawable) {
userBadgedBitmap = Bitmap.createScaledBitmap(
getCircleBitmap((AdaptiveIconDrawable) userBadgedAppIcon, /* size */
userBadgedAppIcon.getIntrinsicWidth()),
mIconBitmapSize, mIconBitmapSize, /* filter */ true);
AdaptiveIconDrawable ad = (AdaptiveIconDrawable) userBadgedAppIcon;
userBadgedAppIcon = new CircularAdaptiveIcon(ad.getBackground(), ad.getForeground());
}
if (isImportantConversation) {
userBadgedAppIcon = new CircularRingDrawable(userBadgedAppIcon);
}
Bitmap userBadgedBitmap = createIconBitmap(
userBadgedAppIcon, 1, BITMAP_GENERATION_MODE_WITH_SHADOW);
return createIconBitmap(userBadgedBitmap);
}
private class CircularRingDrawable extends CircularAdaptiveIcon {
final int mImportantConversationColor;
final Rect mTempBounds = new Rect();
final Drawable mDr;
CircularRingDrawable(Drawable dr) {
super(null, null);
mDr = dr;
mImportantConversationColor = mContext.getResources().getColor(
R.color.important_conversation, null);
}
if (isImportantConversation) {
final float ringStrokeWidth = mContext.getResources().getDimensionPixelSize(
@Override
public void draw(Canvas canvas) {
int save = canvas.save();
canvas.clipPath(getIconMask());
canvas.drawColor(mImportantConversationColor);
int ringStrokeWidth = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width);
final int importantConversationColor = mContext.getResources().getColor(
R.color.important_conversation, null);
Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(),
userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig());
Canvas c = new Canvas(badgeAndRing);
Paint ringPaint = new Paint();
ringPaint.setStyle(Paint.Style.FILL);
ringPaint.setColor(importantConversationColor);
ringPaint.setAntiAlias(true);
c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2, ringPaint);
final int bitmapTop = (int) ringStrokeWidth;
final int bitmapLeft = (int) ringStrokeWidth;
final int bitmapWidth = c.getWidth() - 2 * (int) ringStrokeWidth;
final int bitmapHeight = c.getHeight() - 2 * (int) ringStrokeWidth;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(userBadgedBitmap, bitmapWidth,
bitmapHeight, /* filter */ true);
c.drawBitmap(scaledBitmap, bitmapTop, bitmapLeft, /* paint */null);
shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c);
return createIconBitmap(badgeAndRing);
} else {
Canvas c = new Canvas();
c.setBitmap(userBadgedBitmap);
shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c);
return createIconBitmap(userBadgedBitmap);
mTempBounds.set(getBounds());
mTempBounds.inset(ringStrokeWidth, ringStrokeWidth);
mDr.setBounds(mTempBounds);
mDr.draw(canvas);
canvas.restoreToCount(save);
}
}
private Bitmap getCircleBitmap(AdaptiveIconDrawable icon, int size) {
Drawable foreground = icon.getForeground();
Drawable background = icon.getBackground();
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas();
canvas.setBitmap(bitmap);
private static class CircularAdaptiveIcon extends AdaptiveIconDrawable {
// Clip canvas to circle.
Path circlePath = new Path();
circlePath.addCircle(/* x */ size / 2f,
/* y */ size / 2f,
/* radius */ size / 2f,
Path.Direction.CW);
canvas.clipPath(circlePath);
final Path mPath = new Path();
// Draw background.
background.setBounds(0, 0, size, size);
background.draw(canvas);
CircularAdaptiveIcon(Drawable bg, Drawable fg) {
super(bg, fg);
}
// Draw foreground. The foreground and background drawables are derived from adaptive icons
// Some icon shapes fill more space than others, so adaptive icons are normalized to about
// the same size. This size is smaller than the original bounds, so we estimate
// the difference in this offset.
int offset = size / 5;
foreground.setBounds(-offset, -offset, size + offset, size + offset);
foreground.draw(canvas);
@Override
public Path getIconMask() {
mPath.reset();
Rect bounds = getBounds();
mPath.addOval(bounds.left, bounds.top, bounds.right, bounds.bottom, Path.Direction.CW);
return mPath;
}
canvas.setBitmap(null);
return bitmap;
@Override
public void draw(Canvas canvas) {
int save = canvas.save();
canvas.clipPath(getIconMask());
canvas.drawColor(Color.BLACK);
Drawable d;
if ((d = getBackground()) != null) {
d.draw(canvas);
}
if ((d = getForeground()) != null) {
d.draw(canvas);
}
canvas.restoreToCount(save);
}
}
}

View File

@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
@@ -65,4 +66,19 @@ public class BubbleIconFactory extends BaseIconFactory {
return null;
}
}
/**
* Creates the bitmap for the provided drawable and returns the scale used for
* drawing the actual drawable.
*/
public Bitmap createIconBitmap(@NonNull Drawable icon, float[] outScale) {
if (outScale == null) {
outScale = new float[1];
}
icon = normalizeAndWrapToAdaptiveIcon(icon,
true /* shrinkNonAdaptiveIcons */,
null /* outscale */,
outScale);
return createIconBitmap(icon, outScale[0], BITMAP_GENERATION_MODE_WITH_SHADOW);
}
}

View File

@@ -195,15 +195,18 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
b.isImportantConversation());
info.badgeBitmap = badgeBitmapInfo.icon;
// Raw badge bitmap never includes the important conversation ring
info.mRawBadgeBitmap = badgeIconFactory.getBadgeBitmap(badgedIcon, false).icon;
info.bubbleBitmap = iconFactory.createBadgedIconBitmap(bubbleDrawable).icon;
info.mRawBadgeBitmap = b.isImportantConversation()
? badgeIconFactory.getBadgeBitmap(badgedIcon, false).icon
: badgeBitmapInfo.icon;
float[] bubbleBitmapScale = new float[1];
info.bubbleBitmap = iconFactory.createIconBitmap(bubbleDrawable, bubbleBitmapScale);
// Dot color & placement
Path iconPath = PathParser.createPathFromPathData(
c.getResources().getString(com.android.internal.R.string.config_icon_mask));
Matrix matrix = new Matrix();
float scale = iconFactory.getNormalizer().getScale(bubbleDrawable,
null /* outBounds */, null /* path */, null /* outMaskShape */);
float scale = bubbleBitmapScale[0];
float radius = DEFAULT_PATH_SIZE / 2f;
matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
radius /* pivot y */);