From 0d69cb6ef7cfa1cf1c99575d61ba336782a45f66 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 4 Oct 2021 15:31:38 -0700 Subject: [PATCH] Adding support for dynamic letter spacing for icon labels Bug: 201697936 Test: Manual Change-Id: I0ab81291c40afcac30c5caf7b5638889908775f8 --- src/com/android/launcher3/BubbleTextView.java | 74 +++++++++++++++++++ .../launcher3/config/FeatureFlags.java | 4 + 2 files changed, 78 insertions(+) diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 9da2b798b8..eec6e0ad2e 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING; import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon; import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound; @@ -33,6 +34,7 @@ import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.icu.text.MessageFormat; +import android.text.TextPaint; import android.text.TextUtils.TruncateAt; import android.util.AttributeSet; import android.util.Property; @@ -88,6 +90,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, private static final int DISPLAY_SEARCH_RESULT = 6; private static final int DISPLAY_SEARCH_RESULT_SMALL = 7; + private static final float MIN_LETTER_SPACING = -0.5f; + private static final int MAX_SEARCH_LOOP_COUNT = 20; + private static final int[] STATE_PRESSED = new int[]{android.R.attr.state_pressed}; private static final float HIGHLIGHT_SCALE = 1.16f; @@ -454,6 +459,75 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, return result; } + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + checkForEllipsis(); + } + + @Override + protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { + super.onTextChanged(text, start, lengthBefore, lengthAfter); + checkForEllipsis(); + } + + private void checkForEllipsis() { + if (!ENABLE_ICON_LABEL_AUTO_SCALING.get()) { + return; + } + float width = getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight(); + if (width <= 0) { + return; + } + setLetterSpacing(0); + + String text = getText().toString(); + TextPaint paint = getPaint(); + if (paint.measureText(text) < width) { + return; + } + + float spacing = findBestSpacingValue(paint, text, width, MIN_LETTER_SPACING); + // Reset the paint value so that the call to TextView does appropriate diff. + paint.setLetterSpacing(0); + setLetterSpacing(spacing); + } + + /** + * Find the appropriate text spacing to display the provided text + * @param paint the paint used by the text view + * @param text the text to display + * @param allowedWidthPx available space to render the text + * @param minSpacingEm minimum spacing allowed between characters + * @return the final textSpacing value + * + * @see #setLetterSpacing(float) + */ + private float findBestSpacingValue(TextPaint paint, String text, float allowedWidthPx, + float minSpacingEm) { + paint.setLetterSpacing(minSpacingEm); + if (paint.measureText(text) > allowedWidthPx) { + // If there is no result at high limit, we can do anything more + return minSpacingEm; + } + + float lowLimit = 0; + float highLimit = minSpacingEm; + + for (int i = 0; i < MAX_SEARCH_LOOP_COUNT; i++) { + float value = (lowLimit + highLimit) / 2; + paint.setLetterSpacing(value); + if (paint.measureText(text) < allowedWidthPx) { + highLimit = value; + } else { + lowLimit = value; + } + } + + // At the end error on the higher side + return highLimit; + } + @SuppressWarnings("wrongcall") protected void drawWithoutDot(Canvas canvas) { super.onDraw(canvas); diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 0acafc0b96..f41c19b8e7 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -269,6 +269,10 @@ public final class FeatureFlags { "ENABLE_BACK_SWIPE_HOME_ANIMATION", true, "Enables home animation to icon when user swipes back."); + public static final BooleanFlag ENABLE_ICON_LABEL_AUTO_SCALING = getDebugFlag( + "ENABLE_ICON_LABEL_AUTO_SCALING", true, + "Enables scaling/spacing for icon labels to make more characters visible"); + public static void initialize(Context context) { synchronized (sDebugFlags) { for (DebugFlag flag : sDebugFlags) {