From b8f2dd53e0e19ea376639a610a0b51faabf0f9af Mon Sep 17 00:00:00 2001 From: conradchen Date: Thu, 2 Dec 2021 20:07:56 +0000 Subject: [PATCH] [Badge] Support different locale on badges Resolves https://github.com/material-components/material-components-android/issues/2465 PiperOrigin-RevId: 413738198 --- .../android/material/badge/BadgeDrawable.java | 32 +++++++++++++++++-- .../material/badge/BadgeDrawableTest.java | 6 ++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/lib/java/com/google/android/material/badge/BadgeDrawable.java b/lib/java/com/google/android/material/badge/BadgeDrawable.java index ffedc032d22..b5de8d913a6 100644 --- a/lib/java/com/google/android/material/badge/BadgeDrawable.java +++ b/lib/java/com/google/android/material/badge/BadgeDrawable.java @@ -31,6 +31,8 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; @@ -64,6 +66,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.text.NumberFormat; +import java.util.Locale; /** * {@code BadgeDrawable} contains all the layout and draw logic for a badge. @@ -210,6 +213,7 @@ public static final class SavedState implements Parcelable { @StringRes private int contentDescriptionExceedsMaxBadgeNumberRes; @BadgeGravity private int badgeGravity; private boolean isVisible; + private Locale numberLocale; @Dimension(unit = Dimension.PX) private int horizontalOffsetWithoutText; @@ -241,6 +245,10 @@ public SavedState(@NonNull Context context) { contentDescriptionExceedsMaxBadgeNumberRes = R.string.mtrl_exceed_max_badge_number_content_description; isVisible = true; + numberLocale = + VERSION.SDK_INT >= VERSION_CODES.N + ? Locale.getDefault(Locale.Category.FORMAT) + : Locale.getDefault(); } protected SavedState(@NonNull Parcel in) { @@ -259,6 +267,7 @@ protected SavedState(@NonNull Parcel in) { additionalHorizontalOffset = in.readInt(); additionalVerticalOffset = in.readInt(); isVisible = in.readInt() != 0; + numberLocale = (Locale) in.readSerializable(); } public static final Creator CREATOR = @@ -298,6 +307,7 @@ public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(additionalHorizontalOffset); dest.writeInt(additionalVerticalOffset); dest.writeInt(isVisible ? 1 : 0); + dest.writeSerializable(numberLocale); } } @@ -371,6 +381,7 @@ public void setVisible(boolean visible) { private void restoreFromSavedState(@NonNull SavedState savedState) { setMaxCharacterCount(savedState.maxCharacterCount); + setBadgeNumberLocale(savedState.numberLocale); // Only set the badge number if it exists in the style. // Defaulting it to 0 means the badge will incorrectly show text when the user may want a @@ -647,6 +658,20 @@ public void setBadgeTextColor(@ColorInt int badgeTextColor) { } } + /** Returns the {@link Locale} used to show badge numbers. */ + @NonNull + public Locale getBadgeNumberLocale() { + return savedState.numberLocale; + } + + /** Sets the {@link Locale} used to show badge numbers. */ + public void setBadgeNumberLocale(@NonNull Locale locale) { + if (!locale.equals(savedState.numberLocale)) { + savedState.numberLocale = locale; + invalidateSelf(); + } + } + /** Returns whether this badge will display a number. */ public boolean hasNumber() { return savedState.number != BADGE_NUMBER_NONE; @@ -1137,15 +1162,16 @@ private void drawText(Canvas canvas) { private String getBadgeText() { // If number exceeds max count, show badgeMaxCount+ instead of the number. if (getNumber() <= maxBadgeNumber) { - return NumberFormat.getInstance().format(getNumber()); + return NumberFormat.getInstance(savedState.numberLocale).format(getNumber()); } else { Context context = contextRef.get(); if (context == null) { return ""; } - return context.getString( - R.string.mtrl_exceed_max_badge_number_suffix, + return String.format( + savedState.numberLocale, + context.getString(R.string.mtrl_exceed_max_badge_number_suffix), maxBadgeNumber, DEFAULT_EXCEED_MAX_BADGE_NUMBER_SUFFIX); } diff --git a/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java b/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java index 6965d143755..7db19850019 100644 --- a/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java +++ b/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java @@ -31,6 +31,7 @@ import androidx.test.core.app.ApplicationProvider; import com.google.android.material.badge.BadgeDrawable.SavedState; import com.google.android.material.drawable.DrawableUtils; +import java.util.Locale; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -44,6 +45,7 @@ public class BadgeDrawableTest { private static final int TEST_BADGE_NUMBER = 26; + private static final Locale TEST_BADGE_NUMBER_LOCALE = new Locale("ar"); private static final int TEST_BADGE_HORIZONTAL_OFFSET = 10; private static final int TEST_BADGE_VERTICAL_OFFSET = 5; @@ -84,6 +86,7 @@ public void testSavedState() { badgeDrawable.setBackgroundColor(testBackgroundColor); badgeDrawable.setBadgeTextColor(testBadgeTextColor); badgeDrawable.setVisible(false); + badgeDrawable.setBadgeNumberLocale(TEST_BADGE_NUMBER_LOCALE); Parcel parcel = Parcel.obtain(); drawableState.writeToParcel(parcel, drawableState.describeContents()); @@ -110,6 +113,9 @@ public void testSavedState() { // badge visibility assertThat(restoredBadgeDrawable.isVisible()).isFalse(); + + // badge number locale + assertThat(restoredBadgeDrawable.getBadgeNumberLocale()).isEqualTo(TEST_BADGE_NUMBER_LOCALE); } // Verify that the hardcoded badge gravity attribute values match their piped Gravity counter