Fix bug #5366547 TruncateAt.MARQUEE should be replaces with "two dot" ellipsis on hardware that dont support MARQUEE

- introduce TruncateAt.END_SMALL
- code refactoring for suppressing use of hardcoded constants

Change-Id: I70e24857cd5d6bd012a743cbc0ba46fbd06d5457
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index e8b2045..583cbe6 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -763,7 +763,8 @@
             return;
         }
 
-        float ellipsisWidth = paint.measureText(HORIZONTAL_ELLIPSIS);
+        float ellipsisWidth = paint.measureText(
+                (where == TextUtils.TruncateAt.END_SMALL) ? ELLIPSIS_TWO_DOTS : ELLIPSIS_NORMAL);
         int ellipsisStart = 0;
         int ellipsisCount = 0;
         int len = lineEnd - lineStart;
@@ -791,7 +792,8 @@
                     Log.w(TAG, "Start Ellipsis only supported with one line");
                 }
             }
-        } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE) {
+        } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE ||
+                where == TextUtils.TruncateAt.END_SMALL) {
             float sum = 0;
             int i;
 
@@ -1001,7 +1003,9 @@
     private static final char CHAR_HYPHEN = '-';
 
     private static final double EXTRA_ROUNDING = 0.5;
-    private static final String HORIZONTAL_ELLIPSIS = "\u2026"; // this is "..."
+
+    private static final String ELLIPSIS_NORMAL = "\u2026"; // this is "..."
+    private static final String ELLIPSIS_TWO_DOTS = "\u2025"; // this is ".."
 
     private static final int CHAR_FIRST_HIGH_SURROGATE = 0xD800;
     private static final int CHAR_LAST_LOW_SURROGATE = 0xDFFF;
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 894afbd..95a3cdc 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -53,9 +53,8 @@
 import java.util.regex.Pattern;
 
 public class TextUtils {
-    private TextUtils() { /* cannot be instantiated */ }
 
-    private static String[] EMPTY_STRING_ARRAY = new String[]{};
+    private TextUtils() { /* cannot be instantiated */ }
 
     public static void getChars(CharSequence s, int start, int end,
                                 char[] dest, int destoff) {
@@ -1000,6 +999,10 @@
         MIDDLE,
         END,
         MARQUEE,
+        /**
+         * @hide
+         */
+        END_SMALL
     }
 
     public interface EllipsizeCallback {
@@ -1010,8 +1013,6 @@
         public void ellipsized(int start, int end);
     }
 
-    private static String sEllipsis = null;
-
     /**
      * Returns the original text if it fits in the specified width
      * given the properties of the specified Paint,
@@ -1042,7 +1043,8 @@
                                          boolean preserveLength,
                                          EllipsizeCallback callback) {
         return ellipsize(text, paint, avail, where, preserveLength, callback,
-                TextDirectionHeuristics.FIRSTSTRONG_LTR);
+                TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                (where == TruncateAt.END_SMALL) ? ELLIPSIS_TWO_DOTS : ELLIPSIS_NORMAL);
     }
 
     /**
@@ -1063,11 +1065,7 @@
             float avail, TruncateAt where,
             boolean preserveLength,
             EllipsizeCallback callback,
-            TextDirectionHeuristic textDir) {
-        if (sEllipsis == null) {
-            Resources r = Resources.getSystem();
-            sEllipsis = r.getString(R.string.ellipsis);
-        }
+            TextDirectionHeuristic textDir, String ellipsis) {
 
         int len = text.length();
 
@@ -1085,7 +1083,7 @@
 
             // XXX assumes ellipsis string does not require shaping and
             // is unaffected by style
-            float ellipsiswid = paint.measureText(sEllipsis);
+            float ellipsiswid = paint.measureText(ellipsis);
             avail -= ellipsiswid;
 
             int left = 0;
@@ -1094,7 +1092,7 @@
                 // it all goes
             } else if (where == TruncateAt.START) {
                 right = len - mt.breakText(0, len, false, avail);
-            } else if (where == TruncateAt.END) {
+            } else if (where == TruncateAt.END || where == TruncateAt.END_SMALL) {
                 left = mt.breakText(0, len, true, avail);
             } else {
                 right = len - mt.breakText(0, len, false, avail / 2);
@@ -1112,10 +1110,10 @@
             int remaining = len - (right - left);
             if (preserveLength) {
                 if (remaining > 0) { // else eliminate the ellipsis too
-                    buf[left++] = '\u2026';
+                    buf[left++] = ellipsis.charAt(0);
                 }
                 for (int i = left; i < right; i++) {
-                    buf[i] = '\uFEFF';
+                    buf[i] = ZWNBS_CHAR;
                 }
                 String s = new String(buf, 0, len);
                 if (sp == null) {
@@ -1131,16 +1129,16 @@
             }
 
             if (sp == null) {
-                StringBuilder sb = new StringBuilder(remaining + sEllipsis.length());
+                StringBuilder sb = new StringBuilder(remaining + ellipsis.length());
                 sb.append(buf, 0, left);
-                sb.append(sEllipsis);
+                sb.append(ellipsis);
                 sb.append(buf, right, len - right);
                 return sb.toString();
             }
 
             SpannableStringBuilder ssb = new SpannableStringBuilder();
             ssb.append(text, 0, left);
-            ssb.append(sEllipsis);
+            ssb.append(ellipsis);
             ssb.append(text, right, len);
             return ssb;
         } finally {
@@ -1664,4 +1662,13 @@
 
     private static Object sLock = new Object();
     private static char[] sTemp = null;
+
+    private static String[] EMPTY_STRING_ARRAY = new String[]{};
+
+    private static final char ZWNBS_CHAR = '\uFEFF';
+
+    private static final String ELLIPSIS_NORMAL = Resources.getSystem().getString(
+            R.string.ellipsis);
+    private static final String ELLIPSIS_TWO_DOTS = Resources.getSystem().getString(
+            R.string.ellipsis_two_dots);
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8db6592..88242a9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6130,7 +6130,7 @@
         TruncateAt effectiveEllipsize = mEllipsize;
         if (mEllipsize == TruncateAt.MARQUEE &&
                 mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
-            effectiveEllipsize = TruncateAt.END;
+            effectiveEllipsize = TruncateAt.END_SMALL;
         }
 
         if (mTextDir == null) {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e093fa9..2d5d4cc 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -41,9 +41,13 @@
     <string name="untitled">&lt;untitled&gt;</string>
 
     <!-- Used to replace a range of characters in text that is too wide
-         for the space allocated to it. -->
+         for the space allocated to it (three dots). -->
     <string name="ellipsis">\u2026</string>
 
+    <!-- Used to replace a range of characters in text that is too wide
+         for the space allocated to it (two dots). -->
+    <string name="ellipsis_two_dots">\u2025</string>
+
     <!-- How to display the lack of a phone number -->
     <string name="emptyPhoneNumber">(No phone number)</string>