Loading res/layout/data_usage_bytes_editor.xml +1 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ android:id="@+id/size_spinner" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center_vertical" android:entries="@array/bytes_picker_sizes" /> android:layout_gravity="center_vertical" /> </LinearLayout> res/values/strings.xml +0 −5 Original line number Diff line number Diff line Loading @@ -11307,11 +11307,6 @@ <!-- Text for the setting on whether you can type text into notifications without unlocking the device. --> <string name="lockscreen_remote_input">If device is locked, prevent typing replies or other text in notifications</string> <string-array name="bytes_picker_sizes" translatable="false"> <item>@*android:string/megabyteShort</item> <item>@*android:string/gigabyteShort</item> </string-array> <!-- [CHAR LIMIT=30] Label for setting to control the default spell checker --> <string name="default_spell_checker">Default spell checker</string> src/com/android/settings/datausage/BillingCycleSettings.java +14 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; import android.icu.text.MeasureFormat; import android.icu.util.MeasureUnit; import android.net.NetworkPolicy; import android.net.NetworkTemplate; import android.os.Bundle; Loading @@ -30,6 +32,7 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.EditorInfo; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.NumberPicker; import android.widget.Spinner; Loading Loading @@ -301,6 +304,17 @@ public class BillingCycleSettings extends DataUsageBaseFragment implements : editor.getPolicyWarningBytes(template); final long limitDisabled = isLimit ? LIMIT_DISABLED : WARNING_DISABLED; final MeasureFormat formatter = MeasureFormat.getInstance( getContext().getResources().getConfiguration().locale, MeasureFormat.FormatWidth.SHORT); final String[] unitNames = new String[] { formatter.getUnitDisplayName(MeasureUnit.MEGABYTE), formatter.getUnitDisplayName(MeasureUnit.GIGABYTE) }; final ArrayAdapter<String> adapter = new ArrayAdapter<String>( getContext(), android.R.layout.simple_spinner_item, unitNames); type.setAdapter(adapter); final boolean unitInGigaBytes = (bytes > 1.5f * GIB_IN_BYTES); final String bytesText = formatText(bytes, unitInGigaBytes ? GIB_IN_BYTES : MIB_IN_BYTES); Loading src/com/android/settings/utils/FileSizeFormatter.java +80 −25 Original line number Diff line number Diff line Loading @@ -16,11 +16,20 @@ package com.android.settings.utils; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; import android.icu.text.DecimalFormat; import android.icu.text.MeasureFormat; import android.icu.text.NumberFormat; import android.icu.util.Measure; import android.icu.util.MeasureUnit; import android.text.BidiFormatter; import android.text.format.Formatter; import android.text.TextUtils; import android.view.View; import java.math.BigDecimal; import java.util.Locale; /** * Utility class to aid in formatting file sizes always with the same unit. This is modified from Loading @@ -31,6 +40,61 @@ public final class FileSizeFormatter { public static final long MEGABYTE_IN_BYTES = KILOBYTE_IN_BYTES * 1000; public static final long GIGABYTE_IN_BYTES = MEGABYTE_IN_BYTES * 1000; private static class RoundedBytesResult { public final float value; public final MeasureUnit units; public final int fractionDigits; public final long roundedBytes; private RoundedBytesResult( float value, MeasureUnit units, int fractionDigits, long roundedBytes) { this.value = value; this.units = units; this.fractionDigits = fractionDigits; this.roundedBytes = roundedBytes; } } private static Locale localeFromContext(@NonNull Context context) { return context.getResources().getConfiguration().locale; } private static String bidiWrap(@NonNull Context context, String source) { final Locale locale = localeFromContext(context); if (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL) { return BidiFormatter.getInstance(true /* RTL*/).unicodeWrap(source); } else { return source; } } private static NumberFormat getNumberFormatter(Locale locale, int fractionDigits) { final NumberFormat numberFormatter = NumberFormat.getInstance(locale); numberFormatter.setMinimumFractionDigits(fractionDigits); numberFormatter.setMaximumFractionDigits(fractionDigits); numberFormatter.setGroupingUsed(false); if (numberFormatter instanceof DecimalFormat) { // We do this only for DecimalFormat, since in the general NumberFormat case, calling // setRoundingMode may throw an exception. numberFormatter.setRoundingMode(BigDecimal.ROUND_HALF_UP); } return numberFormatter; } private static String formatMeasureShort(Locale locale, NumberFormat numberFormatter, float value, MeasureUnit units) { final MeasureFormat measureFormatter = MeasureFormat.getInstance( locale, MeasureFormat.FormatWidth.SHORT, numberFormatter); return measureFormatter.format(new Measure(value, units)); } private static String formatRoundedBytesResult( @NonNull Context context, @NonNull RoundedBytesResult input) { final Locale locale = localeFromContext(context); final NumberFormat numberFormatter = getNumberFormatter(locale, input.fractionDigits); return formatMeasureShort(locale, numberFormatter, input.value, input.units); } /** * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc. * Loading @@ -47,23 +111,17 @@ public final class FileSizeFormatter { * * @param context Context to use to load the localized units * @param sizeBytes size value to be formatted, in bytes * @param suffix String id for the unit suffix. * @param mult Amount of bytes in the unit. * @return formatted string with the number * @param unit The unit used for formatting. * @param mult Amount of bytes in the unit. * @return formatted string with the number */ public static String formatFileSize( @Nullable Context context, long sizeBytes, int suffix, long mult) { @Nullable Context context, long sizeBytes, MeasureUnit unit, long mult) { if (context == null) { return ""; } final Formatter.BytesResult res = formatBytes(context.getResources(), sizeBytes, suffix, mult); return BidiFormatter.getInstance() .unicodeWrap(context.getString(getFileSizeSuffix(context), res.value, res.units)); } private static int getFileSizeSuffix(Context context) { final Resources res = context.getResources(); return res.getIdentifier("fileSizeSuffix", "string", "android"); final RoundedBytesResult res = formatBytes(sizeBytes, unit, mult); return bidiWrap(context, formatRoundedBytesResult(context, res)); } /** Loading @@ -76,8 +134,8 @@ public final class FileSizeFormatter { * @param suffix String id for the unit suffix. * @param mult Amount of bytes in the unit. */ private static Formatter.BytesResult formatBytes( Resources res, long sizeBytes, int suffix, long mult) { private static RoundedBytesResult formatBytes( long sizeBytes, MeasureUnit unit, long mult) { final boolean isNegative = (sizeBytes < 0); float result = isNegative ? -sizeBytes : sizeBytes; result = result / mult; Loading @@ -85,32 +143,29 @@ public final class FileSizeFormatter { // compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to // floating point errors. final int roundFactor; final String roundFormat; final int roundDigits; if (mult == 1) { roundFactor = 1; roundFormat = "%.0f"; roundDigits = 0; } else if (result < 1) { roundFactor = 100; roundFormat = "%.2f"; roundDigits = 2; } else if (result < 10) { roundFactor = 10; roundFormat = "%.1f"; roundDigits = 1; } else { // 10 <= result < 100 roundFactor = 1; roundFormat = "%.0f"; roundDigits = 0; } if (isNegative) { result = -result; } final String roundedString = String.format(roundFormat, result); // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so // it's okay (for now)... final long roundedBytes = (((long) Math.round(result * roundFactor)) * mult / roundFactor); final String units = res.getString(suffix); return new Formatter.BytesResult(roundedString, units, roundedBytes); return new RoundedBytesResult(result, unit, roundDigits, roundedBytes); } } tests/legacy_unit/src/com/android/settings/utils/FileSizeFormatterTest.java +8 −6 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.settings.utils; import static com.android.settings.utils.FileSizeFormatter.GIGABYTE_IN_BYTES; import static com.android.settings.utils.FileSizeFormatter.MEGABYTE_IN_BYTES; import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.icu.util.MeasureUnit; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; Loading @@ -46,7 +48,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, 0 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("0.00 GB"); } Loading @@ -57,7 +59,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, MEGABYTE_IN_BYTES * 11 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("0.01 GB"); } Loading @@ -68,7 +70,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, MEGABYTE_IN_BYTES * 155 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("0.16 GB"); } Loading @@ -79,7 +81,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, MEGABYTE_IN_BYTES * 1551 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("1.6 GB"); } Loading @@ -91,7 +93,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, GIGABYTE_IN_BYTES * 15 + MEGABYTE_IN_BYTES * 50 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("15 GB"); } Loading @@ -102,7 +104,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, MEGABYTE_IN_BYTES * -155 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("-0.16 GB"); } Loading Loading
res/layout/data_usage_bytes_editor.xml +1 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ android:id="@+id/size_spinner" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center_vertical" android:entries="@array/bytes_picker_sizes" /> android:layout_gravity="center_vertical" /> </LinearLayout>
res/values/strings.xml +0 −5 Original line number Diff line number Diff line Loading @@ -11307,11 +11307,6 @@ <!-- Text for the setting on whether you can type text into notifications without unlocking the device. --> <string name="lockscreen_remote_input">If device is locked, prevent typing replies or other text in notifications</string> <string-array name="bytes_picker_sizes" translatable="false"> <item>@*android:string/megabyteShort</item> <item>@*android:string/gigabyteShort</item> </string-array> <!-- [CHAR LIMIT=30] Label for setting to control the default spell checker --> <string name="default_spell_checker">Default spell checker</string>
src/com/android/settings/datausage/BillingCycleSettings.java +14 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; import android.icu.text.MeasureFormat; import android.icu.util.MeasureUnit; import android.net.NetworkPolicy; import android.net.NetworkTemplate; import android.os.Bundle; Loading @@ -30,6 +32,7 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.EditorInfo; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.NumberPicker; import android.widget.Spinner; Loading Loading @@ -301,6 +304,17 @@ public class BillingCycleSettings extends DataUsageBaseFragment implements : editor.getPolicyWarningBytes(template); final long limitDisabled = isLimit ? LIMIT_DISABLED : WARNING_DISABLED; final MeasureFormat formatter = MeasureFormat.getInstance( getContext().getResources().getConfiguration().locale, MeasureFormat.FormatWidth.SHORT); final String[] unitNames = new String[] { formatter.getUnitDisplayName(MeasureUnit.MEGABYTE), formatter.getUnitDisplayName(MeasureUnit.GIGABYTE) }; final ArrayAdapter<String> adapter = new ArrayAdapter<String>( getContext(), android.R.layout.simple_spinner_item, unitNames); type.setAdapter(adapter); final boolean unitInGigaBytes = (bytes > 1.5f * GIB_IN_BYTES); final String bytesText = formatText(bytes, unitInGigaBytes ? GIB_IN_BYTES : MIB_IN_BYTES); Loading
src/com/android/settings/utils/FileSizeFormatter.java +80 −25 Original line number Diff line number Diff line Loading @@ -16,11 +16,20 @@ package com.android.settings.utils; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; import android.icu.text.DecimalFormat; import android.icu.text.MeasureFormat; import android.icu.text.NumberFormat; import android.icu.util.Measure; import android.icu.util.MeasureUnit; import android.text.BidiFormatter; import android.text.format.Formatter; import android.text.TextUtils; import android.view.View; import java.math.BigDecimal; import java.util.Locale; /** * Utility class to aid in formatting file sizes always with the same unit. This is modified from Loading @@ -31,6 +40,61 @@ public final class FileSizeFormatter { public static final long MEGABYTE_IN_BYTES = KILOBYTE_IN_BYTES * 1000; public static final long GIGABYTE_IN_BYTES = MEGABYTE_IN_BYTES * 1000; private static class RoundedBytesResult { public final float value; public final MeasureUnit units; public final int fractionDigits; public final long roundedBytes; private RoundedBytesResult( float value, MeasureUnit units, int fractionDigits, long roundedBytes) { this.value = value; this.units = units; this.fractionDigits = fractionDigits; this.roundedBytes = roundedBytes; } } private static Locale localeFromContext(@NonNull Context context) { return context.getResources().getConfiguration().locale; } private static String bidiWrap(@NonNull Context context, String source) { final Locale locale = localeFromContext(context); if (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL) { return BidiFormatter.getInstance(true /* RTL*/).unicodeWrap(source); } else { return source; } } private static NumberFormat getNumberFormatter(Locale locale, int fractionDigits) { final NumberFormat numberFormatter = NumberFormat.getInstance(locale); numberFormatter.setMinimumFractionDigits(fractionDigits); numberFormatter.setMaximumFractionDigits(fractionDigits); numberFormatter.setGroupingUsed(false); if (numberFormatter instanceof DecimalFormat) { // We do this only for DecimalFormat, since in the general NumberFormat case, calling // setRoundingMode may throw an exception. numberFormatter.setRoundingMode(BigDecimal.ROUND_HALF_UP); } return numberFormatter; } private static String formatMeasureShort(Locale locale, NumberFormat numberFormatter, float value, MeasureUnit units) { final MeasureFormat measureFormatter = MeasureFormat.getInstance( locale, MeasureFormat.FormatWidth.SHORT, numberFormatter); return measureFormatter.format(new Measure(value, units)); } private static String formatRoundedBytesResult( @NonNull Context context, @NonNull RoundedBytesResult input) { final Locale locale = localeFromContext(context); final NumberFormat numberFormatter = getNumberFormatter(locale, input.fractionDigits); return formatMeasureShort(locale, numberFormatter, input.value, input.units); } /** * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc. * Loading @@ -47,23 +111,17 @@ public final class FileSizeFormatter { * * @param context Context to use to load the localized units * @param sizeBytes size value to be formatted, in bytes * @param suffix String id for the unit suffix. * @param mult Amount of bytes in the unit. * @return formatted string with the number * @param unit The unit used for formatting. * @param mult Amount of bytes in the unit. * @return formatted string with the number */ public static String formatFileSize( @Nullable Context context, long sizeBytes, int suffix, long mult) { @Nullable Context context, long sizeBytes, MeasureUnit unit, long mult) { if (context == null) { return ""; } final Formatter.BytesResult res = formatBytes(context.getResources(), sizeBytes, suffix, mult); return BidiFormatter.getInstance() .unicodeWrap(context.getString(getFileSizeSuffix(context), res.value, res.units)); } private static int getFileSizeSuffix(Context context) { final Resources res = context.getResources(); return res.getIdentifier("fileSizeSuffix", "string", "android"); final RoundedBytesResult res = formatBytes(sizeBytes, unit, mult); return bidiWrap(context, formatRoundedBytesResult(context, res)); } /** Loading @@ -76,8 +134,8 @@ public final class FileSizeFormatter { * @param suffix String id for the unit suffix. * @param mult Amount of bytes in the unit. */ private static Formatter.BytesResult formatBytes( Resources res, long sizeBytes, int suffix, long mult) { private static RoundedBytesResult formatBytes( long sizeBytes, MeasureUnit unit, long mult) { final boolean isNegative = (sizeBytes < 0); float result = isNegative ? -sizeBytes : sizeBytes; result = result / mult; Loading @@ -85,32 +143,29 @@ public final class FileSizeFormatter { // compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to // floating point errors. final int roundFactor; final String roundFormat; final int roundDigits; if (mult == 1) { roundFactor = 1; roundFormat = "%.0f"; roundDigits = 0; } else if (result < 1) { roundFactor = 100; roundFormat = "%.2f"; roundDigits = 2; } else if (result < 10) { roundFactor = 10; roundFormat = "%.1f"; roundDigits = 1; } else { // 10 <= result < 100 roundFactor = 1; roundFormat = "%.0f"; roundDigits = 0; } if (isNegative) { result = -result; } final String roundedString = String.format(roundFormat, result); // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so // it's okay (for now)... final long roundedBytes = (((long) Math.round(result * roundFactor)) * mult / roundFactor); final String units = res.getString(suffix); return new Formatter.BytesResult(roundedString, units, roundedBytes); return new RoundedBytesResult(result, unit, roundDigits, roundedBytes); } }
tests/legacy_unit/src/com/android/settings/utils/FileSizeFormatterTest.java +8 −6 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.settings.utils; import static com.android.settings.utils.FileSizeFormatter.GIGABYTE_IN_BYTES; import static com.android.settings.utils.FileSizeFormatter.MEGABYTE_IN_BYTES; import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.icu.util.MeasureUnit; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; Loading @@ -46,7 +48,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, 0 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("0.00 GB"); } Loading @@ -57,7 +59,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, MEGABYTE_IN_BYTES * 11 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("0.01 GB"); } Loading @@ -68,7 +70,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, MEGABYTE_IN_BYTES * 155 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("0.16 GB"); } Loading @@ -79,7 +81,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, MEGABYTE_IN_BYTES * 1551 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("1.6 GB"); } Loading @@ -91,7 +93,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, GIGABYTE_IN_BYTES * 15 + MEGABYTE_IN_BYTES * 50 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("15 GB"); } Loading @@ -102,7 +104,7 @@ public class FileSizeFormatterTest { FileSizeFormatter.formatFileSize( mContext, MEGABYTE_IN_BYTES * -155 /* size */, com.android.internal.R.string.gigabyteShort, MeasureUnit.GIGABYTE, GIGABYTE_IN_BYTES)) .isEqualTo("-0.16 GB"); } Loading