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

Commit 256571bd authored by Yash Garg's avatar Yash Garg 💬 Committed by Mohammed Althaf T
Browse files

feat(dots): notification count support for launcher3 app badges



Signed-off-by: default avataralthafvly <althafvly@gmail.com>
parent 91958f64
Loading
Loading
Loading
Loading
+70 −4
Original line number Diff line number Diff line
@@ -26,10 +26,12 @@ import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.Log;
import android.view.ViewDebug;

import androidx.core.graphics.ColorUtils;

/**
 * Used to draw a notification dot on top of an icon.
 */
@@ -38,10 +40,15 @@ public class DotRenderer {
    private static final String TAG = "DotRenderer";

    // The dot size is defined as a percentage of the app icon size.
    private static final float SIZE_PERCENTAGE = 0.228f;
    private static final float SIZE_PERCENTAGE = 0.21f;
    private static final float SIZE_PERCENTAGE_WITH_COUNT = 0.28f;

    // The max number to draw on dots
    private static final int MAX_COUNT = 99;

    private final float mCircleRadius;
    private final Paint mCirclePaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG);
    private final Paint mTextPaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG);

    private final Bitmap mBackgroundWithShadow;
    private final float mBitmapOffset;
@@ -51,8 +58,16 @@ public class DotRenderer {
    private final float[] mLeftDotPosition;

    private static final int MIN_DOT_SIZE = 1;
    private final Rect mTextRect = new Rect();
    private boolean mDisplayCount;

    public DotRenderer(int iconSizePx, Path iconShapePath, int pathSize) {
        int size = Math.round(SIZE_PERCENTAGE * iconSizePx);
        this(iconSizePx, iconShapePath, pathSize, false, null);
    }

    public DotRenderer(int iconSizePx, Path iconShapePath, int pathSize, Boolean displayCount, Typeface typeface) {
        mDisplayCount = displayCount;
        int size = Math.round((displayCount ? SIZE_PERCENTAGE_WITH_COUNT : SIZE_PERCENTAGE) * iconSizePx);
        if (size <= 0) {
            size = MIN_DOT_SIZE;
        }
@@ -66,6 +81,10 @@ public class DotRenderer {
        // 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);

        mTextPaint.setTextSize(size * 0.65f);
        mTextPaint.setTextAlign(Paint.Align.LEFT);
        mTextPaint.setTypeface(typeface);
    }

    private static float[] getPathPoint(Path path, float size, float direction) {
@@ -97,10 +116,14 @@ public class DotRenderer {
        return mRightDotPosition;
    }

    public void draw(Canvas canvas, DrawParams params) {
        draw(canvas, params, 0);
    }

    /**
     * Draw a circle on top of the canvas according to the given params.
     */
    public void draw(Canvas canvas, DrawParams params) {
    public void draw(Canvas canvas, DrawParams params, int numNotifications) {
        if (params == null) {
            Log.e(TAG, "Invalid null argument(s) passed in call to draw.");
            return;
@@ -127,9 +150,30 @@ public class DotRenderer {
        canvas.drawBitmap(mBackgroundWithShadow, mBitmapOffset, mBitmapOffset, mCirclePaint);
        mCirclePaint.setColor(params.dotColor);
        canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint);

        if (mDisplayCount && numNotifications > 0) {
            // Draw the numNotifications text
            mTextPaint.setColor(getCounterTextColor(Color.WHITE));
            String text = String.valueOf(Math.min(numNotifications, MAX_COUNT));
            mTextPaint.getTextBounds(text, 0, text.length(), mTextRect);
            float x = (-mTextRect.width() / 2f - mTextRect.left) * getAdjustment(numNotifications);
            float y = mTextRect.height() / 2f - mTextRect.bottom;
            canvas.drawText(text, x, y, mTextPaint);
        }

        canvas.restore();
    }

    /**
     * Returns the color to use for the counter text based on the dot's background color.
     *
     * @param dotBackgroundColor The color of the dot background.
     * @return The color to use on the counter text.
     */
    private int getCounterTextColor(int dotBackgroundColor) {
        return ColorUtils.setAlphaComponent(dotBackgroundColor, 0xFF);
    }

    public static class DrawParams {
        /** The color (possibly based on the icon) to use for the dot. */
        @ViewDebug.ExportedProperty(category = "notification dot", formatToHexString = true)
@@ -147,4 +191,26 @@ public class DotRenderer {
        @ViewDebug.ExportedProperty(category = "notification dot")
        public boolean leftAlign;
    }

    /**
     * An attempt to adjust digits to their perceived center, they were tuned with Roboto but should
     * (hopefully) work with other OEM fonts as well.
     */
    private float getAdjustment(int number) {
        switch (number) {
            case 1:
                return 1.01f;
            case 2:
                return 0.99f;
            case 3:
            case 4:
            case 6:
                return 0.98f;
            case 7:
                return 1.02f;
            case 9:
                return 0.9f;
        }
        return 1f;
    }
}