Loading core/java/android/text/method/TransformationMethod.java +2 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ public interface TransformationMethod * Beware that the returned text must be exactly the same length as * the source text, and that if the source text is Editable, the returned * text must mirror it dynamically instead of doing a one-time copy. * The method should not return {@code null} unless {@code source} * is {@code null}. */ public CharSequence getTransformation(CharSequence source, View view); Loading core/java/android/widget/TextView.java +29 −0 Original line number Diff line number Diff line Loading @@ -1508,6 +1508,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } setText(text, bufferType); if (mText == null) { mText = ""; } if (mTransformed == null) { mTransformed = ""; } if (textIsSetFromXml) { mTextSetFromXmlOrResourceId = true; } Loading Loading @@ -2191,6 +2198,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return (mText instanceof Editable) ? (Editable) mText : null; } /** * @hide */ @VisibleForTesting public CharSequence getTransformed() { return mTransformed; } /** * Gets the vertical distance between lines of text, in pixels. * Note that markup within the text can cause individual lines Loading Loading @@ -5532,6 +5547,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * PrecomputedText mismatches with this TextView, IllegalArgumentException is thrown. To ensure * the parameters match, you can call {@link TextView#setTextMetricsParams} before calling this. * * Subclasses overriding this method should ensure that the following post condition holds, * in order to guarantee the safety of the view's measurement and layout operations: * regardless of the input, after calling #setText both {@code mText} and {@code mTransformed} * will be different from {@code null}. * * @param text text to be displayed * * @attr ref android.R.styleable#TextView_text Loading @@ -5554,6 +5574,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * {@link android.text.Editable.Factory} to create final or intermediate * {@link Editable Editables}. * * Subclasses overriding this method should ensure that the following post condition holds, * in order to guarantee the safety of the view's measurement and layout operations: * regardless of the input, after calling #setText both {@code mText} and {@code mTransformed} * will be different from {@code null}. * * @param text text to be displayed * * @see #setText(CharSequence) Loading Loading @@ -5706,6 +5731,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { mTransformed = mTransformation.getTransformation(text, this); } if (mTransformed == null) { // Should not happen if the transformation method follows the non-null postcondition. mTransformed = ""; } final int textLength = text.length(); Loading core/tests/coretests/src/android/widget/TextViewTest.java +33 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static junit.framework.Assert.assertTrue; import android.app.Activity; import android.app.Instrumentation; import android.content.Context; import android.content.Intent; import android.graphics.Paint; import android.platform.test.annotations.Presubmit; Loading @@ -44,6 +45,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.lang.reflect.Field; import java.util.Locale; /** Loading Loading @@ -320,6 +322,15 @@ public class TextViewTest { assertTrue(mTextView.useDynamicLayout()); } @Test @UiThreadTest public void testConstructor_doesNotLeaveTextNull() { mTextView = new NullSetTextTextView(mActivity); // Check that mText and mTransformed are empty string instead of null. assertEquals("", mTextView.getText().toString()); assertEquals("", mTextView.getTransformed().toString()); } private String createLongText() { int size = 600 * 1000; final StringBuilder builder = new StringBuilder(size); Loading @@ -328,4 +339,26 @@ public class TextViewTest { } return builder.toString(); } private class NullSetTextTextView extends TextView { NullSetTextTextView(Context context) { super(context); } @Override public void setText(CharSequence text, BufferType type) { // #setText will be called from the TextView constructor. Here we reproduce // the situation when the method sets mText and mTransformed to null. try { final Field textField = TextView.class.getDeclaredField("mText"); textField.setAccessible(true); textField.set(this, null); final Field transformedField = TextView.class.getDeclaredField("mTransformed"); transformedField.setAccessible(true); transformedField.set(this, null); } catch (NoSuchFieldException | IllegalAccessException e) { // Empty. } } } } Loading
core/java/android/text/method/TransformationMethod.java +2 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ public interface TransformationMethod * Beware that the returned text must be exactly the same length as * the source text, and that if the source text is Editable, the returned * text must mirror it dynamically instead of doing a one-time copy. * The method should not return {@code null} unless {@code source} * is {@code null}. */ public CharSequence getTransformation(CharSequence source, View view); Loading
core/java/android/widget/TextView.java +29 −0 Original line number Diff line number Diff line Loading @@ -1508,6 +1508,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } setText(text, bufferType); if (mText == null) { mText = ""; } if (mTransformed == null) { mTransformed = ""; } if (textIsSetFromXml) { mTextSetFromXmlOrResourceId = true; } Loading Loading @@ -2191,6 +2198,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return (mText instanceof Editable) ? (Editable) mText : null; } /** * @hide */ @VisibleForTesting public CharSequence getTransformed() { return mTransformed; } /** * Gets the vertical distance between lines of text, in pixels. * Note that markup within the text can cause individual lines Loading Loading @@ -5532,6 +5547,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * PrecomputedText mismatches with this TextView, IllegalArgumentException is thrown. To ensure * the parameters match, you can call {@link TextView#setTextMetricsParams} before calling this. * * Subclasses overriding this method should ensure that the following post condition holds, * in order to guarantee the safety of the view's measurement and layout operations: * regardless of the input, after calling #setText both {@code mText} and {@code mTransformed} * will be different from {@code null}. * * @param text text to be displayed * * @attr ref android.R.styleable#TextView_text Loading @@ -5554,6 +5574,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * {@link android.text.Editable.Factory} to create final or intermediate * {@link Editable Editables}. * * Subclasses overriding this method should ensure that the following post condition holds, * in order to guarantee the safety of the view's measurement and layout operations: * regardless of the input, after calling #setText both {@code mText} and {@code mTransformed} * will be different from {@code null}. * * @param text text to be displayed * * @see #setText(CharSequence) Loading Loading @@ -5706,6 +5731,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { mTransformed = mTransformation.getTransformation(text, this); } if (mTransformed == null) { // Should not happen if the transformation method follows the non-null postcondition. mTransformed = ""; } final int textLength = text.length(); Loading
core/tests/coretests/src/android/widget/TextViewTest.java +33 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static junit.framework.Assert.assertTrue; import android.app.Activity; import android.app.Instrumentation; import android.content.Context; import android.content.Intent; import android.graphics.Paint; import android.platform.test.annotations.Presubmit; Loading @@ -44,6 +45,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.lang.reflect.Field; import java.util.Locale; /** Loading Loading @@ -320,6 +322,15 @@ public class TextViewTest { assertTrue(mTextView.useDynamicLayout()); } @Test @UiThreadTest public void testConstructor_doesNotLeaveTextNull() { mTextView = new NullSetTextTextView(mActivity); // Check that mText and mTransformed are empty string instead of null. assertEquals("", mTextView.getText().toString()); assertEquals("", mTextView.getTransformed().toString()); } private String createLongText() { int size = 600 * 1000; final StringBuilder builder = new StringBuilder(size); Loading @@ -328,4 +339,26 @@ public class TextViewTest { } return builder.toString(); } private class NullSetTextTextView extends TextView { NullSetTextTextView(Context context) { super(context); } @Override public void setText(CharSequence text, BufferType type) { // #setText will be called from the TextView constructor. Here we reproduce // the situation when the method sets mText and mTransformed to null. try { final Field textField = TextView.class.getDeclaredField("mText"); textField.setAccessible(true); textField.set(this, null); final Field transformedField = TextView.class.getDeclaredField("mTransformed"); transformedField.setAccessible(true); transformedField.set(this, null); } catch (NoSuchFieldException | IllegalAccessException e) { // Empty. } } } }