Merge "AutoSize TextView - support - correct pixel transformations" into oc-support-26.0-dev
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java
index 140f707..bc83b2d 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java
@@ -62,7 +62,7 @@
     // 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.
-    static final int UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE = -1;
+    static final float UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE = -1f;
     // Ported from TextView#VERY_WIDE. Represents a maximum width in pixels the TextView takes when
     // horizontal scrolling is activated.
     private static final int VERY_WIDE = 1024 * 1024;
@@ -71,11 +71,11 @@
     // 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 = new int[0];
@@ -96,9 +96,9 @@
     }
 
     void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
-        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;
 
         TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.AppCompatTextView,
                 defStyleAttr, 0);
@@ -107,17 +107,17 @@
                     TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);
         }
         if (a.hasValue(R.styleable.AppCompatTextView_autoSizeStepGranularity)) {
-            autoSizeStepGranularityInPx = a.getDimensionPixelSize(
+            autoSizeStepGranularityInPx = a.getDimension(
                     R.styleable.AppCompatTextView_autoSizeStepGranularity,
                     UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE);
         }
         if (a.hasValue(R.styleable.AppCompatTextView_autoSizeMinTextSize)) {
-            autoSizeMinTextSizeInPx = a.getDimensionPixelSize(
+            autoSizeMinTextSizeInPx = a.getDimension(
                     R.styleable.AppCompatTextView_autoSizeMinTextSize,
                     UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE);
         }
         if (a.hasValue(R.styleable.AppCompatTextView_autoSizeMaxTextSize)) {
-            autoSizeMaxTextSizeInPx = a.getDimensionPixelSize(
+            autoSizeMaxTextSizeInPx = a.getDimension(
                     R.styleable.AppCompatTextView_autoSizeMaxTextSize,
                     UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE);
         }
@@ -143,14 +143,14 @@
                             mContext.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);
@@ -197,11 +197,11 @@
                 case TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM:
                     final DisplayMetrics displayMetrics =
                             mContext.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);
@@ -256,11 +256,11 @@
             int unit) throws IllegalArgumentException {
         if (supportsAutoSizeText()) {
             final DisplayMetrics displayMetrics = mContext.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,
@@ -307,8 +307,8 @@
                             mContext.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));
                     }
                 }
 
@@ -356,7 +356,7 @@
      */
     @RestrictTo(LIBRARY_GROUP)
     int getAutoSizeStepGranularity() {
-        return mAutoSizeStepGranularityInPx;
+        return Math.round(mAutoSizeStepGranularityInPx);
     }
 
     /**
@@ -372,7 +372,7 @@
      */
     @RestrictTo(LIBRARY_GROUP)
     int getAutoSizeMinTextSize() {
-        return mAutoSizeMinTextSizeInPx;
+        return Math.round(mAutoSizeMinTextSizeInPx);
     }
 
     /**
@@ -388,7 +388,7 @@
      */
     @RestrictTo(LIBRARY_GROUP)
     int getAutoSizeMaxTextSize() {
-        return mAutoSizeMaxTextSizeInPx;
+        return Math.round(mAutoSizeMaxTextSizeInPx);
     }
 
     /**
@@ -465,9 +465,9 @@
      * @throws IllegalArgumentException if any of the params are invalid
      */
     private void validateAndSetAutoSizeTextTypeUniformConfiguration(
-            int autoSizeMinTextSizeInPx,
-            int autoSizeMaxTextSizeInPx,
-            int autoSizeStepGranularityInPx) throws IllegalArgumentException {
+            float autoSizeMinTextSizeInPx,
+            float autoSizeMaxTextSizeInPx,
+            float autoSizeStepGranularityInPx) throws IllegalArgumentException {
         // First validate.
         if (autoSizeMinTextSizeInPx <= 0) {
             throw new IllegalArgumentException("Minimum auto-size text size ("
@@ -502,18 +502,19 @@
                 // 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;
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewAutoSizeTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewAutoSizeTest.java
index 2b8aa5c..3b95732 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewAutoSizeTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewAutoSizeTest.java
@@ -47,6 +47,74 @@
     }
 
     @Test
+    public void testAutoSizeUniform_equivalentConfigurations() throws Throwable {
+        final DisplayMetrics dm = getActivity().getResources().getDisplayMetrics();
+        final int minTextSize = 10;
+        final int maxTextSize = 20;
+        final int granularity = 2;
+        final int unit = TypedValue.COMPLEX_UNIT_SP;
+
+        final AppCompatTextView granularityTextView = new AppCompatTextView(getActivity());
+        granularityTextView.setAutoSizeTextTypeUniformWithConfiguration(
+                minTextSize, maxTextSize, granularity, unit);
+
+        final AppCompatTextView presetTextView = new AppCompatTextView(getActivity());
+        presetTextView.setAutoSizeTextTypeUniformWithPresetSizes(
+                new int[]{minTextSize, 12, 14, 16, 18, maxTextSize}, unit);
+
+        // The TextViews have been configured differently but the end result should be nearly
+        // identical.
+        final int expectedAutoSizeType = AppCompatTextView.AUTO_SIZE_TEXT_TYPE_UNIFORM;
+        assertEquals(expectedAutoSizeType, granularityTextView.getAutoSizeTextType());
+        assertEquals(expectedAutoSizeType, presetTextView.getAutoSizeTextType());
+
+        final int expectedMinTextSizeInPx = Math.round(
+                TypedValue.applyDimension(unit, minTextSize, dm));
+        assertEquals(expectedMinTextSizeInPx, granularityTextView.getAutoSizeMinTextSize());
+        assertEquals(expectedMinTextSizeInPx, presetTextView.getAutoSizeMinTextSize());
+
+        final int expectedMaxTextSizeInPx = Math.round(
+                TypedValue.applyDimension(unit, maxTextSize, dm));
+        assertEquals(expectedMaxTextSizeInPx, granularityTextView.getAutoSizeMaxTextSize());
+        assertEquals(expectedMaxTextSizeInPx, presetTextView.getAutoSizeMaxTextSize());
+
+        // Configured with granularity.
+        assertEquals(Math.round(TypedValue.applyDimension(unit, granularity, dm)),
+                granularityTextView.getAutoSizeStepGranularity());
+        // Configured with preset values, there is no granularity.
+        assertEquals(-1, presetTextView.getAutoSizeStepGranularity());
+
+        // Both TextViews generate exactly the same sizes in pixels to choose from when auto-sizing.
+        assertArrayEquals(
+                granularityTextView.getAutoSizeTextAvailableSizes(),
+                presetTextView.getAutoSizeTextAvailableSizes());
+
+        final String someText = "This is a string";
+        final int widthHeight = 600;
+        // Configure identically and attach to layout.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                LinearLayout ll = getActivity().findViewById(R.id.layout_textviewtest);
+                ll.removeAllViews();
+                ll.addView(granularityTextView);
+                ll.addView(presetTextView);
+
+                granularityTextView.setText(someText);
+                granularityTextView.setWidth(widthHeight);
+                granularityTextView.setHeight(widthHeight);
+
+                presetTextView.setText(someText);
+                presetTextView.setWidth(widthHeight);
+                presetTextView.setHeight(widthHeight);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+        assertEquals(granularityTextView.getTextSize(), presetTextView.getTextSize(), 0f);
+    }
+
+    @Test
     public void testAutoSize_notSupportedByEditText() throws Throwable {
         final AppCompatEditText autoSizeEditText = (AppCompatEditText) getActivity().findViewById(
                 R.id.edittext_autosize_uniform);
@@ -757,8 +825,8 @@
 
         // It does not matter which unit has been used to set the min size, the getter always
         // returns it in pixels.
-        Assert.assertEquals((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, newMinSize,
-                getActivity().getResources().getDisplayMetrics()),
+        Assert.assertEquals(Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
+                newMinSize, getActivity().getResources().getDisplayMetrics())),
                         textView.getAutoSizeMinTextSize());
     }
 
@@ -818,8 +886,8 @@
                 TypedValue.COMPLEX_UNIT_SP);
         // It does not matter which unit has been used to set the max size, the getter always
         // returns it in pixels.
-        Assert.assertEquals((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, newMaxSize,
-                getActivity().getResources().getDisplayMetrics()),
+        Assert.assertEquals(Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
+                newMaxSize, getActivity().getResources().getDisplayMetrics())),
                         textView.getAutoSizeMaxTextSize());
     }