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

Commit d4082bb9 authored by Andrei Stingaceanu's avatar Andrei Stingaceanu
Browse files

AutoSize TextView - correct pixel transformations

When configuring a TextView to auto-size via min/max/granularity
do the calculations in float pixels and only convert to int (via
rounding, see TypedArray#getDimensionPixelSize) to produce the
final text size values to be used by the auto-size algorithm.
This is because the previous version where the values were
initially directly converted to pixels and only after used in
calculations was losing precision and was not consistent with how
we deal with preset configuration (and the developer
expectations).

Practically

textView1.setAutoSizeTextTypeUniformWithConfiguration(10, 20, 2,
        TypedValue.COMPLEX_UNIT_SP)

and

textView2.setAutoSizeTextTypeUniformWithPresetSizes(
         new int[] {10, 12, 14, 16, 18, 20},
         TypedValue.COMPLEX_UNIT_SP);

produce exactly the same values in pixels to choose from when
auto-sizing (on any device) =>
(TextView#getAutoSizeTextAvailableSizes())

Bug: 38185233
Bug: 37265610
Test: attached in the same topic
Change-Id: I95cbbf4674e98f080d7752ae350df26b4adf31b4
parent ab516db3
Loading
Loading
Loading
Loading
+29 −28
Original line number Diff line number Diff line
@@ -746,17 +746,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    // Default value for the step size in pixels.
    private static final int DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX = 1;
    // Use this to specify that any of the auto-size configuration int values have not been set.
    private static final int UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE = -1;
    private static final float UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE = -1f;
    // Auto-size text type.
    private int mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_NONE;
    // Specify if auto-size text is needed.
    private boolean mNeedsAutoSizeText = false;
    // Step size for auto-sizing in pixels.
    private int mAutoSizeStepGranularityInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
    private float mAutoSizeStepGranularityInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
    // Minimum text size for auto-sizing in pixels.
    private int mAutoSizeMinTextSizeInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
    private float mAutoSizeMinTextSizeInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
    // Maximum text size for auto-sizing in pixels.
    private int mAutoSizeMaxTextSizeInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
    private float mAutoSizeMaxTextSizeInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
    // Contains a (specified or computed) distinct sorted set of text sizes in pixels to pick from
    // when auto-sizing text.
    private int[] mAutoSizeTextSizesInPx = EmptyArray.INT;
@@ -987,9 +987,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        CharSequence text = "";
        CharSequence hint = null;
        boolean password = false;
        int autoSizeMinTextSizeInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
        int autoSizeMaxTextSizeInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
        int autoSizeStepGranularityInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
        float autoSizeMinTextSizeInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
        float autoSizeMaxTextSizeInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
        float autoSizeStepGranularityInPx = UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE;
        int inputType = EditorInfo.TYPE_NULL;
        a = theme.obtainStyledAttributes(
                    attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes);
@@ -1363,17 +1363,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    break;

                case com.android.internal.R.styleable.TextView_autoSizeStepGranularity:
                    autoSizeStepGranularityInPx = a.getDimensionPixelSize(attr,
                    autoSizeStepGranularityInPx = a.getDimension(attr,
                        UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE);
                    break;

                case com.android.internal.R.styleable.TextView_autoSizeMinTextSize:
                    autoSizeMinTextSizeInPx = a.getDimensionPixelSize(attr,
                    autoSizeMinTextSizeInPx = a.getDimension(attr,
                        UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE);
                    break;

                case com.android.internal.R.styleable.TextView_autoSizeMaxTextSize:
                    autoSizeMaxTextSizeInPx = a.getDimensionPixelSize(attr,
                    autoSizeMaxTextSizeInPx = a.getDimension(attr,
                        UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE);
                    break;

@@ -1675,14 +1675,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();

                    if (autoSizeMinTextSizeInPx == UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE) {
                        autoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
                        autoSizeMinTextSizeInPx = TypedValue.applyDimension(
                                TypedValue.COMPLEX_UNIT_SP,
                                DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP,
                                displayMetrics);
                    }

                    if (autoSizeMaxTextSizeInPx == UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE) {
                        autoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
                        autoSizeMaxTextSizeInPx = TypedValue.applyDimension(
                                TypedValue.COMPLEX_UNIT_SP,
                                DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP,
                                displayMetrics);
@@ -1727,11 +1727,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    break;
                case AUTO_SIZE_TEXT_TYPE_UNIFORM:
                    final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
                    final int autoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
                    final float autoSizeMinTextSizeInPx = TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP,
                            DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP,
                            displayMetrics);
                    final int autoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
                    final float autoSizeMaxTextSizeInPx = TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP,
                            DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP,
                            displayMetrics);
@@ -1780,11 +1780,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            int autoSizeMaxTextSize, int autoSizeStepGranularity, int unit) {
        if (supportsAutoSizeText()) {
            final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
            final int autoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
            final float autoSizeMinTextSizeInPx = TypedValue.applyDimension(
                    unit, autoSizeMinTextSize, displayMetrics);
            final int autoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
            final float autoSizeMaxTextSizeInPx = TypedValue.applyDimension(
                    unit, autoSizeMaxTextSize, displayMetrics);
            final int autoSizeStepGranularityInPx = (int) TypedValue.applyDimension(
            final float autoSizeStepGranularityInPx = TypedValue.applyDimension(
                    unit, autoSizeStepGranularity, displayMetrics);

            validateAndSetAutoSizeTextTypeUniformConfiguration(autoSizeMinTextSizeInPx,
@@ -1826,8 +1826,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
                    // Convert all to sizes to pixels.
                    for (int i = 0; i < presetSizesLength; i++) {
                        presetSizesInPx[i] = (int) TypedValue.applyDimension(unit, presetSizes[i],
                            displayMetrics);
                        presetSizesInPx[i] = Math.round(TypedValue.applyDimension(unit,
                            presetSizes[i], displayMetrics));
                    }
                }

@@ -1869,7 +1869,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     * @see #setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int)
     */
    public int getAutoSizeStepGranularity() {
        return mAutoSizeStepGranularityInPx;
        return Math.round(mAutoSizeStepGranularityInPx);
    }

    /**
@@ -1882,7 +1882,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     * @see #setAutoSizeTextTypeUniformWithPresetSizes(int[], int)
     */
    public int getAutoSizeMinTextSize() {
        return mAutoSizeMinTextSizeInPx;
        return Math.round(mAutoSizeMinTextSizeInPx);
    }

    /**
@@ -1895,7 +1895,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     * @see #setAutoSizeTextTypeUniformWithPresetSizes(int[], int)
     */
    public int getAutoSizeMaxTextSize() {
        return mAutoSizeMaxTextSizeInPx;
        return Math.round(mAutoSizeMaxTextSizeInPx);
    }

    /**
@@ -1938,8 +1938,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     *
     * @throws IllegalArgumentException if any of the params are invalid
     */
    private void validateAndSetAutoSizeTextTypeUniformConfiguration(int autoSizeMinTextSizeInPx,
            int autoSizeMaxTextSizeInPx, int autoSizeStepGranularityInPx) {
    private void validateAndSetAutoSizeTextTypeUniformConfiguration(float autoSizeMinTextSizeInPx,
            float autoSizeMaxTextSizeInPx, float autoSizeStepGranularityInPx) {
        // First validate.
        if (autoSizeMinTextSizeInPx <= 0) {
            throw new IllegalArgumentException("Minimum auto-size text size ("
@@ -2005,18 +2005,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                // Calculate sizes to choose from based on the current auto-size configuration.
                int autoSizeValuesLength = (int) Math.ceil(
                        (mAutoSizeMaxTextSizeInPx - mAutoSizeMinTextSizeInPx)
                                / (float) mAutoSizeStepGranularityInPx);
                                / mAutoSizeStepGranularityInPx);
                // Also reserve a slot for the max size if it fits.
                if ((mAutoSizeMaxTextSizeInPx - mAutoSizeMinTextSizeInPx)
                        % mAutoSizeStepGranularityInPx == 0) {
                    autoSizeValuesLength++;
                }
                mAutoSizeTextSizesInPx = new int[autoSizeValuesLength];
                int sizeToAdd = mAutoSizeMinTextSizeInPx;
                int[] autoSizeTextSizesInPx = new int[autoSizeValuesLength];
                float sizeToAdd = mAutoSizeMinTextSizeInPx;
                for (int i = 0; i < autoSizeValuesLength; i++) {
                    mAutoSizeTextSizesInPx[i] = sizeToAdd;
                    autoSizeTextSizesInPx[i] = Math.round(sizeToAdd);
                    sizeToAdd += mAutoSizeStepGranularityInPx;
                }
                mAutoSizeTextSizesInPx = cleanupAutoSizePresetSizes(autoSizeTextSizesInPx);
            }

            mNeedsAutoSizeText = true;