Index: chrome/android/java/src/org/chromium/chrome/browser/snackbar/TemplatePreservingTextView.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/TemplatePreservingTextView.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/TemplatePreservingTextView.java |
index 36f4759d422ccde16430d13b43f0edeb6704d5bd..480670fc181d80be72a7ddffc4c4920a477aee7f 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/TemplatePreservingTextView.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/TemplatePreservingTextView.java |
@@ -13,13 +13,21 @@ import android.util.AttributeSet; |
import android.widget.TextView; |
/** |
- * A {@link AppCompatTextView} that properly clips content within a template, instead of clipping |
- * the templated content. |
+ * A {@link AppCompatTextView} that truncates content within a template, instead of truncating |
+ * the template text. Truncation only happens if maxLines is set to 1 and there's not enough space |
+ * to display the entire content. |
+ * |
+ * For example, given the following template and content |
+ * Template: "%s was closed" |
+ * Content: "https://www.google.com/webhp?sourceid=chrome-instant&q=potato" |
+ * |
+ * the TemplatePreservingTextView would truncate the content but not the template text: |
+ * "https://www.google.com/webh... was closed" |
*/ |
public class TemplatePreservingTextView extends AppCompatTextView { |
- private static final String DEFAULT_TEMPLATE = "%1$s"; |
private String mTemplate; |
- private CharSequence mContent; |
+ private CharSequence mContent = ""; |
+ private CharSequence mVisibleText; |
/** |
* Builds an instance of an {@link TemplatePreservingTextView}. |
@@ -31,41 +39,38 @@ public class TemplatePreservingTextView extends AppCompatTextView { |
} |
/** |
- * Update template for undo text |
- * @param template Template format string (eg. "Close %s") |
+ * Sets the template format string. setText() must be called after calling this method for the |
+ * new template text to take effect. |
+ * |
+ * @param template Template format string (e.g. "Closed %s"), or null. If null is passed, this |
+ * view acts like a normal TextView. |
*/ |
public void setTemplate(String template) { |
- mTemplate = TextUtils.isEmpty(template) ? DEFAULT_TEMPLATE : template; |
+ mTemplate = TextUtils.isEmpty(template) ? null : template; |
} |
/** |
* This will take {@code text} and apply it to the internal template, building a new |
- * {@link String} to set. This {code text} will be automatically truncated to fit within |
+ * {@link String} to set. This {@code text} will be automatically truncated to fit within |
* the template as best as possible, making sure the template does not get clipped. |
*/ |
@Override |
public void setText(CharSequence text, BufferType type) { |
- final int availWidth = getWidth() - getPaddingLeft() - getPaddingRight(); |
- setClippedText(text, availWidth); |
+ mContent = text != null ? text : ""; |
+ setContentDescription(mTemplate == null ? mContent : String.format(mTemplate, mContent)); |
+ updateVisibleText(0, true); |
} |
@Override |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
final int availWidth = |
MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); |
- setClippedText(mContent, availWidth); |
- |
+ updateVisibleText(availWidth, |
+ MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED); |
super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
} |
- private void setClippedText(CharSequence text, int availWidth) { |
- mContent = text != null ? text : ""; |
- |
- if (mTemplate == null) { |
- super.setText(mContent, BufferType.SPANNABLE); |
- return; |
- } |
- |
+ private CharSequence getTruncatedText(int availWidth) { |
final TextPaint paint = getPaint(); |
// Calculate the width the template takes. |
@@ -79,13 +84,25 @@ public class TemplatePreservingTextView extends AppCompatTextView { |
CharSequence clipped = TextUtils.ellipsize(mContent, paint, contentWidth, TruncateAt.END); |
// Build the full string, which should fit within availWidth. |
- String finalContent = String.format(mTemplate, clipped); |
+ return String.format(mTemplate, clipped); |
+ } |
+ |
+ private void updateVisibleText(int availWidth, boolean unspecifiedWidth) { |
+ CharSequence visibleText; |
+ if (mTemplate == null) { |
+ visibleText = mContent; |
+ } else if (getMaxLines() != 1 || unspecifiedWidth) { |
+ visibleText = String.format(mTemplate, mContent); |
+ } else { |
+ visibleText = getTruncatedText(availWidth); |
+ } |
- // BufferType.SPANNABLE is required so that TextView.getIterableTextForAccessibility() |
- // doesn't call our custom setText(). See crbug.com/449311 |
- super.setText(finalContent, BufferType.SPANNABLE); |
+ if (!visibleText.equals(mVisibleText)) { |
+ mVisibleText = visibleText; |
- // Set the content description to the non-ellipsized text |
- setContentDescription(String.format(mTemplate, mContent)); |
+ // BufferType.SPANNABLE is required so that TextView.getIterableTextForAccessibility() |
+ // doesn't call our custom setText(). See crbug.com/449311 |
+ super.setText(mVisibleText, BufferType.SPANNABLE); |
+ } |
} |
} |