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

Commit e08a2b0a authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Moving the icon shape properties outside of DotRenderer into a separate class

This will eventually allow caching DotRenderer as it is no longer theme dependent

Bug: 432290550
Flag: EXEMPT bugfix
Test: Verified manually
Change-Id: I9e860a096fe7c8869fc58e328e479d287b24e335
parent af469e17
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -73,10 +73,7 @@ public class BubbleIconFactory extends BaseIconFactory {
     * Creates the bitmap for the provided drawable and returns the scale used for
     * drawing the actual drawable. This is used for the larger icon shown for the bubble.
     */
    public Bitmap getBubbleBitmap(@NonNull Drawable icon, float[] outScale) {
        if (outScale != null) {
            outScale[0] = IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
        }
    public Bitmap getBubbleBitmap(@NonNull Drawable icon) {
        return createIconBitmap(
                wrapToAdaptiveIcon(icon),
                IconNormalizer.ICON_VISIBLE_AREA_FACTOR,
+64 −38
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.graphics.Color.luminance;
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;

import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
import static com.android.systemui.shared.Flags.notificationDotContrastBorder;

import android.graphics.Bitmap;
@@ -28,10 +29,12 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.Log;
import android.view.ViewDebug;

import androidx.annotation.NonNull;
import androidx.core.graphics.ColorUtils;

/**
@@ -52,12 +55,9 @@ public class DotRenderer {
    private final Bitmap mBackgroundWithShadow;
    private final float mBitmapOffset;

    // Stores the center x and y position as a percentage (0 to 1) of the icon size
    private final float[] mRightDotPosition;
    private final float[] mLeftDotPosition;

    private static final int MIN_DOT_SIZE = 1;
    public DotRenderer(int iconSizePx, Path iconShapePath, int pathSize) {

    public DotRenderer(int iconSizePx) {
        int size = Math.round(SIZE_PERCENTAGE * iconSizePx);
        if (size <= 0) {
            size = MIN_DOT_SIZE;
@@ -68,13 +68,9 @@ public class DotRenderer {
        mCircleRadius = builder.radius;

        mBitmapOffset = -mBackgroundWithShadow.getHeight() * 0.5f; // Same as width.

        // Find the points on the path that are closest to the top left and right corners.
        mLeftDotPosition = getPathPoint(iconShapePath, pathSize, -1);
        mRightDotPosition = getPathPoint(iconShapePath, pathSize, 1);
    }

    private static float[] getPathPoint(Path path, float size, float direction) {
    private static PointF getPathPoint(Path path, float size, float direction) {
        float halfSize = size / 2;
        // Small delta so that we don't get a zero size triangle
        float delta = 1;
@@ -89,18 +85,7 @@ public class DotRenderer {
        trianglePath.op(path, Path.Op.INTERSECT);
        float[] pos = new float[2];
        new PathMeasure(trianglePath, false).getPosTan(0, pos, null);

        pos[0] = pos[0] / size;
        pos[1] = pos[1] / size;
        return pos;
    }

    public float[] getLeftDotPosition() {
        return mLeftDotPosition;
    }

    public float[] getRightDotPosition() {
        return mRightDotPosition;
        return new PointF(pos[0] / size, pos[1] / size);
    }

    /**
@@ -114,9 +99,9 @@ public class DotRenderer {
        canvas.save();

        Rect iconBounds = params.iconBounds;
        float[] dotPosition = params.leftAlign ? mLeftDotPosition : mRightDotPosition;
        float dotCenterX = iconBounds.left + iconBounds.width() * dotPosition[0];
        float dotCenterY = iconBounds.top + iconBounds.height() * dotPosition[1];
        PointF dotPosition = params.getDotPosition();
        float dotCenterX = iconBounds.left + iconBounds.width() * dotPosition.x;
        float dotCenterY = iconBounds.top + iconBounds.height() * dotPosition.y;

        // Ensure dot fits entirely in canvas clip bounds.
        Rect canvasBounds = canvas.getClipBounds();
@@ -133,25 +118,14 @@ public class DotRenderer {
        mCirclePaint.setColor(Color.BLACK);
        canvas.drawBitmap(mBackgroundWithShadow, mBitmapOffset, mBitmapOffset, mCirclePaint);

        // Draw Colored Dot - Update dot color to have sufficient accessibility contrast
        if (notificationDotContrastBorder() && luminance(params.dotColor) < LUMINENSCE_LIMIT) {
            double[] lab = new double[3];
            ColorUtils.colorToLAB(params.dotColor, lab);
            params.dotColor = ColorUtils.LABToColor(100 * LUMINENSCE_LIMIT, lab[1], lab[2]);
        }

        mCirclePaint.setColor(params.dotColor);
        mCirclePaint.setColor(params.mDotColor);
        canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint);
        canvas.restore();
    }

    public static class DrawParams {
        /** The color (possibly based on the icon) to use for the dot. */
        @ViewDebug.ExportedProperty(category = "notification dot", formatToHexString = true)
        public int dotColor;
        /** The color (possibly based on the icon) to use for a predicted app. */
        @ViewDebug.ExportedProperty(category = "notification dot", formatToHexString = true)
        public int appColor;
        private int mDotColor;
        /** The bounds of the icon that the dot is drawn on top of. */
        @ViewDebug.ExportedProperty(category = "notification dot")
        public Rect iconBounds = new Rect();
@@ -161,5 +135,57 @@ public class DotRenderer {
        /** Whether the dot should align to the top left of the icon rather than the top right. */
        @ViewDebug.ExportedProperty(category = "notification dot")
        public boolean leftAlign;

        @NonNull
        public IconShapeInfo shapeInfo = IconShapeInfo.DEFAULT;

        public PointF getDotPosition() {
            return leftAlign ? shapeInfo.leftCornerPosition : shapeInfo.rightCornerPosition;
        }

        /** The color (possibly based on the icon) to use for the dot. */
        public void setDotColor(int color) {
            mDotColor = color;

            if (notificationDotContrastBorder() && luminance(color) < LUMINENSCE_LIMIT) {
                double[] lab = new double[3];
                ColorUtils.colorToLAB(color, lab);
                mDotColor = ColorUtils.LABToColor(100 * LUMINENSCE_LIMIT, lab[1], lab[2]);
            }
        }
    }

    /**
     * Class stores information about the icon icon shape on which the dot is being rendered.
     * It stores the center x and y position as a percentage (0 to 1) of the icon size
     */
    public record IconShapeInfo(PointF leftCornerPosition, PointF rightCornerPosition) {

        /** Shape when the icon rendered completely fills {@link DrawParams#iconBounds} */
        public static IconShapeInfo DEFAULT =
                fromPath(IconShape.EMPTY.path, IconShape.EMPTY.pathSize);

        /** Shape when a normalized icon is rendered within {@link DrawParams#iconBounds} */
        public static IconShapeInfo DEFAULT_NORMALIZED = new IconShapeInfo(
                normalizedPosition(DEFAULT.leftCornerPosition),
                normalizedPosition(DEFAULT.rightCornerPosition)
        );

        /**
         * Creates an IconShapeInfo from the provided path in bounds [0, 0, pathSize, pathSize]
         */
        public static IconShapeInfo fromPath(Path path, int pathSize) {
            return new IconShapeInfo(
                    getPathPoint(path, pathSize, -1),
                    getPathPoint(path, pathSize, 1));
        }

        private static PointF normalizedPosition(PointF pos) {
            float center = 0.5f;
            return new PointF(
                    center + ICON_VISIBLE_AREA_FACTOR * (pos.x - center),
                    center + ICON_VISIBLE_AREA_FACTOR * (pos.y - center)
            );
        }
    }
}