summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andrei Stingaceanu <stg@google.com> 2017-01-27 15:31:19 +0000
committer Andrei Stingaceanu <stg@google.com> 2017-02-08 12:48:21 +0000
commit9fe208fe6b0c0aef797a2d3757f50b88ecd86a0c (patch)
treebb9e5f807e2d2ed49a1c3f977c92cc9941208338
parent155c3a88ac6e6b690fb3324054abfcc8095e9cc3 (diff)
AutoSize TextView (part 8) - APIs for predefined sizes
* getter/setter for predefined sizes * reads and configures from XML at construction time * fix for an ugly bug where the sizes were missing an entry in certain cases, e.g: min = 10; max = 20; step = 2 would have produced [10, 12, 14, 16, 18] instead of [10, 12, 14, 16, 18, 20] * fix using getHeight()/getWidth() instead of untrusted getMeasuredHeight()/getMeasuredWidth() and move the auto-sizing triggering to onLayout() instead of onMeasure() (while manually testing discovered missing or extra pixels and sometimes resizing being skipped - it's all fixed now) * fix using deceiving getTotalPaddingBottom()/...Top() and replaced with getExtendedPaddingBottom()/..Top() (getTotal... was removing the whitespace height but auto-size needs to know about it so it can fill the space) Bug: 32221168 Test: attached in the same topic run cts-dev -m CtsWidgetTestCases -t \ android.widget.cts.TextViewTest Change-Id: Id5a31d0d32b2b4082af45b4bd65af8cb85bdc92e
-rw-r--r--api/current.txt2
-rw-r--r--api/system-current.txt2
-rw-r--r--api/test-current.txt2
-rw-r--r--core/java/android/widget/TextView.java212
4 files changed, 168 insertions, 50 deletions
diff --git a/api/current.txt b/api/current.txt
index d7721819e404..15a6ec7d7d32 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -50383,6 +50383,7 @@ package android.widget {
method public int getAutoSizeMaxTextSize();
method public int getAutoSizeMinTextSize();
method public int getAutoSizeStepGranularity();
+ method public int[] getAutoSizeTextPresetSizes();
method public int getAutoSizeTextType();
method public int getBreakStrategy();
method public int getCompoundDrawablePadding();
@@ -50496,6 +50497,7 @@ package android.widget {
method public void setAutoSizeMaxTextSize(int, float);
method public void setAutoSizeMinTextSize(int, float);
method public void setAutoSizeStepGranularity(int, float);
+ method public void setAutoSizeTextPresetSizes(int[]);
method public void setAutoSizeTextType(int);
method public void setBreakStrategy(int);
method public void setCompoundDrawablePadding(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 6affa7fea40f..d24dc4212b7a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -54154,6 +54154,7 @@ package android.widget {
method public int getAutoSizeMaxTextSize();
method public int getAutoSizeMinTextSize();
method public int getAutoSizeStepGranularity();
+ method public int[] getAutoSizeTextPresetSizes();
method public int getAutoSizeTextType();
method public int getBreakStrategy();
method public int getCompoundDrawablePadding();
@@ -54267,6 +54268,7 @@ package android.widget {
method public void setAutoSizeMaxTextSize(int, float);
method public void setAutoSizeMinTextSize(int, float);
method public void setAutoSizeStepGranularity(int, float);
+ method public void setAutoSizeTextPresetSizes(int[]);
method public void setAutoSizeTextType(int);
method public void setBreakStrategy(int);
method public void setCompoundDrawablePadding(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index bbb7f898d201..0ac218c3cb2a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -50703,6 +50703,7 @@ package android.widget {
method public int getAutoSizeMaxTextSize();
method public int getAutoSizeMinTextSize();
method public int getAutoSizeStepGranularity();
+ method public int[] getAutoSizeTextPresetSizes();
method public int getAutoSizeTextType();
method public int getBreakStrategy();
method public int getCompoundDrawablePadding();
@@ -50816,6 +50817,7 @@ package android.widget {
method public void setAutoSizeMaxTextSize(int, float);
method public void setAutoSizeMinTextSize(int, float);
method public void setAutoSizeStepGranularity(int, float);
+ method public void setAutoSizeTextPresetSizes(int[]);
method public void setAutoSizeTextType(int);
method public void setBreakStrategy(int);
method public void setCompoundDrawablePadding(int);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a5ff29119dc9..31bb6b65cb85 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -109,6 +109,7 @@ import android.text.style.URLSpan;
import android.text.style.UpdateAppearance;
import android.text.util.Linkify;
import android.util.AttributeSet;
+import android.util.IntArray;
import android.util.Log;
import android.util.TypedValue;
import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -159,6 +160,8 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FastMath;
import com.android.internal.widget.EditableInputConnection;
+import libcore.util.EmptyArray;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
@@ -166,6 +169,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Locale;
/**
@@ -262,6 +266,7 @@ import java.util.Locale;
* @attr ref android.R.styleable#TextView_autoSizeMinTextSize
* @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
* @attr ref android.R.styleable#TextView_autoSizeStepGranularity
+ * @attr ref android.R.styleable#TextView_autoSizeStepSizeSet
*/
@RemoteView
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
@@ -708,8 +713,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private int mAutoSizeMinTextSizeInPx = 0;
// Maximum text size for auto-sizing in pixels.
private int mAutoSizeMaxTextSizeInPx = 0;
- // Contains the sorted set of desired text sizes in pixels to pick from when auto-sizing text.
- private int[] mAutoSizeTextSizesInPx;
+ // 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;
+ // Specifies whether auto-size should use the provided auto size steps set or if it should
+ // build the steps set using mAutoSizeMinTextSizeInPx, mAutoSizeMaxTextSizeInPx and
+ // mAutoSizeStepGranularityInPx.
+ private boolean mHasPredefinedAutoSizeSet = false;
// Watcher used to notify changes to auto-fill manager.
private AutoFillChangeWatcher mAutoFillChangeWatcher;
@@ -1301,8 +1311,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case com.android.internal.R.styleable.TextView_autoSizeMaxTextSize:
mAutoSizeMaxTextSizeInPx = a.getDimensionPixelSize(attr, 0);
break;
+
+ case com.android.internal.R.styleable.TextView_autoSizeStepSizeSet:
+ final int autoSizeStepSizeArrayResId = a.getResourceId(attr, 0);
+ if (autoSizeStepSizeArrayResId > 0) {
+ final TypedArray autoSizePreDefTextSizes = a.getResources()
+ .obtainTypedArray(autoSizeStepSizeArrayResId);
+ setupAutoSizeStepSizeSet(autoSizePreDefTextSizes);
+ autoSizePreDefTextSizes.recycle();
+ }
+ break;
}
}
+
a.recycle();
BufferType bufferType = BufferType.EDITABLE;
@@ -1599,7 +1620,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mAutoSizeMinTextSizeInPx = 0;
mAutoSizeMaxTextSizeInPx = 0;
mAutoSizeStepGranularityInPx = 0;
- mAutoSizeTextSizesInPx = null;
+ mAutoSizeTextSizesInPx = EmptyArray.INT;
mNeedsAutoSizeText = false;
}
break;
@@ -1651,6 +1672,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (supportsAutoSizeText()) {
mAutoSizeStepGranularityInPx = (int) TypedValue.applyDimension(
unit, size, getResources().getDisplayMetrics());
+ mHasPredefinedAutoSizeSet = false;
setupAutoSizeTextXY();
}
}
@@ -1683,6 +1705,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (supportsAutoSizeText()) {
mAutoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
unit, size, getResources().getDisplayMetrics());
+ mHasPredefinedAutoSizeSet = false;
setupAutoSizeTextXY();
}
}
@@ -1716,6 +1739,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (supportsAutoSizeText()) {
mAutoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
unit, size, getResources().getDisplayMetrics());
+ mHasPredefinedAutoSizeSet = false;
setupAutoSizeTextXY();
}
}
@@ -1730,44 +1754,137 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return mAutoSizeMaxTextSizeInPx;
}
- private void setupAutoSizeTextXY() {
- if (supportsAutoSizeText() && mAutoSizeTextType == AUTO_SIZE_TEXT_TYPE_XY) {
- // Set valid defaults.
- if (mAutoSizeMinTextSizeInPx <= 0) {
- mAutoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_SP,
- DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP,
- getResources().getDisplayMetrics());
+ /**
+ * Sets a predefined array of sizes to be used when auto-sizing.
+ *
+ * <ul>Note:
+ * <li>when <code>presetSizes</code> is not empty then the auto-size algorithm will use the
+ * values provided here instead of calculating the values based on min, max and step size. Also
+ * the values will be de-duplicated, sorted and negative or zero values will be removed.
+ * <li>when <code>presetSizes</code> is empty then the auto-size algorithm will use the min, max
+ * and step size to build the set of available sizes to choose from. Note that if no values have
+ * been provided for any of min, max or step size then defaults will be used.
+ * </ul>
+ *
+ * @param presetSizes an {@code int} array of sizes in pixels
+ *
+ * @attr ref android.R.styleable#TextView_autoSizeStepSizeSet
+ *
+ * @see #getAutoSizeTextPresetSizes()
+ */
+ public void setAutoSizeTextPresetSizes(@NonNull int[] presetSizes) {
+ if (supportsAutoSizeText()) {
+ if (presetSizes.length > 0) {
+ mAutoSizeTextSizesInPx = cleanupAutoSizePredefinedSizes(presetSizes);
+ final int sizesLength = mAutoSizeTextSizesInPx.length;
+ mHasPredefinedAutoSizeSet = sizesLength > 0;
+ if (mHasPredefinedAutoSizeSet) {
+ mAutoSizeMinTextSizeInPx = mAutoSizeTextSizesInPx[0];
+ mAutoSizeMaxTextSizeInPx = mAutoSizeTextSizesInPx[sizesLength - 1];
+ mAutoSizeStepGranularityInPx = 0;
+ }
+ } else {
+ mHasPredefinedAutoSizeSet = false;
}
+ setupAutoSizeTextXY();
+ }
+ }
- if (mAutoSizeMaxTextSizeInPx <= 0) {
- mAutoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_SP,
- DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP,
- getResources().getDisplayMetrics());
- }
+ /**
+ * @return the current auto-size {@code int} sizes array (in pixels).
+ *
+ * @see #setAutoSizeTextPresetSizes(int[])
+ * @see #setAutoSizeMinTextSize(int, float)
+ * @see #setAutoSizeMaxTextSize(int, float)
+ * @see #setAutoSizeStepGranularity(int, float)
+ */
+ public int[] getAutoSizeTextPresetSizes() {
+ return mAutoSizeTextSizesInPx;
+ }
+
+ private void setupAutoSizeStepSizeSet(TypedArray textSizes) {
+ final int textSizesLength = textSizes.length();
+ final int[] parsedSizes = new int[textSizesLength];
- if (mAutoSizeStepGranularityInPx <= 0) {
- mAutoSizeStepGranularityInPx = DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX;
+ if (textSizesLength > 0) {
+ for (int i = 0; i < textSizesLength; i++) {
+ parsedSizes[i] = textSizes.getDimensionPixelSize(i, -1);
}
+ mAutoSizeTextSizesInPx = cleanupAutoSizePredefinedSizes(parsedSizes);
+ mHasPredefinedAutoSizeSet = mAutoSizeTextSizesInPx.length > 0;
+ }
+ }
- // Validate.
- if (mAutoSizeMaxTextSizeInPx <= mAutoSizeMinTextSizeInPx) {
- throw new IllegalStateException("Maximum auto-size text size ("
- + mAutoSizeMaxTextSizeInPx + "px) is less or equal to minimum auto-size "
- + "text size (" + mAutoSizeMinTextSizeInPx + "px)");
+ // Returns distinct sorted positive values.
+ private int[] cleanupAutoSizePredefinedSizes(int[] predefinedValues) {
+ final int predefinedValuesLength = predefinedValues.length;
+ if (predefinedValuesLength == 0) {
+ return predefinedValues;
+ }
+ Arrays.sort(predefinedValues);
+
+ final IntArray uniqueValidSizes = new IntArray();
+ for (int i = 0; i < predefinedValuesLength; i++) {
+ final int currentPredefinedValue = predefinedValues[i];
+
+ if (currentPredefinedValue > 0
+ && uniqueValidSizes.binarySearch(currentPredefinedValue) < 0) {
+ uniqueValidSizes.add(currentPredefinedValue);
}
+ }
- // Calculate sizes to choose from based on the current auto-size configuration.
- final int autoSizeValuesLength = (int) Math.ceil(
- (mAutoSizeMaxTextSizeInPx - mAutoSizeMinTextSizeInPx)
- / mAutoSizeStepGranularityInPx);
+ return predefinedValuesLength == uniqueValidSizes.size()
+ ? predefinedValues
+ : uniqueValidSizes.toArray();
+ }
+
+ private void setupAutoSizeTextXY() {
+ if (supportsAutoSizeText() && mAutoSizeTextType == AUTO_SIZE_TEXT_TYPE_XY) {
+ // Calculate the sizes set based on minimum size, maximum size and step size if we do
+ // not have a predefined set of sizes or if the current sizes array is empty.
+ if (!mHasPredefinedAutoSizeSet || mAutoSizeTextSizesInPx.length == 0) {
+ // Set valid defaults.
+ if (mAutoSizeMinTextSizeInPx <= 0) {
+ mAutoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_SP,
+ DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP,
+ getResources().getDisplayMetrics());
+ }
+
+ if (mAutoSizeMaxTextSizeInPx <= 0) {
+ mAutoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_SP,
+ DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP,
+ getResources().getDisplayMetrics());
+ }
+
+ if (mAutoSizeStepGranularityInPx <= 0) {
+ mAutoSizeStepGranularityInPx = DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX;
+ }
- mAutoSizeTextSizesInPx = new int[autoSizeValuesLength];
- int sizeToAdd = mAutoSizeMinTextSizeInPx;
- for (int i = 0; i < autoSizeValuesLength; i++) {
- mAutoSizeTextSizesInPx[i] = sizeToAdd;
- sizeToAdd += mAutoSizeStepGranularityInPx;
+ // Validate.
+ if (mAutoSizeMaxTextSizeInPx <= mAutoSizeMinTextSizeInPx) {
+ throw new IllegalStateException("Maximum auto-size text size ("
+ + mAutoSizeMaxTextSizeInPx
+ + "px) is less or equal to minimum auto-size "
+ + "text size (" + mAutoSizeMinTextSizeInPx + "px)");
+ }
+
+ // Calculate sizes to choose from based on the current auto-size configuration.
+ int autoSizeValuesLength = (int) Math.ceil(
+ (mAutoSizeMaxTextSizeInPx - mAutoSizeMinTextSizeInPx)
+ / (float) 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;
+ for (int i = 0; i < autoSizeValuesLength; i++) {
+ mAutoSizeTextSizesInPx[i] = sizeToAdd;
+ sizeToAdd += mAutoSizeStepGranularityInPx;
+ }
}
mNeedsAutoSizeText = true;
@@ -7815,16 +7932,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
scrollTo(0, 0);
}
- if (isAutoSizeEnabled()) {
- if (mNeedsAutoSizeText) {
- // Call auto-size after the width and height have been calculated.
- autoSizeText();
- }
- // Always try to auto-size if enabled. Functions that do not want to trigger auto-sizing
- // after the next measuring round should set this to false.
- mNeedsAutoSizeText = true;
- }
-
setMeasuredDimension(width, height);
}
@@ -7832,8 +7939,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Automatically computes and sets the text size.
*/
private void autoSizeText() {
- final int maxWidth = getMeasuredWidth() - getTotalPaddingLeft() - getTotalPaddingRight();
- final int maxHeight = getMeasuredHeight() - getTotalPaddingBottom() - getTotalPaddingTop();
+ final int maxWidth = getWidth() - getTotalPaddingLeft() - getTotalPaddingRight();
+ final int maxHeight = getHeight() - getExtendedPaddingBottom() - getExtendedPaddingTop();
if (maxWidth <= 0 || maxHeight <= 0) {
return;
@@ -7907,11 +8014,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
- // Width overflow.
- if (layout.getWidth() > availableSpace.right) {
- return false;
- }
-
// Height overflow.
if (layout.getHeight() > availableSpace.bottom) {
return false;
@@ -8079,6 +8181,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mDeferScroll = -1;
bringPointIntoView(Math.min(curs, mText.length()));
}
+
+ if (isAutoSizeEnabled()) {
+ if (mNeedsAutoSizeText) {
+ // Call auto-size after the width and height have been calculated.
+ autoSizeText();
+ }
+ // Always try to auto-size if enabled. Functions that do not want to trigger auto-sizing
+ // after the next layout round should set this to false.
+ mNeedsAutoSizeText = true;
+ }
}
private boolean isShowingHint() {