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.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Color;
import android.graphics.Path; import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.ShadowGenerator;
import com.android.wm.shell.R; 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. * will include the workprofile indicator on the badge if appropriate.
*/ */
BitmapInfo getBadgeBitmap(Drawable userBadgedAppIcon, boolean isImportantConversation) { BitmapInfo getBadgeBitmap(Drawable userBadgedAppIcon, boolean isImportantConversation) {
ShadowGenerator shadowGenerator = new ShadowGenerator(mIconBitmapSize);
Bitmap userBadgedBitmap = createIconBitmap(userBadgedAppIcon, 1f, mIconBitmapSize);
if (userBadgedAppIcon instanceof AdaptiveIconDrawable) { if (userBadgedAppIcon instanceof AdaptiveIconDrawable) {
userBadgedBitmap = Bitmap.createScaledBitmap( AdaptiveIconDrawable ad = (AdaptiveIconDrawable) userBadgedAppIcon;
getCircleBitmap((AdaptiveIconDrawable) userBadgedAppIcon, /* size */ userBadgedAppIcon = new CircularAdaptiveIcon(ad.getBackground(), ad.getForeground());
userBadgedAppIcon.getIntrinsicWidth()), }
mIconBitmapSize, mIconBitmapSize, /* filter */ true); 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) { @Override
final float ringStrokeWidth = mContext.getResources().getDimensionPixelSize( 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); com.android.internal.R.dimen.importance_ring_stroke_width);
final int importantConversationColor = mContext.getResources().getColor( mTempBounds.set(getBounds());
R.color.important_conversation, null); mTempBounds.inset(ringStrokeWidth, ringStrokeWidth);
Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(), mDr.setBounds(mTempBounds);
userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig()); mDr.draw(canvas);
Canvas c = new Canvas(badgeAndRing); canvas.restoreToCount(save);
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);
} }
} }
private Bitmap getCircleBitmap(AdaptiveIconDrawable icon, int size) { private static class CircularAdaptiveIcon extends AdaptiveIconDrawable {
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);
// Clip canvas to circle. final Path mPath = new Path();
Path circlePath = new Path();
circlePath.addCircle(/* x */ size / 2f,
/* y */ size / 2f,
/* radius */ size / 2f,
Path.Direction.CW);
canvas.clipPath(circlePath);
// Draw background. CircularAdaptiveIcon(Drawable bg, Drawable fg) {
background.setBounds(0, 0, size, size); super(bg, fg);
background.draw(canvas); }
// Draw foreground. The foreground and background drawables are derived from adaptive icons @Override
// Some icon shapes fill more space than others, so adaptive icons are normalized to about public Path getIconMask() {
// the same size. This size is smaller than the original bounds, so we estimate mPath.reset();
// the difference in this offset. Rect bounds = getBounds();
int offset = size / 5; mPath.addOval(bounds.left, bounds.top, bounds.right, bounds.bottom, Path.Direction.CW);
foreground.setBounds(-offset, -offset, size + offset, size + offset); return mPath;
foreground.draw(canvas); }
canvas.setBitmap(null); @Override
return bitmap; 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.Intent;
import android.content.pm.LauncherApps; import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon; import android.graphics.drawable.Icon;
@@ -65,4 +66,19 @@ public class BubbleIconFactory extends BaseIconFactory {
return null; 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()); b.isImportantConversation());
info.badgeBitmap = badgeBitmapInfo.icon; info.badgeBitmap = badgeBitmapInfo.icon;
// Raw badge bitmap never includes the important conversation ring // Raw badge bitmap never includes the important conversation ring
info.mRawBadgeBitmap = badgeIconFactory.getBadgeBitmap(badgedIcon, false).icon; info.mRawBadgeBitmap = b.isImportantConversation()
info.bubbleBitmap = iconFactory.createBadgedIconBitmap(bubbleDrawable).icon; ? badgeIconFactory.getBadgeBitmap(badgedIcon, false).icon
: badgeBitmapInfo.icon;
float[] bubbleBitmapScale = new float[1];
info.bubbleBitmap = iconFactory.createIconBitmap(bubbleDrawable, bubbleBitmapScale);
// Dot color & placement // Dot color & placement
Path iconPath = PathParser.createPathFromPathData( Path iconPath = PathParser.createPathFromPathData(
c.getResources().getString(com.android.internal.R.string.config_icon_mask)); c.getResources().getString(com.android.internal.R.string.config_icon_mask));
Matrix matrix = new Matrix(); Matrix matrix = new Matrix();
float scale = iconFactory.getNormalizer().getScale(bubbleDrawable, float scale = bubbleBitmapScale[0];
null /* outBounds */, null /* path */, null /* outMaskShape */);
float radius = DEFAULT_PATH_SIZE / 2f; float radius = DEFAULT_PATH_SIZE / 2f;
matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */, matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
radius /* pivot y */); radius /* pivot y */);