diff options
author | Fabrice Di Meglio <fdimeglio@google.com> | 2011-08-10 16:31:58 -0700 |
---|---|---|
committer | Fabrice Di Meglio <fdimeglio@google.com> | 2011-08-15 13:18:34 -0700 |
commit | 8059e0903e36cbb5cf8b5c5d5d653acc9bbc8402 (patch) | |
tree | fba90001b825ca2d8c7102659d915b02caa3b7b9 /core/java | |
parent | b2a85b69ce98a312c450849dfd18bd1f878b5d66 (diff) | |
download | frameworks_base-8059e0903e36cbb5cf8b5c5d5d653acc9bbc8402.zip frameworks_base-8059e0903e36cbb5cf8b5c5d5d653acc9bbc8402.tar.gz frameworks_base-8059e0903e36cbb5cf8b5c5d5d653acc9bbc8402.tar.bz2 |
Fix bug #3388534 Long file names are improperly displayed when played
- force ellipsising when there are more lines found than maxLines
- do not care about lines when we have reached maxLines
- also fix relayouting when changing maxLines thru setMaxLines()
- do not allow START / MIDDLE ellipsis when there are multiple lines
(and print a log accordingly)
Change-Id: I90f5a7f5200a220aceee01fb7300bec2c4c3a075
Diffstat (limited to 'core/java')
-rw-r--r-- | core/java/android/text/DynamicLayout.java | 5 | ||||
-rw-r--r-- | core/java/android/text/Layout.java | 15 | ||||
-rw-r--r-- | core/java/android/text/StaticLayout.java | 133 | ||||
-rw-r--r-- | core/java/android/text/TextLine.java | 3 | ||||
-rw-r--r-- | core/java/android/widget/TextView.java | 56 |
5 files changed, 124 insertions, 88 deletions
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index 2c78679..2f9852d 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -275,7 +275,7 @@ extends Layout } if (reflowed == null) { - reflowed = new StaticLayout(true); + reflowed = new StaticLayout(getText()); } else { reflowed.prepare(); } @@ -488,7 +488,8 @@ extends Layout private int mTopPadding, mBottomPadding; - private static StaticLayout sStaticLayout = new StaticLayout(true); + private static StaticLayout sStaticLayout = null; + private static final Object[] sLock = new Object[0]; private static final int START = 0; diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index eabeef0..421e995 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -880,6 +880,10 @@ public abstract class Layout { } } Directions directions = getLineDirections(line); + // Returned directions can actually be null + if (directions == null) { + return 0f; + } int dir = getParagraphDirection(line); TextLine tl = TextLine.obtain(); @@ -1781,17 +1785,6 @@ public abstract class Layout { } } - /** - * Inform this layout that not all of its lines will be displayed, because a maximum number of - * lines has been set on the associated TextView. - * - * A non strictly positive value means that all lines are displayed. - * - * @param lineCount number of visible lines - * @hide - */ - public void setMaximumVisibleLineCount(int lineCount) {} - private CharSequence mText; private TextPaint mPaint; /* package */ TextPaint mWorkPaint; diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 14c71b2..788711d 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -23,6 +23,7 @@ import android.text.style.LeadingMarginSpan.LeadingMarginSpan2; import android.text.style.LineHeightSpan; import android.text.style.MetricAffectingSpan; import android.text.style.TabStopSpan; +import android.util.Log; import com.android.internal.util.ArrayUtils; @@ -38,6 +39,8 @@ import com.android.internal.util.ArrayUtils; */ public class StaticLayout extends Layout { + static final String TAG = "StaticLayout"; + public StaticLayout(CharSequence source, TextPaint paint, int width, Alignment align, float spacingmult, float spacingadd, @@ -75,7 +78,7 @@ public class StaticLayout extends Layout { float spacingmult, float spacingadd, boolean includepad) { this(source, bufstart, bufend, paint, outerwidth, align, textDir, - spacingmult, spacingadd, includepad, null, 0); + spacingmult, spacingadd, includepad, null, 0, Integer.MAX_VALUE); } public StaticLayout(CharSequence source, int bufstart, int bufend, @@ -86,7 +89,7 @@ public class StaticLayout extends Layout { TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { this(source, bufstart, bufend, paint, outerwidth, align, TextDirectionHeuristics.FIRSTSTRONG_LTR, - spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth); + spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, Integer.MAX_VALUE); } /** @@ -97,7 +100,7 @@ public class StaticLayout extends Layout { Alignment align, TextDirectionHeuristic textDir, float spacingmult, float spacingadd, boolean includepad, - TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { + TextUtils.TruncateAt ellipsize, int ellipsizedWidth, int maxLines) { super((ellipsize == null) ? source : (source instanceof Spanned) @@ -130,6 +133,7 @@ public class StaticLayout extends Layout { mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)]; mLineDirections = new Directions[ ArrayUtils.idealIntArraySize(2 * mColumns)]; + mMaximumVisibleLineCount = maxLines; mMeasured = MeasuredText.obtain(); @@ -141,8 +145,8 @@ public class StaticLayout extends Layout { mFontMetricsInt = null; } - /* package */ StaticLayout(boolean ellipsize) { - super(null, null, 0, null, 0, 0); + /* package */ StaticLayout(CharSequence text) { + super(text, null, 0, null, 0, 0); mColumns = COLUMNS_ELLIPSIZE; mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)]; @@ -394,6 +398,7 @@ public class StaticLayout extends Layout { okBottom = fitBottom; } } else { + final boolean moreChars = (j + 1 < spanEnd); if (ok != here) { // Log.e("text", "output ok " + here + " to " +ok); @@ -411,7 +416,7 @@ public class StaticLayout extends Layout { ok == bufEnd, includepad, trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, okWidth, - paint); + paint, moreChars); here = ok; } else if (fit != here) { @@ -427,7 +432,7 @@ public class StaticLayout extends Layout { fit == bufEnd, includepad, trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, fitWidth, - paint); + paint, moreChars); here = fit; } else { @@ -449,7 +454,7 @@ public class StaticLayout extends Layout { trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, - widths[here - paraStart], paint); + widths[here - paraStart], paint, moreChars); here = here + 1; } @@ -472,10 +477,13 @@ public class StaticLayout extends Layout { width = restWidth; } } + if (mLineCount >= mMaximumVisibleLineCount) { + break; + } } } - if (paraEnd != here) { + if (paraEnd != here && mLineCount < mMaximumVisibleLineCount) { if ((fitTop | fitBottom | fitDescent | fitAscent) == 0) { paint.getFontMetricsInt(fm); @@ -496,7 +504,7 @@ public class StaticLayout extends Layout { needMultiply, paraStart, chdirs, dir, easy, paraEnd == bufEnd, includepad, trackpad, chs, widths, paraStart, - ellipsize, ellipsizedWidth, w, paint); + ellipsize, ellipsizedWidth, w, paint, paraEnd != bufEnd); } paraStart = paraEnd; @@ -505,7 +513,8 @@ public class StaticLayout extends Layout { break; } - if (bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) { + if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) && + mLineCount < mMaximumVisibleLineCount) { // Log.e("text", "output last " + bufEnd); paint.getFontMetricsInt(fm); @@ -519,7 +528,7 @@ public class StaticLayout extends Layout { needMultiply, bufEnd, null, DEFAULT_DIR, true, true, includepad, trackpad, null, null, bufStart, - ellipsize, ellipsizedWidth, 0, paint); + ellipsize, ellipsizedWidth, 0, paint, false); } } @@ -624,7 +633,7 @@ public class StaticLayout extends Layout { boolean includePad, boolean trackPad, char[] chs, float[] widths, int widthStart, TextUtils.TruncateAt ellipsize, float ellipsisWidth, - float textWidth, TextPaint paint) { + float textWidth, TextPaint paint, boolean moreChars) { int j = mLineCount; int off = j * mColumns; int want = off + mColumns + TOP; @@ -722,9 +731,10 @@ public class StaticLayout extends Layout { // If ellipsize is in marquee mode, do not apply ellipsis on the first line if (ellipsize != null && (ellipsize != TextUtils.TruncateAt.MARQUEE || j != 0)) { + boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount); calculateEllipsis(start, end, widths, widthStart, ellipsisWidth, ellipsize, j, - textWidth, paint); + textWidth, paint, forceEllipsis); } mLineCount++; @@ -734,9 +744,9 @@ public class StaticLayout extends Layout { private void calculateEllipsis(int lineStart, int lineEnd, float[] widths, int widthStart, float avail, TextUtils.TruncateAt where, - int line, float textWidth, TextPaint paint) { - - if (textWidth <= avail) { + int line, float textWidth, TextPaint paint, + boolean forceEllipsis) { + if (textWidth <= avail && !forceEllipsis) { // Everything fits! mLines[mColumns * line + ELLIPSIS_START] = 0; mLines[mColumns * line + ELLIPSIS_COUNT] = 0; @@ -744,25 +754,33 @@ public class StaticLayout extends Layout { } float ellipsisWidth = paint.measureText(HORIZONTAL_ELLIPSIS); - int ellipsisStart, ellipsisCount; + int ellipsisStart = 0; + int ellipsisCount = 0; int len = lineEnd - lineStart; + // We only support start ellipsis on a single line if (where == TextUtils.TruncateAt.START) { - float sum = 0; - int i; + if (mMaximumVisibleLineCount == 1) { + float sum = 0; + int i; - for (i = len; i >= 0; i--) { - float w = widths[i - 1 + lineStart - widthStart]; + for (i = len; i >= 0; i--) { + float w = widths[i - 1 + lineStart - widthStart]; - if (w + sum + ellipsisWidth > avail) { - break; + if (w + sum + ellipsisWidth > avail) { + break; + } + + sum += w; } - sum += w; + ellipsisStart = 0; + ellipsisCount = i; + } else { + if (Log.isLoggable(TAG, Log.WARN)) { + Log.w(TAG, "Start Ellipsis only supported with one line"); + } } - - ellipsisStart = 0; - ellipsisCount = i; } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE) { float sum = 0; int i; @@ -779,34 +797,45 @@ public class StaticLayout extends Layout { ellipsisStart = i; ellipsisCount = len - i; - } else /* where = TextUtils.TruncateAt.MIDDLE */ { - float lsum = 0, rsum = 0; - int left = 0, right = len; + if (forceEllipsis && ellipsisCount == 0 && i > 0) { + ellipsisStart = i - 1; + ellipsisCount = 1; + } + } else { + // where = TextUtils.TruncateAt.MIDDLE We only support middle ellipsis on a single line + if (mMaximumVisibleLineCount == 1) { + float lsum = 0, rsum = 0; + int left = 0, right = len; - float ravail = (avail - ellipsisWidth) / 2; - for (right = len; right >= 0; right--) { - float w = widths[right - 1 + lineStart - widthStart]; + float ravail = (avail - ellipsisWidth) / 2; + for (right = len; right >= 0; right--) { + float w = widths[right - 1 + lineStart - widthStart]; - if (w + rsum > ravail) { - break; + if (w + rsum > ravail) { + break; + } + + rsum += w; } - rsum += w; - } + float lavail = avail - ellipsisWidth - rsum; + for (left = 0; left < right; left++) { + float w = widths[left + lineStart - widthStart]; - float lavail = avail - ellipsisWidth - rsum; - for (left = 0; left < right; left++) { - float w = widths[left + lineStart - widthStart]; + if (w + lsum > lavail) { + break; + } - if (w + lsum > lavail) { - break; + lsum += w; } - lsum += w; + ellipsisStart = left; + ellipsisCount = right - left; + } else { + if (Log.isLoggable(TAG, Log.WARN)) { + Log.w(TAG, "Middle Ellipsis only supported with one line"); + } } - - ellipsisStart = left; - ellipsisCount = right - left; } mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart; @@ -916,14 +945,6 @@ public class StaticLayout extends Layout { return mEllipsizedWidth; } - /** - * @hide - */ - @Override - public void setMaximumVisibleLineCount(int lineCount) { - mMaximumVisibleLineCount = lineCount; - } - void prepare() { mMeasured = MeasuredText.obtain(); } @@ -949,7 +970,7 @@ public class StaticLayout extends Layout { private int[] mLines; private Directions[] mLineDirections; - private int mMaximumVisibleLineCount = 0; + private int mMaximumVisibleLineCount = Integer.MAX_VALUE; private static final int START_MASK = 0x1FFFFFFF; private static final int DIR_SHIFT = 30; diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 376e4f5..fcc372e 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -125,6 +125,9 @@ class TextLine { mLen = limit - start; mDir = dir; mDirections = directions; + if (mDirections == null) { + throw new IllegalArgumentException("Directions cannot be null"); + } mHasTabs = hasTabs; mSpanned = null; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 1ab1a87..d1a5196 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -6068,6 +6068,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int ellipsisWidth, boolean bringIntoView) { stopMarquee(); + // Update "old" cached values + mOldMaximum = mMaximum; + mOldMaxMode = mMaxMode; + mHighlightPathBogus = true; if (w < 0) { @@ -6129,7 +6133,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 0, mTransformed.length(), mTextPaint, w, alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mEllipsize, - ellipsisWidth); + ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); } else { mLayout = new StaticLayout(mTransformed, mTextPaint, w, alignment, mTextDir, mSpacingMult, mSpacingAdd, @@ -6140,7 +6144,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 0, mTransformed.length(), mTextPaint, w, alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mEllipsize, - ellipsisWidth); + ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); } else { mLayout = new StaticLayout(mTransformed, mTextPaint, w, alignment, mTextDir, mSpacingMult, mSpacingAdd, @@ -6195,7 +6199,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 0, mHint.length(), mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mEllipsize, - ellipsisWidth); + ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); } else { mHintLayout = new StaticLayout(mHint, mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd, @@ -6206,7 +6210,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 0, mHint.length(), mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mEllipsize, - ellipsisWidth); + ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE); } else { mHintLayout = new StaticLayout(mHint, mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd, @@ -6411,25 +6415,34 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mHorizontallyScrolling) want = VERY_WIDE; int hintWant = want; - int hintWidth = mHintLayout == null ? hintWant : mHintLayout.getWidth(); + int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth(); if (mLayout == null) { makeNewLayout(want, hintWant, boring, hintBoring, width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false); - } else if ((mLayout.getWidth() != want) || (hintWidth != hintWant) || - (mLayout.getEllipsizedWidth() != - width - getCompoundPaddingLeft() - getCompoundPaddingRight())) { - if (mHint == null && mEllipsize == null && - want > mLayout.getWidth() && - (mLayout instanceof BoringLayout || - (fromexisting && des >= 0 && des <= want))) { - mLayout.increaseWidthTo(want); + } else { + final boolean layoutChanged = (mLayout.getWidth() != want) || + (hintWidth != hintWant) || + (mLayout.getEllipsizedWidth() != + width - getCompoundPaddingLeft() - getCompoundPaddingRight()); + + final boolean widthChanged = (mHint == null) && + (mEllipsize == null) && + (want > mLayout.getWidth()) && + (mLayout instanceof BoringLayout || (fromexisting && des >= 0 && des <= want)); + + final boolean maximumChanged = (mMaxMode != mOldMaxMode) || (mMaximum != mOldMaximum); + + if (layoutChanged || maximumChanged) { + if (!maximumChanged && widthChanged) { + mLayout.increaseWidthTo(want); + } else { + makeNewLayout(want, hintWant, boring, hintBoring, + width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false); + } } else { - makeNewLayout(want, hintWant, boring, hintBoring, - width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false); + // Nothing has changed } - } else { - // Width has not changed. } if (heightMode == MeasureSpec.EXACTLY) { @@ -6489,7 +6502,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } desired += pad; - layout.setMaximumVisibleLineCount(0); if (mMaxMode == LINES) { /* @@ -6498,7 +6510,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ if (cap) { if (linecount > mMaximum) { - layout.setMaximumVisibleLineCount(mMaximum); desired = layout.getLineTop(mMaximum); if (dr != null) { @@ -7106,6 +7117,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * to constrain the text to a single line. Use <code>null</code> * to turn off ellipsizing. * + * If {@link #setMaxLines} has been used to set two or more lines, + * {@link TextUtils.TruncateAt#END} and {@link TextUtils.TruncateAt#MARQUEE} + * are only supported (other ellipsizing types will not do anything). + * * @attr ref android.R.styleable#TextView_ellipsize */ public void setEllipsize(TextUtils.TruncateAt where) { @@ -10878,6 +10893,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mMinimum = 0; private int mMinMode = LINES; + private int mOldMaximum = mMaximum; + private int mOldMaxMode = mMaxMode; + private int mMaxWidth = Integer.MAX_VALUE; private int mMaxWidthMode = PIXELS; private int mMinWidth = 0; |