Add more firstStrong alternatives for textDirection.

The current firstStrong value of textDirection is locale-dependent,
and can create problems when consistent display of text across
locales of potentially different direction is desired.

This adds two new values for textDirection, firstStrongLtr and
firstStrongRtl, which don't use the locale or the view's direction as
fallback, but explicit values of LTR or RTL.

Using firstStrongLtr also guarantees the exact algorithm defined in
the Unicode Bidirectional Algorithm to be used for determining
direction.

Bug: 13428339
Change-Id: I450d4f6b5197763ace7f9506c72cf87a90da4218
diff --git a/api/current.txt b/api/current.txt
index 6de9a03..f35ed00 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35538,6 +35538,8 @@
     field public static final int TEXT_ALIGNMENT_VIEW_START = 5; // 0x5
     field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2
     field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1
+    field public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; // 0x6
+    field public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; // 0x7
     field public static final int TEXT_DIRECTION_INHERIT = 0; // 0x0
     field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5
     field public static final int TEXT_DIRECTION_LTR = 3; // 0x3
diff --git a/api/system-current.txt b/api/system-current.txt
index 2d387d1..6818947a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -38163,6 +38163,8 @@
     field public static final int TEXT_ALIGNMENT_VIEW_START = 5; // 0x5
     field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2
     field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1
+    field public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; // 0x6
+    field public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; // 0x7
     field public static final int TEXT_DIRECTION_INHERIT = 0; // 0x0
     field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5
     field public static final int TEXT_DIRECTION_LTR = 3; // 0x3
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3fa8c81..6b28746 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1795,6 +1795,8 @@
      *                          11       PFLAG2_TEXT_DIRECTION_FLAGS[3]
      *                         1         PFLAG2_TEXT_DIRECTION_FLAGS[4]
      *                         1 1       PFLAG2_TEXT_DIRECTION_FLAGS[5]
+     *                         11        PFLAG2_TEXT_DIRECTION_FLAGS[6]
+     *                         111       PFLAG2_TEXT_DIRECTION_FLAGS[7]
      *                         111       PFLAG2_TEXT_DIRECTION_MASK
      *                        1          PFLAG2_TEXT_DIRECTION_RESOLVED
      *                       1           PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT
@@ -1968,6 +1970,20 @@
     public static final int TEXT_DIRECTION_LOCALE = 5;
 
     /**
+     * Text direction is using "first strong algorithm". The first strong directional character
+     * determines the paragraph direction. If there is no strong directional character, the
+     * paragraph direction is LTR.
+     */
+    public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6;
+
+    /**
+     * Text direction is using "first strong algorithm". The first strong directional character
+     * determines the paragraph direction. If there is no strong directional character, the
+     * paragraph direction is RTL.
+     */
+    public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7;
+
+    /**
      * Default text direction is inherited
      */
     private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
@@ -2002,7 +2018,9 @@
             TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
             TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
             TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
-            TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT
+            TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT
     };
 
     /**
@@ -19636,11 +19654,13 @@
      * @return the defined text direction. It can be one of:
      *
      * {@link #TEXT_DIRECTION_INHERIT},
-     * {@link #TEXT_DIRECTION_FIRST_STRONG}
+     * {@link #TEXT_DIRECTION_FIRST_STRONG},
      * {@link #TEXT_DIRECTION_ANY_RTL},
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
-     * {@link #TEXT_DIRECTION_LOCALE}
+     * {@link #TEXT_DIRECTION_LOCALE},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}
      *
      * @attr ref android.R.styleable#View_textDirection
      *
@@ -19652,7 +19672,9 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE")
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
     })
     public int getRawTextDirection() {
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT;
@@ -19664,11 +19686,13 @@
      * @param textDirection the direction to set. Should be one of:
      *
      * {@link #TEXT_DIRECTION_INHERIT},
-     * {@link #TEXT_DIRECTION_FIRST_STRONG}
+     * {@link #TEXT_DIRECTION_FIRST_STRONG},
      * {@link #TEXT_DIRECTION_ANY_RTL},
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE}
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL},
      *
      * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution
      * proceeds up the parent chain of the view to get the value. If there is no parent, then it will
@@ -19698,11 +19722,13 @@
      *
      * @return the resolved text direction. Returns one of:
      *
-     * {@link #TEXT_DIRECTION_FIRST_STRONG}
+     * {@link #TEXT_DIRECTION_FIRST_STRONG},
      * {@link #TEXT_DIRECTION_ANY_RTL},
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
-     * {@link #TEXT_DIRECTION_LOCALE}
+     * {@link #TEXT_DIRECTION_LOCALE},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}
      *
      * @attr ref android.R.styleable#View_textDirection
      */
@@ -19712,7 +19738,9 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE")
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
     })
     public int getTextDirection() {
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
@@ -19771,6 +19799,8 @@
                         case TEXT_DIRECTION_LTR:
                         case TEXT_DIRECTION_RTL:
                         case TEXT_DIRECTION_LOCALE:
+                        case TEXT_DIRECTION_FIRST_STRONG_LTR:
+                        case TEXT_DIRECTION_FIRST_STRONG_RTL:
                             mPrivateFlags2 |=
                                     (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
                             break;
@@ -19784,6 +19814,8 @@
                 case TEXT_DIRECTION_LTR:
                 case TEXT_DIRECTION_RTL:
                 case TEXT_DIRECTION_LOCALE:
+                case TEXT_DIRECTION_FIRST_STRONG_LTR:
+                case TEXT_DIRECTION_FIRST_STRONG_RTL:
                     // Resolved direction is the same as text direction
                     mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
                     break;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9bbf375..b44a886 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9275,6 +9275,10 @@
                 return TextDirectionHeuristics.RTL;
             case TEXT_DIRECTION_LOCALE:
                 return TextDirectionHeuristics.LOCALE;
+            case TEXT_DIRECTION_FIRST_STRONG_LTR:
+                return TextDirectionHeuristics.FIRSTSTRONG_LTR;
+            case TEXT_DIRECTION_FIRST_STRONG_RTL:
+                return TextDirectionHeuristics.FIRSTSTRONG_RTL;
         }
     }
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index cbd74cd..7163eed 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2520,6 +2520,12 @@
             <enum name="rtl" value="4" />
             <!-- The paragraph direction is coming from the system Locale. -->
             <enum name="locale" value="5" />
+            <!-- The first strong directional character determines the paragraph direction. If
+                 there is no strong directional character, the paragraph direction is LTR. -->
+            <enum name="firstStrongLtr" value="6" />
+            <!-- The first strong directional character determines the paragraph direction. If
+                 there is no strong directional character, the paragraph direction is RTL. -->
+            <enum name="firstStrongRtl" value="7" />
         </attr>
 
         <!-- Defines the alignment of the text. A heuristic is used to determine the resolved