From 99e123528e6ddb91bd940c817b53de2da3fb207e Mon Sep 17 00:00:00 2001 From: Yash Garg Date: Thu, 24 Aug 2023 12:44:40 +0530 Subject: [PATCH 01/11] chore: support for gradle standalone build --- iconloaderlib/build.gradle | 33 ++++++--------------------------- searchuilib/build.gradle | 26 +------------------------- 2 files changed, 7 insertions(+), 52 deletions(-) diff --git a/iconloaderlib/build.gradle b/iconloaderlib/build.gradle index 10ec889d..7b92aac6 100644 --- a/iconloaderlib/build.gradle +++ b/iconloaderlib/build.gradle @@ -1,36 +1,15 @@ -apply plugin: 'com.android.library' +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} android { - compileSdkVersion COMPILE_SDK - buildToolsVersion BUILD_TOOLS_VERSION - - defaultConfig { - minSdkVersion 26 - targetSdkVersion 28 - } - + namespace "com.android.launcher3.icons" sourceSets { main { - java.srcDirs = ['src', 'src_full_lib'] + java.srcDirs = ['src'] manifest.srcFile 'AndroidManifest.xml' res.srcDirs = ['res'] } } - - lintOptions { - abortOnError false - } - - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - -dependencies { - implementation "androidx.core:core:${ANDROID_X_VERSION}" } diff --git a/searchuilib/build.gradle b/searchuilib/build.gradle index 3bf65fe6..fb113409 100644 --- a/searchuilib/build.gradle +++ b/searchuilib/build.gradle @@ -1,35 +1,11 @@ apply plugin: 'com.android.library' android { - compileSdkVersion COMPILE_SDK - buildToolsVersion BUILD_TOOLS_VERSION - - defaultConfig { - minSdkVersion 25 - targetSdkVersion 28 - } - + namespace "com.android.app.search" sourceSets { main { java.srcDirs = ['src'] manifest.srcFile 'AndroidManifest.xml' } } - - lintOptions { - abortOnError false - } - - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - -dependencies { - implementation "androidx.core:core:${ANDROID_X_VERSION}" } -- GitLab From a551ef59bb3a07f690c57ec8e9851991a823b08c Mon Sep 17 00:00:00 2001 From: Yash Garg Date: Mon, 27 Mar 2023 21:17:45 +0530 Subject: [PATCH 02/11] feat(dots): notification count support for launcher3 app badges --- .../android/launcher3/icons/DotRenderer.java | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java index 97a0fd3f..9d1dbb6c 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java +++ b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java @@ -27,9 +27,12 @@ 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 +41,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; @@ -50,8 +58,12 @@ public class DotRenderer { private final float[] mRightDotPosition; private final float[] mLeftDotPosition; - public DotRenderer(int iconSizePx, Path iconShapePath, int pathSize) { - int size = Math.round(SIZE_PERCENTAGE * iconSizePx); + private final Rect mTextRect = new Rect(); + private final boolean mDisplayCount; + + 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); ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT); builder.ambientShadowAlpha = 88; mBackgroundWithShadow = builder.setupBlurForSize(size).createPill(size, size); @@ -62,6 +74,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) { @@ -96,7 +112,7 @@ public class DotRenderer { /** * 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; @@ -123,9 +139,30 @@ public class DotRenderer { canvas.drawBitmap(mBackgroundWithShadow, mBitmapOffset, mBitmapOffset, mCirclePaint); mCirclePaint.setColor(params.color); 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) @@ -140,4 +177,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; + } } -- GitLab From 0316457d47ef17c7f2eea0cbb24af6e75526860b Mon Sep 17 00:00:00 2001 From: TheScarastic Date: Thu, 13 Apr 2023 18:49:02 +0530 Subject: [PATCH 03/11] iconloader: Add unchanges constructor for aosp --- .../src/com/android/launcher3/icons/DotRenderer.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java index 9d1dbb6c..52b4919b 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java +++ b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java @@ -61,6 +61,10 @@ public class DotRenderer { private final Rect mTextRect = new Rect(); private final boolean mDisplayCount; + public DotRenderer(int iconSizePx, Path iconShapePath, int pathSize) { + 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); @@ -112,6 +116,10 @@ public class DotRenderer { /** * Draw a circle on top of the canvas according to the given params. */ + public void draw(Canvas canvas, DrawParams params) { + draw(canvas, params, 0); + } + public void draw(Canvas canvas, DrawParams params, int numNotifications) { if (params == null) { Log.e(TAG, "Invalid null argument(s) passed in call to draw."); -- GitLab From 8b9ed99a08fb9a7e548a8080b1fbe298930bdcfd Mon Sep 17 00:00:00 2001 From: TheScarastic Date: Fri, 29 Sep 2023 13:26:56 +0530 Subject: [PATCH 04/11] feat(icons): Add month icon support for calendar --- .../android/launcher3/icons/IconProvider.java | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java b/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java index 449c0daa..a4dd4bf0 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java +++ b/iconloaderlib/src/com/android/launcher3/icons/IconProvider.java @@ -32,6 +32,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.XmlResourceParser; +import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; @@ -70,6 +71,9 @@ public class IconProvider { private static final boolean DEBUG = false; private static final String ICON_METADATA_KEY_PREFIX = ".dynamic_icons"; + private static final String MONTH_BG_ICON_METADATA_KEY_PREFIX = ".month_dynamic_icons"; + private static final String DAY_FG_ICON_METADATA_KEY_PREFIX = ".day_dynamic_icons"; + private static final String SYSTEM_STATE_SEPARATOR = " "; private static final String THEMED_ICON_MAP_FILE = "grayscale_icon_map"; @@ -223,6 +227,7 @@ public class IconProvider { } private Drawable loadCalendarDrawable(int iconDpi) { + Log.e("lulz", "loading cal iconn"); PackageManager pm = mContext.getPackageManager(); try { final Bundle metadata = pm.getActivityInfo( @@ -231,9 +236,15 @@ public class IconProvider { .metaData; final Resources resources = pm.getResourcesForApplication(mCalendar.getPackageName()); final int id = getDynamicIconId(metadata, resources); - if (id != ID_NULL) { + final int[] monthDayIds = getDynamicBackgroundIconId(metadata, resources); + if (id != ID_NULL && (monthDayIds == null || + monthDayIds[0] == ID_NULL || monthDayIds[1] == ID_NULL)) { if (DEBUG) Log.d(TAG, "Got icon #" + id); return resources.getDrawableForDensity(id, iconDpi, null /* theme */); + } else if (monthDayIds != null) { + Drawable background = resources.getDrawableForDensity(monthDayIds[0], iconDpi, null /* theme */); + Drawable foreground = resources.getDrawableForDensity(monthDayIds[1], iconDpi, null /* theme */); + return new AdaptiveIconDrawable(background, foreground); } } catch (PackageManager.NameNotFoundException e) { if (DEBUG) { @@ -272,6 +283,29 @@ public class IconProvider { } } + private int[] getDynamicBackgroundIconId(Bundle metadata, Resources resources) { + if (metadata == null) { + return null; + } + String bgKey = mCalendar.getPackageName() + MONTH_BG_ICON_METADATA_KEY_PREFIX; + String fgKey = mCalendar.getPackageName() + DAY_FG_ICON_METADATA_KEY_PREFIX; + final int bgArrayId = metadata.getInt(bgKey, ID_NULL); + final int fgArrayId = metadata.getInt(fgKey, ID_NULL); + if (bgArrayId == ID_NULL || fgArrayId == ID_NULL) { + return null; + } + try { + return new int[] {resources.obtainTypedArray(bgArrayId).getResourceId(getMonth(), ID_NULL), + resources.obtainTypedArray(fgArrayId).getResourceId(getDay(), ID_NULL)}; + } catch (Resources.NotFoundException e) { + if (DEBUG) { + Log.d(TAG, "package defines '" + bgKey + " and " + fgKey + "' but corresponding array not found"); + } + return null; + } + } + + /** * @return Today's day of the month, zero-indexed. */ @@ -279,6 +313,10 @@ public class IconProvider { return Calendar.getInstance().get(Calendar.DAY_OF_MONTH) - 1; } + private static int getMonth() { + return Calendar.getInstance().get(Calendar.MONTH); + } + private static ComponentName parseComponentOrNull(Context context, int resId) { String cn = context.getString(resId); return TextUtils.isEmpty(cn) ? null : ComponentName.unflattenFromString(cn); -- GitLab From dafcb2c1a32614c7b509031f7d0a9963299fc628 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Tue, 24 Jan 2023 02:13:06 +0200 Subject: [PATCH 05/11] ClockDrawableWrapper: Set DISABLE_SECONDS to false Change-Id: I63c53af5ad2d029063f2b7eedb20b02f42ccd0a1 --- .../src/com/android/launcher3/icons/ClockDrawableWrapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java b/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java index d2cbe72f..e79d11f5 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java +++ b/iconloaderlib/src/com/android/launcher3/icons/ClockDrawableWrapper.java @@ -59,7 +59,7 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap private static final String TAG = "ClockDrawableWrapper"; - private static final boolean DISABLE_SECONDS = true; + private static final boolean DISABLE_SECONDS = false; // Time after which the clock icon should check for an update. The actual invalidate // will only happen in case of any change. -- GitLab From 06aca6deaf2ed10bb594a91e1533994ca3cb5bff Mon Sep 17 00:00:00 2001 From: Yash Garg Date: Thu, 19 Oct 2023 18:18:49 +0530 Subject: [PATCH 06/11] chore: improve adaptive icons --- iconloaderlib/Android.bp | 4 +++ .../launcher3/icons/AdaptiveIconGenerator.kt | 26 +++++++++++++++++++ .../launcher3/icons/BaseIconFactory.java | 7 +++-- 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 iconloaderlib/src/com/android/launcher3/icons/AdaptiveIconGenerator.kt diff --git a/iconloaderlib/Android.bp b/iconloaderlib/Android.bp index 6867e6b5..fa3a34fe 100644 --- a/iconloaderlib/Android.bp +++ b/iconloaderlib/Android.bp @@ -22,12 +22,14 @@ android_library { min_sdk_version: "26", static_libs: [ "androidx.core_core", + "androidx.core_core-ktx", ], resource_dirs: [ "res", ], srcs: [ "src/**/*.java", + "src/**/*.kt", ], } @@ -37,6 +39,7 @@ android_library { min_sdk_version: "26", static_libs: [ "androidx.core_core", + "androidx.core_core-ktx", ], resource_dirs: [ "res", @@ -44,5 +47,6 @@ android_library { srcs: [ "src/**/*.java", "src_full_lib/**/*.java", + "src/**/*.kt", ], } diff --git a/iconloaderlib/src/com/android/launcher3/icons/AdaptiveIconGenerator.kt b/iconloaderlib/src/com/android/launcher3/icons/AdaptiveIconGenerator.kt new file mode 100644 index 00000000..4a38395b --- /dev/null +++ b/iconloaderlib/src/com/android/launcher3/icons/AdaptiveIconGenerator.kt @@ -0,0 +1,26 @@ +package com.android.launcher3.icons + +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import androidx.core.graphics.drawable.toBitmap + +object AdaptiveIconGenerator { + private const val ICON_SCALE = 1.46f + + @JvmStatic + fun toBitmap(drawable: Drawable) = drawable.toBitmap() + + @JvmStatic + fun getScale(bitmap: Bitmap, scale: Float): Float { + val topRightPx = bitmap.getPixel(0, 0) + val topLeftPx = bitmap.getPixel(0, bitmap.height - 1) + val bottomRightPx = bitmap.getPixel(bitmap.width - 1, 0) + val bottomLeftPx = bitmap.getPixel(bitmap.width - 1, bitmap.height - 1) + + return if (!(topRightPx != 0 && topLeftPx != 0 && bottomRightPx != 0 && bottomLeftPx != 0)) { + scale + } else { + ICON_SCALE + } + } +} diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java index f5ce8144..2f960fbf 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java @@ -26,6 +26,7 @@ import android.os.Process; import android.os.UserHandle; import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; import com.android.launcher3.icons.BitmapInfo.Extender; @@ -305,11 +306,13 @@ public class BaseIconFactory implements AutoCloseable { if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) { FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground()); fsd.setDrawable(icon); - fsd.setScale(scale); + Bitmap bitmap = AdaptiveIconGenerator.toBitmap(icon); + fsd.setScale(AdaptiveIconGenerator.getScale(bitmap, scale)); icon = dr; scale = getNormalizer().getScale(icon, outIconBounds, null, null); - ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor); + int color = ColorUtils.setAlphaComponent(new ColorExtractor().findDominantColorByHue(bitmap), 200); + ((ColorDrawable) dr.getBackground()).setColor(color); } } else { scale = getNormalizer().getScale(icon, outIconBounds, null, null); -- GitLab From bbfed6e5e7e43d2a4cc76875bd51bcc238827f51 Mon Sep 17 00:00:00 2001 From: Yash Garg Date: Wed, 6 Dec 2023 19:26:42 +0530 Subject: [PATCH 07/11] feat: convert badge to round rect when count > 99 --- .../android/launcher3/icons/DotRenderer.java | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java index 52b4919b..7bcf476b 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java +++ b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java @@ -140,18 +140,32 @@ public class DotRenderer { float offsetY = Math.max(0, canvasBounds.top - (dotCenterY + mBitmapOffset)); // We draw the dot relative to its center. - canvas.translate(dotCenterX + offsetX, dotCenterY + offsetY); - canvas.scale(params.scale, params.scale); + float dx = dotCenterX + offsetX; + float dy = dotCenterY + offsetY - 15f; + + if (numNotifications > 9 && numNotifications < 100) { + canvas.translate(dx - 3f, dy); + } else if (numNotifications > 99 && numNotifications < 1000) { + canvas.translate(dx + 6f, dy); + } else { + canvas.translate(dx - 12f, dy); + } - mCirclePaint.setColor(Color.BLACK); - canvas.drawBitmap(mBackgroundWithShadow, mBitmapOffset, mBitmapOffset, mCirclePaint); mCirclePaint.setColor(params.color); - canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint); + if (numNotifications > 9 && numNotifications < 100) { + canvas.drawRoundRect(new RectF(-mCircleRadius - 10, -mCircleRadius, mCircleRadius + 10, mCircleRadius), 50, 50, mCirclePaint); + } else if (numNotifications > 99 && numNotifications < 1000) { + canvas.drawRoundRect(new RectF(-mCircleRadius - 20, -mCircleRadius, mCircleRadius + 20, mCircleRadius), 50, 50, mCirclePaint); + } else { + 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.setTextSize(42f); + mTextPaint.setTypeface(Typeface.DEFAULT_BOLD); + String text = numToNotation(numNotifications); mTextPaint.getTextBounds(text, 0, text.length(), mTextRect); float x = (-mTextRect.width() / 2f - mTextRect.left) * getAdjustment(numNotifications); float y = mTextRect.height() / 2f - mTextRect.bottom; @@ -161,6 +175,14 @@ public class DotRenderer { canvas.restore(); } + private String numToNotation(int num) { + if (num < 1000) { + return String.valueOf(num); + } else { + return num / 1000 + "k"; + } + } + /** * Returns the color to use for the counter text based on the dot's background color. * -- GitLab From 5c7953736183e027d7228a25b356bd275755d7b7 Mon Sep 17 00:00:00 2001 From: TheScarastic Date: Tue, 12 Dec 2023 14:08:26 +0530 Subject: [PATCH 08/11] DotRenderer: Add shadow to notification dots --- .../src/com/android/launcher3/icons/DotRenderer.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java index 7bcf476b..972f00bf 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java +++ b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java @@ -49,6 +49,8 @@ public class DotRenderer { private final float mCircleRadius; private final Paint mCirclePaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG); + private final Paint mCircleShadowPaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG); + private final Paint mTextPaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG); private final Bitmap mBackgroundWithShadow; @@ -152,11 +154,15 @@ public class DotRenderer { } mCirclePaint.setColor(params.color); + mCircleShadowPaint.setColor(params.shadowDotColor); if (numNotifications > 9 && numNotifications < 100) { + canvas.drawRoundRect(new RectF(-mCircleRadius - 10, -mCircleRadius, mCircleRadius + 10, mCircleRadius + 3), 50, 50, mCircleShadowPaint); canvas.drawRoundRect(new RectF(-mCircleRadius - 10, -mCircleRadius, mCircleRadius + 10, mCircleRadius), 50, 50, mCirclePaint); } else if (numNotifications > 99 && numNotifications < 1000) { + canvas.drawRoundRect(new RectF(-mCircleRadius - 20, -mCircleRadius, mCircleRadius + 20, mCircleRadius + 3), 50, 50, mCircleShadowPaint); canvas.drawRoundRect(new RectF(-mCircleRadius - 20, -mCircleRadius, mCircleRadius + 20, mCircleRadius), 50, 50, mCirclePaint); } else { + canvas.drawCircle(0, 3, mCircleRadius, mCircleShadowPaint); canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint); } @@ -206,6 +212,8 @@ 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; + @ViewDebug.ExportedProperty(category = "notification dot", formatToHexString = true) + public int shadowDotColor; } /** -- GitLab From f5c37962a3ecb2dfa84b8aa389d872b2f774dd40 Mon Sep 17 00:00:00 2001 From: Yash Garg Date: Thu, 1 Feb 2024 12:56:39 +0530 Subject: [PATCH 09/11] fix: check height width before converting to bitmap --- .../android/launcher3/icons/BaseIconFactory.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java index 2f960fbf..051a33f1 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java @@ -305,13 +305,19 @@ public class BaseIconFactory implements AutoCloseable { scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape); if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) { FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground()); - fsd.setDrawable(icon); - Bitmap bitmap = AdaptiveIconGenerator.toBitmap(icon); - fsd.setScale(AdaptiveIconGenerator.getScale(bitmap, scale)); + + int color; + if (icon.getIntrinsicHeight() > 0 && icon.getIntrinsicWidth() > 0) { + Bitmap bitmap = AdaptiveIconGenerator.toBitmap(icon); + fsd.setScale(AdaptiveIconGenerator.getScale(bitmap, scale)); + color = ColorUtils.setAlphaComponent(new ColorExtractor().findDominantColorByHue(bitmap), 200); + } else { + fsd.setScale(scale); + color = mWrapperBackgroundColor; + } + icon = dr; scale = getNormalizer().getScale(icon, outIconBounds, null, null); - - int color = ColorUtils.setAlphaComponent(new ColorExtractor().findDominantColorByHue(bitmap), 200); ((ColorDrawable) dr.getBackground()).setColor(color); } } else { -- GitLab From 0085dae76f3f17285c7ada5e1ca7c0c7391a39db Mon Sep 17 00:00:00 2001 From: TheScarastic Date: Tue, 20 Feb 2024 16:55:43 +0530 Subject: [PATCH 10/11] fixup!: check height width before converting to bitmap --- .../src/com/android/launcher3/icons/BaseIconFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java index 051a33f1..88265b87 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java @@ -305,6 +305,7 @@ public class BaseIconFactory implements AutoCloseable { scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape); if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) { FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground()); + fsd.setDrawable(icon); int color; if (icon.getIntrinsicHeight() > 0 && icon.getIntrinsicWidth() > 0) { -- GitLab From def0947c3f66a17a308ed8d68f88d4aaaf2e3fb7 Mon Sep 17 00:00:00 2001 From: althafvly Date: Thu, 29 Feb 2024 21:22:20 +0530 Subject: [PATCH 11/11] feat: adjust dot size accordingly --- .../android/launcher3/icons/DotRenderer.java | 51 +++++++------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java index 972f00bf..5209c092 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java +++ b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java @@ -72,7 +72,7 @@ public class DotRenderer { int size = Math.round((displayCount ? SIZE_PERCENTAGE_WITH_COUNT : SIZE_PERCENTAGE) * iconSizePx); ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT); builder.ambientShadowAlpha = 88; - mBackgroundWithShadow = builder.setupBlurForSize(size).createPill(size, size); + mBackgroundWithShadow = builder.setupBlurForSize(size).createPill(size, displayCount ? (size - 25) : size); mCircleRadius = builder.radius; mBitmapOffset = -mBackgroundWithShadow.getHeight() * 0.5f; // Same as width. @@ -155,27 +155,32 @@ public class DotRenderer { mCirclePaint.setColor(params.color); mCircleShadowPaint.setColor(params.shadowDotColor); - if (numNotifications > 9 && numNotifications < 100) { - canvas.drawRoundRect(new RectF(-mCircleRadius - 10, -mCircleRadius, mCircleRadius + 10, mCircleRadius + 3), 50, 50, mCircleShadowPaint); - canvas.drawRoundRect(new RectF(-mCircleRadius - 10, -mCircleRadius, mCircleRadius + 10, mCircleRadius), 50, 50, mCirclePaint); - } else if (numNotifications > 99 && numNotifications < 1000) { - canvas.drawRoundRect(new RectF(-mCircleRadius - 20, -mCircleRadius, mCircleRadius + 20, mCircleRadius + 3), 50, 50, mCircleShadowPaint); - canvas.drawRoundRect(new RectF(-mCircleRadius - 20, -mCircleRadius, mCircleRadius + 20, mCircleRadius), 50, 50, mCirclePaint); + + if (numNotifications >= 10 && numNotifications < 1000) { + canvas.drawRoundRect(new RectF(-mCircleRadius + 10, -mCircleRadius, mCircleRadius + 20, mCircleRadius), 50, 50, mCircleShadowPaint); + canvas.drawRoundRect(new RectF(-mCircleRadius + 10, -mCircleRadius, mCircleRadius + 20, mCircleRadius), 50, 50, mCirclePaint); } else { - canvas.drawCircle(0, 3, mCircleRadius, mCircleShadowPaint); - canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint); + canvas.drawCircle(5, 10, mCircleRadius, mCircleShadowPaint); + canvas.drawCircle(5, 10, mCircleRadius, mCirclePaint); } if (mDisplayCount && numNotifications > 0) { // Draw the numNotifications text mTextPaint.setColor(getCounterTextColor(Color.WHITE)); - mTextPaint.setTextSize(42f); mTextPaint.setTypeface(Typeface.DEFAULT_BOLD); + mTextPaint.setTextSize(32f); String text = numToNotation(numNotifications); 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); + if (numNotifications < 10) { + canvas.drawText(text, -4f, 22f, mTextPaint); + } else if (numNotifications < 100) { + canvas.drawText(text, -4f, y, mTextPaint); + } else if (numNotifications >= 1000) { + canvas.drawText(text, -14f, 20f, mTextPaint); + } else { + canvas.drawText(text, -14f, y, mTextPaint); + } } canvas.restore(); @@ -215,26 +220,4 @@ public class DotRenderer { @ViewDebug.ExportedProperty(category = "notification dot", formatToHexString = true) public int shadowDotColor; } - - /** - * 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; - } } -- GitLab