diff options
Diffstat (limited to 'android/widget/TextView.java')
-rw-r--r-- | android/widget/TextView.java | 314 |
1 files changed, 285 insertions, 29 deletions
diff --git a/android/widget/TextView.java b/android/widget/TextView.java index 1e17f34a..7d3fcf46 100644 --- a/android/widget/TextView.java +++ b/android/widget/TextView.java @@ -27,8 +27,10 @@ import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.FloatRange; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.Px; import android.annotation.Size; import android.annotation.StringRes; import android.annotation.StyleRes; @@ -44,6 +46,7 @@ import android.content.UndoManager; import android.content.res.ColorStateList; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.content.res.ResourceId; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; @@ -51,6 +54,7 @@ import android.graphics.BaseCanvas; import android.graphics.Canvas; import android.graphics.Insets; import android.graphics.Paint; +import android.graphics.Paint.FontMetricsInt; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -76,8 +80,8 @@ import android.text.GraphicsOperations; import android.text.InputFilter; import android.text.InputType; import android.text.Layout; +import android.text.MeasuredText; import android.text.ParcelableSpan; -import android.text.PremeasuredText; import android.text.Selection; import android.text.SpanWatcher; import android.text.Spannable; @@ -295,6 +299,7 @@ import java.util.Locale; * @attr ref android.R.styleable#TextView_imeActionId * @attr ref android.R.styleable#TextView_editorExtras * @attr ref android.R.styleable#TextView_elegantTextHeight + * @attr ref android.R.styleable#TextView_fallbackLineSpacing * @attr ref android.R.styleable#TextView_letterSpacing * @attr ref android.R.styleable#TextView_fontFeatureSettings * @attr ref android.R.styleable#TextView_breakStrategy @@ -304,12 +309,12 @@ import java.util.Locale; * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize * @attr ref android.R.styleable#TextView_autoSizeStepGranularity * @attr ref android.R.styleable#TextView_autoSizePresetSizes + * @attr ref android.R.styleable#TextView_accessibilityHeading */ @RemoteView public class TextView extends View implements ViewTreeObserver.OnPreDrawListener { static final String LOG_TAG = "TextView"; static final boolean DEBUG_EXTRACT = false; - static final boolean DEBUG_AUTOFILL = false; private static final float[] TEMP_POSITION = new float[2]; // Enum for the "typeface" XML parameter. @@ -399,6 +404,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mCurTextColor; private int mCurHintTextColor; private boolean mFreezesText; + private boolean mIsAccessibilityHeading; private Editable.Factory mEditableFactory = Editable.Factory.getInstance(); private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance(); @@ -654,7 +660,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // True if internationalized input should be used for numbers and date and time. private final boolean mUseInternationalizedInput; // True if fallback fonts that end up getting used should be allowed to affect line spacing. - /* package */ final boolean mUseFallbackLineSpacing; + /* package */ boolean mUseFallbackLineSpacing; @ViewDebug.ExportedProperty(category = "text") private int mGravity = Gravity.TOP | Gravity.START; @@ -785,9 +791,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // mAutoSizeStepGranularityInPx. private boolean mHasPresetAutoSizeValues = false; - // Indicates whether the text was set from resources or dynamically, so it can be used to + // Indicates whether the text was set statically or dynamically, so it can be used to // sanitize autofill requests. - private boolean mTextFromResource = false; + private boolean mTextSetFromXmlOrResourceId = false; + // Resource id used to set the text - used for autofill purposes. + private @StringRes int mTextId = ResourceId.ID_NULL; /** * Kick-start the font cache for the zygote process (to pay the cost of @@ -921,12 +929,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int inputType = EditorInfo.TYPE_NULL; a = theme.obtainStyledAttributes( attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes); + int firstBaselineToTopHeight = -1; + int lastBaselineToBottomHeight = -1; + int lineHeight = -1; readTextAppearance(context, a, attributes, true /* styleArray */); int n = a.getIndexCount(); - boolean fromResourceId = false; + // Must set id in a temporary variable because it will be reset by setText() + boolean textIsSetFromXml = false; for (int i = 0; i < n; i++) { int attr = a.getIndex(i); @@ -1068,7 +1080,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener break; case com.android.internal.R.styleable.TextView_text: - fromResourceId = true; + textIsSetFromXml = true; + mTextId = a.getResourceId(attr, ResourceId.ID_NULL); text = a.getText(attr); break; @@ -1244,6 +1257,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case com.android.internal.R.styleable.TextView_justificationMode: mJustificationMode = a.getInt(attr, Layout.JUSTIFICATION_MODE_NONE); break; + + case com.android.internal.R.styleable.TextView_firstBaselineToTopHeight: + firstBaselineToTopHeight = a.getDimensionPixelSize(attr, -1); + break; + + case com.android.internal.R.styleable.TextView_lastBaselineToBottomHeight: + lastBaselineToBottomHeight = a.getDimensionPixelSize(attr, -1); + break; + + case com.android.internal.R.styleable.TextView_lineHeight: + lineHeight = a.getDimensionPixelSize(attr, -1); + break; + case com.android.internal.R.styleable.TextView_accessibilityHeading: + mIsAccessibilityHeading = a.getBoolean(attr, false); } } @@ -1460,8 +1487,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } setText(text, bufferType); - if (fromResourceId) { - mTextFromResource = true; + if (textIsSetFromXml) { + mTextSetFromXmlOrResourceId = true; } if (hint != null) setHint(hint); @@ -1558,6 +1585,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_NONE; } + + if (firstBaselineToTopHeight >= 0) { + setFirstBaselineToTopHeight(firstBaselineToTopHeight); + } + if (lastBaselineToBottomHeight >= 0) { + setLastBaselineToBottomHeight(lastBaselineToBottomHeight); + } + if (lineHeight >= 0) { + setLineHeight(lineHeight); + } } /** @@ -2360,7 +2397,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setText(mText); if (hasPasswordTransformationMethod()) { - notifyViewAccessibilityStateChangedIfNeeded( + notifyAccessibilityStateChanged( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } @@ -3160,6 +3197,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + /** + * @inheritDoc + * + * @see #setFirstBaselineToTopHeight(int) + * @see #setLastBaselineToBottomHeight(int) + */ @Override public void setPadding(int left, int top, int right, int bottom) { if (left != mPaddingLeft @@ -3174,6 +3217,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener invalidate(); } + /** + * @inheritDoc + * + * @see #setFirstBaselineToTopHeight(int) + * @see #setLastBaselineToBottomHeight(int) + */ @Override public void setPaddingRelative(int start, int top, int end, int bottom) { if (start != getPaddingStart() @@ -3189,6 +3238,97 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Updates the top padding of the TextView so that {@code firstBaselineToTopHeight} is + * equal to the distance between the firt text baseline and the top of this TextView. + * <strong>Note</strong> that if {@code FontMetrics.top} or {@code FontMetrics.ascent} was + * already greater than {@code firstBaselineToTopHeight}, the top padding is not updated. + * + * @param firstBaselineToTopHeight distance between first baseline to top of the container + * in pixels + * + * @see #getFirstBaselineToTopHeight() + * @see #setPadding(int, int, int, int) + * @see #setPaddingRelative(int, int, int, int) + * + * @attr ref android.R.styleable#TextView_firstBaselineToTopHeight + */ + public void setFirstBaselineToTopHeight(@Px @IntRange(from = 0) int firstBaselineToTopHeight) { + Preconditions.checkArgumentNonnegative(firstBaselineToTopHeight); + + final FontMetricsInt fontMetrics = getPaint().getFontMetricsInt(); + final int fontMetricsTop; + if (getIncludeFontPadding()) { + fontMetricsTop = fontMetrics.top; + } else { + fontMetricsTop = fontMetrics.ascent; + } + + // TODO: Decide if we want to ignore density ratio (i.e. when the user changes font size + // in settings). At the moment, we don't. + + if (firstBaselineToTopHeight > Math.abs(fontMetricsTop)) { + final int paddingTop = firstBaselineToTopHeight - (-fontMetricsTop); + setPadding(getPaddingLeft(), paddingTop, getPaddingRight(), getPaddingBottom()); + } + } + + /** + * Updates the bottom padding of the TextView so that {@code lastBaselineToBottomHeight} is + * equal to the distance between the last text baseline and the bottom of this TextView. + * <strong>Note</strong> that if {@code FontMetrics.bottom} or {@code FontMetrics.descent} was + * already greater than {@code lastBaselineToBottomHeight}, the bottom padding is not updated. + * + * @param lastBaselineToBottomHeight distance between last baseline to bottom of the container + * in pixels + * + * @see #getLastBaselineToBottomHeight() + * @see #setPadding(int, int, int, int) + * @see #setPaddingRelative(int, int, int, int) + * + * @attr ref android.R.styleable#TextView_lastBaselineToBottomHeight + */ + public void setLastBaselineToBottomHeight( + @Px @IntRange(from = 0) int lastBaselineToBottomHeight) { + Preconditions.checkArgumentNonnegative(lastBaselineToBottomHeight); + + final FontMetricsInt fontMetrics = getPaint().getFontMetricsInt(); + final int fontMetricsBottom; + if (getIncludeFontPadding()) { + fontMetricsBottom = fontMetrics.bottom; + } else { + fontMetricsBottom = fontMetrics.descent; + } + + // TODO: Decide if we want to ignore density ratio (i.e. when the user changes font size + // in settings). At the moment, we don't. + + if (lastBaselineToBottomHeight > Math.abs(fontMetricsBottom)) { + final int paddingBottom = lastBaselineToBottomHeight - fontMetricsBottom; + setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom); + } + } + + /** + * Returns the distance between the first text baseline and the top of this TextView. + * + * @see #setFirstBaselineToTopHeight(int) + * @attr ref android.R.styleable#TextView_firstBaselineToTopHeight + */ + public int getFirstBaselineToTopHeight() { + return getPaddingTop() - getPaint().getFontMetricsInt().top; + } + + /** + * Returns the distance between the last text baseline and the bottom of this TextView. + * + * @see #setLastBaselineToBottomHeight(int) + * @attr ref android.R.styleable#TextView_lastBaselineToBottomHeight + */ + public int getLastBaselineToBottomHeight() { + return getPaddingBottom() + getPaint().getFontMetricsInt().bottom; + } + + /** * Gets the autolink mask of the text. See {@link * android.text.util.Linkify#ALL Linkify.ALL} and peers for * possible values. @@ -3250,6 +3390,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener float mShadowDx = 0, mShadowDy = 0, mShadowRadius = 0; boolean mHasElegant = false; boolean mElegant = false; + boolean mHasFallbackLineSpacing = false; + boolean mFallbackLineSpacing = false; boolean mHasLetterSpacing = false; float mLetterSpacing = 0; String mFontFeatureSettings = null; @@ -3274,6 +3416,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener + " mShadowRadius:" + mShadowRadius + "\n" + " mHasElegant:" + mHasElegant + "\n" + " mElegant:" + mElegant + "\n" + + " mHasFallbackLineSpacing:" + mHasFallbackLineSpacing + "\n" + + " mFallbackLineSpacing:" + mFallbackLineSpacing + "\n" + " mHasLetterSpacing:" + mHasLetterSpacing + "\n" + " mLetterSpacing:" + mLetterSpacing + "\n" + " mFontFeatureSettings:" + mFontFeatureSettings + "\n" @@ -3312,6 +3456,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener com.android.internal.R.styleable.TextAppearance_shadowRadius); sAppearanceValues.put(com.android.internal.R.styleable.TextView_elegantTextHeight, com.android.internal.R.styleable.TextAppearance_elegantTextHeight); + sAppearanceValues.put(com.android.internal.R.styleable.TextView_fallbackLineSpacing, + com.android.internal.R.styleable.TextAppearance_fallbackLineSpacing); sAppearanceValues.put(com.android.internal.R.styleable.TextView_letterSpacing, com.android.internal.R.styleable.TextAppearance_letterSpacing); sAppearanceValues.put(com.android.internal.R.styleable.TextView_fontFeatureSettings, @@ -3402,6 +3548,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener attributes.mHasElegant = true; attributes.mElegant = appearance.getBoolean(attr, attributes.mElegant); break; + case com.android.internal.R.styleable.TextAppearance_fallbackLineSpacing: + attributes.mHasFallbackLineSpacing = true; + attributes.mFallbackLineSpacing = appearance.getBoolean(attr, + attributes.mFallbackLineSpacing); + break; case com.android.internal.R.styleable.TextAppearance_letterSpacing: attributes.mHasLetterSpacing = true; attributes.mLetterSpacing = @@ -3455,6 +3606,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setElegantTextHeight(attributes.mElegant); } + if (attributes.mHasFallbackLineSpacing) { + setFallbackLineSpacing(attributes.mFallbackLineSpacing); + } + if (attributes.mHasLetterSpacing) { setLetterSpacing(attributes.mLetterSpacing); } @@ -3736,7 +3891,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * * @param elegant set the paint's elegant metrics flag. * - * @see Paint#isElegantTextHeight(boolean) + * @see #isElegantTextHeight() + * @see Paint#isElegantTextHeight() * * @attr ref android.R.styleable#TextView_elegantTextHeight */ @@ -3752,6 +3908,43 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Set whether to respect the ascent and descent of the fallback fonts that are used in + * displaying the text (which is needed to avoid text from consecutive lines running into + * each other). If set, fallback fonts that end up getting used can increase the ascent + * and descent of the lines that they are used on. + * <p/> + * It is required to be true if text could be in languages like Burmese or Tibetan where text + * is typically much taller or deeper than Latin text. + * + * @param enabled whether to expand linespacing based on fallback fonts, {@code true} by default + * + * @see StaticLayout.Builder#setUseLineSpacingFromFallbacks(boolean) + * + * @attr ref android.R.styleable#TextView_fallbackLineSpacing + */ + public void setFallbackLineSpacing(boolean enabled) { + if (mUseFallbackLineSpacing != enabled) { + mUseFallbackLineSpacing = enabled; + if (mLayout != null) { + nullLayouts(); + requestLayout(); + invalidate(); + } + } + } + + /** + * @return whether fallback line spacing is enabled, {@code true} by default + * + * @see #setFallbackLineSpacing(boolean) + * + * @attr ref android.R.styleable#TextView_fallbackLineSpacing + */ + public boolean isFallbackLineSpacing() { + return mUseFallbackLineSpacing; + } + + /** * Get the value of the TextView's elegant height metrics flag. This setting selects font * variants that have not been compacted to fit Latin-based vertical * metrics, and also increases top and bottom bounds to provide more space. @@ -4917,6 +5110,53 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Sets an explicit line height for this TextView. This is equivalent to the vertical distance + * between subsequent baselines in the TextView. + * + * @param lineHeight the line height in pixels + * + * @see #setLineSpacing(float, float) + * @see #getLineSpacing() + * + * @attr ref android.R.styleable#TextView_lineHeight + */ + public void setLineHeight(@Px @IntRange(from = 0) int lineHeight) { + Preconditions.checkArgumentNonnegative(lineHeight); + + final int fontHeight = getPaint().getFontMetricsInt(null); + // Make sure we don't setLineSpacing if it's not needed to avoid unnecessary redraw. + if (lineHeight != fontHeight) { + // Set lineSpacingExtra by the difference of lineSpacing with lineHeight + setLineSpacing(lineHeight - fontHeight, 1f); + } + } + + /** + * Gets whether this view is a heading for accessibility purposes. + * + * @return {@code true} if the view is a heading, {@code false} otherwise. + * + * @attr ref android.R.styleable#TextView_accessibilityHeading + */ + public boolean isAccessibilityHeading() { + return mIsAccessibilityHeading; + } + + /** + * Set if view is a heading for a section of content for accessibility purposes. + * + * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. + * + * @attr ref android.R.styleable#TextView_accessibilityHeading + */ + public void setAccessibilityHeading(boolean isHeading) { + if (isHeading != mIsAccessibilityHeading) { + mIsAccessibilityHeading = isHeading; + notifyAccessibilityStateChanged(AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); + } + } + + /** * Convenience method to append the specified text to the TextView's * display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE} * if it was not already editable. @@ -5278,7 +5518,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private void setText(CharSequence text, BufferType type, boolean notifyBefore, int oldlen) { - mTextFromResource = false; + mTextSetFromXmlOrResourceId = false; if (text == null) { text = ""; } @@ -5336,7 +5576,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (imm != null) imm.restartInput(this); } else if (type == BufferType.SPANNABLE || mMovement != null) { text = mSpannableFactory.newSpannable(text); - } else if (!(text instanceof PremeasuredText || text instanceof CharWrapper)) { + } else if (!(text instanceof MeasuredText || text instanceof CharWrapper)) { text = TextUtils.stringOrSpannedString(text); } @@ -5419,7 +5659,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener sendOnTextChanged(text, 0, oldlen, textLength); onTextChanged(text, 0, oldlen, textLength); - notifyViewAccessibilityStateChangedIfNeeded(AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT); + notifyAccessibilityStateChanged(AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT); if (needEditableForNotification) { sendAfterTextChanged((Editable) text); @@ -5516,7 +5756,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @android.view.RemotableViewMethod public final void setText(@StringRes int resid) { setText(getContext().getResources().getText(resid)); - mTextFromResource = true; + mTextSetFromXmlOrResourceId = true; + mTextId = resid; } /** @@ -5543,7 +5784,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ public final void setText(@StringRes int resid, BufferType type) { setText(getContext().getResources().getText(resid), type); - mTextFromResource = true; + mTextSetFromXmlOrResourceId = true; + mTextId = resid; } /** @@ -6151,7 +6393,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void setError(CharSequence error, Drawable icon) { createEditorIfNeeded(); mEditor.setError(error, icon); - notifyViewAccessibilityStateChangedIfNeeded( + notifyAccessibilityStateChanged( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } @@ -9066,8 +9308,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * - * Checks whether the transformation method applied to this TextView is set to ALL CAPS. This - * settings is internally ignored if this field is editable or selectable. + * Checks whether the transformation method applied to this TextView is set to ALL CAPS. * @return Whether the current transformation method is for ALL CAPS. * * @see #setAllCaps(boolean) @@ -9456,7 +9697,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } final AutofillManager afm = mContext.getSystemService(AutofillManager.class); if (afm != null) { - if (DEBUG_AUTOFILL) { + if (android.view.autofill.Helper.sVerbose) { Log.v(LOG_TAG, "sendAfterTextChanged(): notify AFM for text=" + mText); } afm.notifyValueChanged(TextView.this); @@ -10234,7 +10475,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean isPassword = hasPasswordTransformationMethod() || isPasswordInputType(getInputType()); if (forAutofill) { - structure.setDataIsSensitive(!mTextFromResource); + structure.setDataIsSensitive(!mTextSetFromXmlOrResourceId); + if (mTextId != ResourceId.ID_NULL) { + try { + structure.setTextIdEntry(getResources().getResourceEntryName(mTextId)); + } catch (Resources.NotFoundException e) { + if (android.view.autofill.Helper.sVerbose) { + Log.v(LOG_TAG, "onProvideAutofillStructure(): cannot set name for text id " + + mTextId + ": " + e.getMessage()); + } + } + } } if (!isPassword || forAutofill) { @@ -10455,6 +10706,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener info.setText(getTextForAccessibility()); info.setHintText(mHint); info.setShowingHintText(isShowingHint()); + info.setHeading(mIsAccessibilityHeading); if (mBufferType == BufferType.EDITABLE) { info.setEditable(true); @@ -10942,6 +11194,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return true; case ID_COPY: + // For link action mode in a non-selectable/non-focusable TextView, + // make sure that we set the appropriate min/max. + final int selStart = getSelectionStart(); + final int selEnd = getSelectionEnd(); + min = Math.max(0, Math.min(selStart, selEnd)); + max = Math.max(0, Math.max(selStart, selEnd)); final ClipData copyData = ClipData.newPlainText(null, getTransformedText(min, max)); if (setPrimaryClip(copyData)) { stopTextActionMode(); @@ -11164,11 +11422,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ public boolean requestActionMode(@NonNull TextLinks.TextLink link) { Preconditions.checkNotNull(link); - if (mEditor != null) { - mEditor.startLinkActionModeAsync(link); - return true; - } - return false; + createEditorIfNeeded(); + mEditor.startLinkActionModeAsync(link); + return true; } /** * @hide @@ -11883,7 +12139,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private final Choreographer mChoreographer; private byte mStatus = MARQUEE_STOPPED; - private final float mPixelsPerSecond; + private final float mPixelsPerMs; private float mMaxScroll; private float mMaxFadeScroll; private float mGhostStart; @@ -11896,7 +12152,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Marquee(TextView v) { final float density = v.getContext().getResources().getDisplayMetrics().density; - mPixelsPerSecond = MARQUEE_DP_PER_SECOND * density; + mPixelsPerMs = MARQUEE_DP_PER_SECOND * density / 1000f; mView = new WeakReference<TextView>(v); mChoreographer = Choreographer.getInstance(); } @@ -11941,7 +12197,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener long currentMs = mChoreographer.getFrameTime(); long deltaMs = currentMs - mLastAnimationMs; mLastAnimationMs = currentMs; - float deltaPx = deltaMs / 1000f * mPixelsPerSecond; + float deltaPx = deltaMs * mPixelsPerMs; mScroll += deltaPx; if (mScroll > mMaxScroll) { mScroll = mMaxScroll; |