Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24f130cb authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Optimizing some icon generation code in bubble

> Generating only one bitmap when creating appIcon
> Extracting the scale during icon generation for main icon
  instead of running icon normalizer again
> Avoiding unnecessary color extraction on main icon

Bug: 238937089
Test: Verified on device
Change-Id: Ia01801f15e5982593852f05c2512d0f1f737f5f7
parent f5b0a3e3
Loading
Loading
Loading
Loading
+67 −68
Original line number Diff line number Diff line
@@ -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) {
            final float 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);
            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);
        }

        @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);
            mTempBounds.set(getBounds());
            mTempBounds.inset(ringStrokeWidth, ringStrokeWidth);
            mDr.setBounds(mTempBounds);
            mDr.draw(canvas);
            canvas.restoreToCount(save);
        }
    }

    private static class CircularAdaptiveIcon extends AdaptiveIconDrawable {

        final Path mPath = new Path();

        CircularAdaptiveIcon(Drawable bg, Drawable fg) {
            super(bg, fg);
        }

        @Override
        public Path getIconMask() {
            mPath.reset();
            Rect bounds = getBounds();
            mPath.addOval(bounds.left, bounds.top, bounds.right, bounds.bottom, Path.Direction.CW);
            return mPath;
        }

    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);

        // 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);

        // Draw background.
        background.setBounds(0, 0, size, size);
        background.draw(canvas);

        // 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);

        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);
        }
    }
}
+16 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+7 −4
Original line number Diff line number Diff line
@@ -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 */);