Merge "Ellipsize marquee TextViews that aren't currently animating"

This commit is contained in:
Adam Powell
2011-08-30 17:40:40 -07:00
committed by Android (Google) Code Review

View File

@@ -64,6 +64,7 @@ import android.text.TextDirectionHeuristics;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.TextUtils.TruncateAt;
import android.text.method.AllCapsTransformationMethod;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.DateKeyListener;
@@ -366,6 +367,35 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private boolean mResolvedDrawables = false;
/**
* On some devices the fading edges add a performance penalty if used
* extensively in the same layout. This mode indicates how the marquee
* is currently being shown, if applicable. (mEllipsize will == MARQUEE)
*/
private int mMarqueeFadeMode = MARQUEE_FADE_NORMAL;
/**
* When mMarqueeFadeMode is not MARQUEE_FADE_NORMAL, this stores
* the layout that should be used when the mode switches.
*/
private Layout mSavedMarqueeModeLayout;
/**
* Draw marquee text with fading edges as usual
*/
private static final int MARQUEE_FADE_NORMAL = 0;
/**
* Draw marquee text as ellipsize end while inactive instead of with the fade.
* (Useful for devices where the fade can be expensive if overdone)
*/
private static final int MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS = 1;
/**
* Draw marquee text with fading edges because it is currently active/animating.
*/
private static final int MARQUEE_FADE_SWITCH_SHOW_FADE = 2;
/*
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -997,8 +1027,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setEllipsize(TextUtils.TruncateAt.END);
break;
case 4:
setHorizontalFadingEdgeEnabled(
ViewConfiguration.get(context).isFadingMarqueeEnabled());
if (ViewConfiguration.get(context).isFadingMarqueeEnabled()) {
setHorizontalFadingEdgeEnabled(true);
mMarqueeFadeMode = MARQUEE_FADE_NORMAL;
} else {
setHorizontalFadingEdgeEnabled(false);
mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS;
}
setEllipsize(TextUtils.TruncateAt.MARQUEE);
break;
}
@@ -3069,8 +3104,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (text instanceof Spanned &&
((Spanned) text).getSpanStart(TextUtils.TruncateAt.MARQUEE) >= 0) {
setHorizontalFadingEdgeEnabled(
ViewConfiguration.get(mContext).isFadingMarqueeEnabled());
if (ViewConfiguration.get(mContext).isFadingMarqueeEnabled()) {
setHorizontalFadingEdgeEnabled(true);
mMarqueeFadeMode = MARQUEE_FADE_NORMAL;
} else {
setHorizontalFadingEdgeEnabled(false);
mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS;
}
setEllipsize(TextUtils.TruncateAt.MARQUEE);
}
@@ -4763,7 +4803,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int layoutDirection = getResolvedLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
if (!mSingleLine && getLineCount() == 1 && canMarquee() &&
(absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
canvas.translate(mLayout.getLineRight(0) - (mRight - mLeft -
@@ -5947,7 +5988,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mSavedHintLayout = (BoringLayout) mHintLayout;
}
mLayout = mHintLayout = null;
mSavedMarqueeModeLayout = mLayout = mHintLayout = null;
// Since it depends on the value of mLayout
prepareCursorControllers();
@@ -6067,73 +6108,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Layout.Alignment alignment = getLayoutAlignment();
boolean shouldEllipsize = mEllipsize != null && mInput == null;
final boolean switchEllipsize = mEllipsize == TruncateAt.MARQUEE &&
mMarqueeFadeMode != MARQUEE_FADE_NORMAL;
TruncateAt effectiveEllipsize = mEllipsize;
if (mEllipsize == TruncateAt.MARQUEE &&
mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
effectiveEllipsize = TruncateAt.END;
}
if (mTextDir == null) {
resolveTextDirection();
}
if (mText instanceof Spannable) {
mLayout = new DynamicLayout(mText, mTransformed, mTextPaint, w,
alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, mInput == null ? mEllipsize : null,
ellipsisWidth);
} else {
if (boring == UNKNOWN_BORING) {
boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
if (boring != null) {
mBoring = boring;
}
}
if (boring != null) {
if (boring.width <= w &&
(mEllipsize == null || boring.width <= ellipsisWidth)) {
if (mSavedLayout != null) {
mLayout = mSavedLayout.
replaceOrMake(mTransformed, mTextPaint,
w, alignment, mSpacingMult, mSpacingAdd,
boring, mIncludePad);
} else {
mLayout = BoringLayout.make(mTransformed, mTextPaint,
w, alignment, mSpacingMult, mSpacingAdd,
boring, mIncludePad);
}
mSavedLayout = (BoringLayout) mLayout;
} else if (shouldEllipsize && boring.width <= w) {
if (mSavedLayout != null) {
mLayout = mSavedLayout.
replaceOrMake(mTransformed, mTextPaint,
w, alignment, mSpacingMult, mSpacingAdd,
boring, mIncludePad, mEllipsize,
ellipsisWidth);
} else {
mLayout = BoringLayout.make(mTransformed, mTextPaint,
w, alignment, mSpacingMult, mSpacingAdd,
boring, mIncludePad, mEllipsize,
ellipsisWidth);
}
} else if (shouldEllipsize) {
mLayout = new StaticLayout(mTransformed,
0, mTransformed.length(),
mTextPaint, w, alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, mEllipsize,
ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
} else {
mLayout = new StaticLayout(mTransformed, mTextPaint,
w, alignment, mTextDir, mSpacingMult, mSpacingAdd,
mIncludePad);
}
} else if (shouldEllipsize) {
mLayout = new StaticLayout(mTransformed,
0, mTransformed.length(),
mTextPaint, w, alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, mEllipsize,
ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
} else {
mLayout = new StaticLayout(mTransformed, mTextPaint,
w, alignment, mTextDir, mSpacingMult, mSpacingAdd,
mIncludePad);
}
mLayout = makeSingleLayout(w, boring, ellipsisWidth, alignment, shouldEllipsize,
effectiveEllipsize, effectiveEllipsize == mEllipsize);
if (switchEllipsize) {
TruncateAt oppositeEllipsize = effectiveEllipsize == TruncateAt.MARQUEE ?
TruncateAt.END : TruncateAt.MARQUEE;
mSavedMarqueeModeLayout = makeSingleLayout(w, boring, ellipsisWidth, alignment,
shouldEllipsize, oppositeEllipsize, effectiveEllipsize != mEllipsize);
}
shouldEllipsize = mEllipsize != null;
@@ -6224,6 +6217,77 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
prepareCursorControllers();
}
private Layout makeSingleLayout(int w, BoringLayout.Metrics boring, int ellipsisWidth,
Layout.Alignment alignment, boolean shouldEllipsize, TruncateAt effectiveEllipsize,
boolean useSaved) {
Layout result = null;
if (mText instanceof Spannable) {
result = new DynamicLayout(mText, mTransformed, mTextPaint, w,
alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, mInput == null ? effectiveEllipsize : null,
ellipsisWidth);
} else {
if (boring == UNKNOWN_BORING) {
boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
if (boring != null) {
mBoring = boring;
}
}
if (boring != null) {
if (boring.width <= w &&
(effectiveEllipsize == null || boring.width <= ellipsisWidth)) {
if (useSaved && mSavedLayout != null) {
result = mSavedLayout.replaceOrMake(mTransformed, mTextPaint,
w, alignment, mSpacingMult, mSpacingAdd,
boring, mIncludePad);
} else {
result = BoringLayout.make(mTransformed, mTextPaint,
w, alignment, mSpacingMult, mSpacingAdd,
boring, mIncludePad);
}
if (useSaved) {
mSavedLayout = (BoringLayout) result;
}
} else if (shouldEllipsize && boring.width <= w) {
if (useSaved && mSavedLayout != null) {
result = mSavedLayout.replaceOrMake(mTransformed, mTextPaint,
w, alignment, mSpacingMult, mSpacingAdd,
boring, mIncludePad, effectiveEllipsize,
ellipsisWidth);
} else {
result = BoringLayout.make(mTransformed, mTextPaint,
w, alignment, mSpacingMult, mSpacingAdd,
boring, mIncludePad, effectiveEllipsize,
ellipsisWidth);
}
} else if (shouldEllipsize) {
result = new StaticLayout(mTransformed,
0, mTransformed.length(),
mTextPaint, w, alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, effectiveEllipsize,
ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
} else {
result = new StaticLayout(mTransformed, mTextPaint,
w, alignment, mTextDir, mSpacingMult, mSpacingAdd,
mIncludePad);
}
} else if (shouldEllipsize) {
result = new StaticLayout(mTransformed,
0, mTransformed.length(),
mTextPaint, w, alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, effectiveEllipsize,
ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
} else {
result = new StaticLayout(mTransformed, mTextPaint,
w, alignment, mTextDir, mSpacingMult, mSpacingAdd,
mIncludePad);
}
}
return result;
}
private boolean compressText(float width) {
if (isHardwareAccelerated()) return false;
@@ -7179,7 +7243,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private boolean canMarquee() {
int width = (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight());
return width > 0 && mLayout.getLineWidth(0) > width;
return width > 0 && (mLayout.getLineWidth(0) > width ||
(mMarqueeFadeMode != MARQUEE_FADE_NORMAL && mSavedMarqueeModeLayout != null &&
mSavedMarqueeModeLayout.getLineWidth(0) > width));
}
private void startMarquee() {
@@ -7193,6 +7259,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if ((mMarquee == null || mMarquee.isStopped()) && (isFocused() || isSelected()) &&
getLineCount() == 1 && canMarquee()) {
if (mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_FADE;
final Layout tmp = mLayout;
mLayout = mSavedMarqueeModeLayout;
mSavedMarqueeModeLayout = tmp;
setHorizontalFadingEdgeEnabled(true);
requestLayout();
invalidate();
}
if (mMarquee == null) mMarquee = new Marquee(this);
mMarquee.start(mMarqueeRepeatLimit);
}
@@ -7202,6 +7278,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mMarquee != null && !mMarquee.isStopped()) {
mMarquee.stop();
}
if (mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_FADE) {
mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS;
final Layout tmp = mSavedMarqueeModeLayout;
mSavedMarqueeModeLayout = mLayout;
mLayout = tmp;
setHorizontalFadingEdgeEnabled(false);
requestLayout();
invalidate();
}
}
private void startStopMarquee(boolean start) {
@@ -8407,7 +8493,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
protected float getLeftFadingEdgeStrength() {
if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return 0.0f;
if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
if (mMarquee != null && !mMarquee.isStopped()) {
final Marquee marquee = mMarquee;
if (marquee.shouldDrawLeftFade()) {
@@ -8436,7 +8523,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
protected float getRightFadingEdgeStrength() {
if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return 0.0f;
if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
if (mMarquee != null && !mMarquee.isStopped()) {
final Marquee marquee = mMarquee;
return (marquee.mMaxFadeScroll - marquee.mScroll) / getHorizontalFadingEdgeLength();