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

Commit 41571691 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Offer to format data sizes in either IEC or SI.

Add flags to let callers specify if they want IEC (power-of-two) or
SI (power-of-ten) units when formatting bytes.

Continue using SI units by default, since certain folks seem to have
strong opinions about that.

Bug: 76159924
Test: atest android.text.format.FormatterTest
Exempt-From-Owner-Approval: previous PS approved
Change-Id: I0074bb2578c2230e938b3f39c2564b1083feb825
parent f28034e8
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -40,6 +40,10 @@ public final class Formatter {
    public static final int FLAG_SHORTER = 1 << 0;
    /** {@hide} */
    public static final int FLAG_CALCULATE_ROUNDED = 1 << 1;
    /** {@hide} */
    public static final int FLAG_SI_UNITS = 1 << 2;
    /** {@hide} */
    public static final int FLAG_IEC_UNITS = 1 << 3;

    /** {@hide} */
    public static class BytesResult {
@@ -90,7 +94,7 @@ public final class Formatter {
        if (context == null) {
            return "";
        }
        final BytesResult res = formatBytes(context.getResources(), sizeBytes, 0);
        final BytesResult res = formatBytes(context.getResources(), sizeBytes, FLAG_SI_UNITS);
        return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
                res.value, res.units));
    }
@@ -103,41 +107,43 @@ public final class Formatter {
        if (context == null) {
            return "";
        }
        final BytesResult res = formatBytes(context.getResources(), sizeBytes, FLAG_SHORTER);
        final BytesResult res = formatBytes(context.getResources(), sizeBytes,
                FLAG_SI_UNITS | FLAG_SHORTER);
        return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
                res.value, res.units));
    }

    /** {@hide} */
    public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) {
        final int unit = ((flags & FLAG_IEC_UNITS) != 0) ? 1024 : 1000;
        final boolean isNegative = (sizeBytes < 0);
        float result = isNegative ? -sizeBytes : sizeBytes;
        int suffix = com.android.internal.R.string.byteShort;
        long mult = 1;
        if (result > 900) {
            suffix = com.android.internal.R.string.kilobyteShort;
            mult = 1000;
            result = result / 1000;
            mult = unit;
            result = result / unit;
        }
        if (result > 900) {
            suffix = com.android.internal.R.string.megabyteShort;
            mult *= 1000;
            result = result / 1000;
            mult *= unit;
            result = result / unit;
        }
        if (result > 900) {
            suffix = com.android.internal.R.string.gigabyteShort;
            mult *= 1000;
            result = result / 1000;
            mult *= unit;
            result = result / unit;
        }
        if (result > 900) {
            suffix = com.android.internal.R.string.terabyteShort;
            mult *= 1000;
            result = result / 1000;
            mult *= unit;
            result = result / unit;
        }
        if (result > 900) {
            suffix = com.android.internal.R.string.petabyteShort;
            mult *= 1000;
            result = result / 1000;
            mult *= unit;
            result = result / unit;
        }
        // Note we calculate the rounded long by ourselves, but still let String.format()
        // compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to
+31 −3
Original line number Diff line number Diff line
@@ -16,12 +16,14 @@

package android.text.format;

import static android.text.format.Formatter.FLAG_IEC_UNITS;
import static android.text.format.Formatter.FLAG_SI_UNITS;

import static org.junit.Assert.assertEquals;

import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.icu.util.MeasureUnit;
import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
@@ -34,7 +36,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Locale;
import java.util.Set;

@Presubmit
@SmallTest
@@ -104,6 +105,27 @@ public class FormatterTest {
        checkFormatBytes(9123000, false, "9,12", 9120000);
    }

    @Test
    public void testFormatBytesSi() {
        setLocale(Locale.US);

        checkFormatBytes(1_000, FLAG_SI_UNITS, "1.00", 1_000);
        checkFormatBytes(1_024, FLAG_SI_UNITS, "1.02", 1_020);
        checkFormatBytes(1_500, FLAG_SI_UNITS, "1.50", 1_500);
        checkFormatBytes(12_582_912L, FLAG_SI_UNITS, "12.58", 12_580_000L);
    }

    @Test
    public void testFormatBytesIec() {
        setLocale(Locale.US);

        checkFormatBytes(1_000, FLAG_IEC_UNITS, "0.98", 1_003);
        checkFormatBytes(1_024, FLAG_IEC_UNITS, "1.00", 1_024);
        checkFormatBytes(1_500, FLAG_IEC_UNITS, "1.46", 1_495);
        checkFormatBytes(12_500_000L, FLAG_IEC_UNITS, "11.92", 12_499_025L);
        checkFormatBytes(12_582_912L, FLAG_IEC_UNITS, "12.00", 12_582_912L);
    }

    private static final long SECOND = 1000;
    private static final long MINUTE = 60 * SECOND;
    private static final long HOUR = 60 * MINUTE;
@@ -195,8 +217,14 @@ public class FormatterTest {

    private void checkFormatBytes(long bytes, boolean useShort,
            String expectedString, long expectedRounded) {
        checkFormatBytes(bytes, (useShort ? Formatter.FLAG_SHORTER : 0),
                expectedString, expectedRounded);
    }

    private void checkFormatBytes(long bytes, int flags,
            String expectedString, long expectedRounded) {
        BytesResult r = Formatter.formatBytes(mContext.getResources(), bytes,
                Formatter.FLAG_CALCULATE_ROUNDED | (useShort ? Formatter.FLAG_SHORTER : 0));
                Formatter.FLAG_CALCULATE_ROUNDED | flags);
        assertEquals(expectedString, r.value);
        assertEquals(expectedRounded, r.roundedBytes);
    }