Concat an ellipsis character when ellipsizing
The ellipsize function should add an ellipsis when it truncates test.
The Android default implementation uses MeasuredParagraph
to measure text length for check left characters after applying
avaiable length and ellipsis string, but it doesn't work
correctly in Robolectric environment, also the Paint#breakText
doesn't work in Robolectric environment either, so this CL
thinks every character has the same length to simulate an
acceptable calculation for text's width to make ellipsis workable.
Co-authored-by: utzcoz <utzcoz@outlook.com>
Signed-off-by: utzcoz <utzcoz@outlook.com>
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextUtilsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextUtilsTest.java
index 65990ac..22197ab 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextUtilsTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextUtilsTest.java
@@ -87,8 +87,8 @@
.isEqualTo("");
assertThat(TextUtils.ellipsize("apples", p, -1, TextUtils.TruncateAt.END).toString())
.isEqualTo("");
- assertThat(TextUtils.ellipsize("apples", p, 3, TextUtils.TruncateAt.END).toString())
- .isEqualTo("app");
+ assertThat(TextUtils.ellipsize("apples", p, 4, TextUtils.TruncateAt.END).toString())
+ .isEqualTo("app…");
assertThat(TextUtils.ellipsize("apples", p, 100, TextUtils.TruncateAt.END).toString())
.isEqualTo("apples");
assertThat(TextUtils.ellipsize("", p, 100, TextUtils.TruncateAt.END).toString()).isEqualTo("");
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextUtils.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextUtils.java
index f2c06ef..a996462 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextUtils.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextUtils.java
@@ -10,18 +10,52 @@
@SuppressWarnings({"UnusedDeclaration"})
@Implements(TextUtils.class)
public class ShadowTextUtils {
+ // See
+ // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/text/TextUtils.java;l=96?q=TextUtils.java&ss=android%2Fplatform%2Fsuperproject%2Fmain
+ private static final String ELLIPSIS_NORMAL = "\u2026"; // HORIZONTAL ELLIPSIS (…)
@Implementation
protected static CharSequence ellipsize(
CharSequence text, TextPaint p, float avail, TruncateAt where) {
+ // The AOSP implementation doesn't check text's null, so we don't check it here either.
// This shadow follows the convention of ShadowPaint#measureText where each
// characters width is 1.0.
+ int len = text.length();
+ float measuredWidth = p.measureText(text, 0, len);
+ if (measuredWidth <= avail) {
+ return text;
+ }
+ float ellipsisWidth = p.measureText(ELLIPSIS_NORMAL);
+ // Calculate available width after removing ellipsis.
+ avail -= ellipsisWidth;
+ // Current Robolectric's breakText doesn't work as expected, the workaround is to think
+ // every character has the same width, although it is not always true.
+ int widthPerChar = (int) measuredWidth / len;
+ // If available length is less than or equals to ellipsis size, we should return empty string.
if (avail <= 0) {
return "";
- } else if (text.length() < (int) (avail)) {
- return text;
+ } else if (where == TruncateAt.START) {
+ int right = (int) (len - avail / widthPerChar);
+ if (right >= len) {
+ return "";
+ } else {
+ return TextUtils.concat(ELLIPSIS_NORMAL, text.subSequence(right, len));
+ }
+ } else if (where == TruncateAt.END) {
+ int left = (int) (avail / widthPerChar);
+ if (left > 0) {
+ return TextUtils.concat(text.subSequence(0, left), ELLIPSIS_NORMAL);
+ } else {
+ return "";
+ }
} else {
- return text.subSequence(0, (int) avail);
+ // See TextUtilTest.java, the Android default implementation prefers the starting has more
+ // characters than the ending if it is not even.
+ int right = len - (int) (avail / 2 / widthPerChar);
+ avail -= p.measureText(text, right, len);
+ int left = (int) (avail / widthPerChar);
+ return TextUtils.concat(
+ text.subSequence(0, left), ELLIPSIS_NORMAL, text.subSequence(right, len));
}
}
}