diff options
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 22 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 1 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 44 | ||||
| -rwxr-xr-x | core/res/res/values/attrs.xml | 12 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/widget/TextViewTest.java | 34 |
6 files changed, 107 insertions, 7 deletions
diff --git a/api/current.txt b/api/current.txt index 03c654ebe55c..c23b28b27c5d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22069,6 +22069,7 @@ package android.view { method public boolean willNotDraw(); field public static android.util.Property ALPHA; field protected static int DEFAULT_TEXT_DIRECTION; + field protected static float DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD; field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0 field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000 field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000 diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bf7f359303ef..8a72c4a14c66 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2523,18 +2523,26 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit public static final int TEXT_DIRECTION_ANY_RTL = 2; /** + * Text direction is the same as the one held by a 60% majority of the characters. If there is + * no majority then the paragraph direction is the resolved layout direction of the View. + * + * @hide + */ + public static final int TEXT_DIRECTION_CHAR_COUNT = 3; + + /** * Text direction is forced to LTR. * * @hide */ - public static final int TEXT_DIRECTION_LTR = 3; + public static final int TEXT_DIRECTION_LTR = 4; /** * Text direction is forced to RTL. * * @hide */ - public static final int TEXT_DIRECTION_RTL = 4; + public static final int TEXT_DIRECTION_RTL = 5; /** * Default text direction is inherited @@ -2542,6 +2550,11 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT; /** + * Default threshold for "char count" heuristic. + */ + protected static float DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD = 0.6f; + + /** * The text direction that has been defined by {@link #setTextDirection(int)}. * * {@hide} @@ -2551,6 +2564,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), + @ViewDebug.IntToString(from = TEXT_DIRECTION_CHAR_COUNT, to = "CHAR_COUNT"), @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL") }) @@ -11963,7 +11977,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit mPrivateFlags |= FORCE_LAYOUT; mPrivateFlags |= INVALIDATED; - if (mLayoutParams != null) { + if (mLayoutParams != null && mParent != null) { mLayoutParams.resolveWithDirection(getResolvedLayoutDirection()); } @@ -12990,6 +13004,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit * {@link #TEXT_DIRECTION_INHERIT}, * {@link #TEXT_DIRECTION_FIRST_STRONG} * {@link #TEXT_DIRECTION_ANY_RTL}, + * {@link #TEXT_DIRECTION_CHAR_COUNT}, * {@link #TEXT_DIRECTION_LTR}, * {@link #TEXT_DIRECTION_RTL}, * @@ -13007,6 +13022,7 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit * {@link #TEXT_DIRECTION_INHERIT}, * {@link #TEXT_DIRECTION_FIRST_STRONG} * {@link #TEXT_DIRECTION_ANY_RTL}, + * {@link #TEXT_DIRECTION_CHAR_COUNT}, * {@link #TEXT_DIRECTION_LTR}, * {@link #TEXT_DIRECTION_RTL}, * diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 2a90ddea3b55..25ca42178417 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -5039,6 +5039,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Pass down the hierarchy the following text direction values case TEXT_DIRECTION_FIRST_STRONG: case TEXT_DIRECTION_ANY_RTL: + case TEXT_DIRECTION_CHAR_COUNT: case TEXT_DIRECTION_LTR: case TEXT_DIRECTION_RTL: resolvedTextDirection = mTextDirection; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index f79dabd9a808..04b79c5ef8e6 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -10039,6 +10039,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case TEXT_DIRECTION_ANY_RTL: resolvedTextDirection = getTextDirectionFromAnyRtl(mText); break; + case TEXT_DIRECTION_CHAR_COUNT: + resolvedTextDirection = getTextDirectionFromCharCount(mText); + break; case TEXT_DIRECTION_LTR: resolvedTextDirection = TEXT_DIRECTION_LTR; break; @@ -10072,6 +10075,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ private static int getTextDirectionFromFirstStrong(final CharSequence cs) { final int length = cs.length(); + if (length == 0) { + return TEXT_DIRECTION_UNDEFINED; + } for(int i = 0; i < length; i++) { final char c = cs.charAt(i); final byte dir = Character.getDirectionality(c); @@ -10094,6 +10100,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ private static int getTextDirectionFromAnyRtl(final CharSequence cs) { final int length = cs.length(); + if (length == 0) { + return TEXT_DIRECTION_UNDEFINED; + } boolean foundStrongLtr = false; boolean foundStrongRtl = false; for(int i = 0; i < length; i++) { @@ -10115,6 +10124,41 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Get text direction following the "char count" heuristic. + * + * @param cs the CharSequence used to get the text direction. + * + * @return {@link #TEXT_DIRECTION_RTL} if direction it RTL, {@link #TEXT_DIRECTION_LTR} if + * direction it LTR or {@link #TEXT_DIRECTION_UNDEFINED} if direction cannot be found. + */ + private int getTextDirectionFromCharCount(CharSequence cs) { + final int length = cs.length(); + if (length == 0) { + return TEXT_DIRECTION_UNDEFINED; + } + int countLtr = 0; + int countRtl = 0; + for(int i = 0; i < length; i++) { + final char c = cs.charAt(i); + final byte dir = Character.getDirectionality(c); + if (isStrongLtrChar(dir)) { + countLtr++; + } else if (isStrongRtlChar(dir)) { + countRtl++; + } + } + final float percentLtr = ((float) countLtr) / (countLtr + countRtl); + if (percentLtr > DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD) { + return TEXT_DIRECTION_LTR; + } + final float percentRtl = ((float) countRtl) / (countLtr + countRtl); + if (percentRtl > DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD) { + return TEXT_DIRECTION_RTL; + } + return TEXT_DIRECTION_UNDEFINED; + } + + /** * Return true if the char direction is corresponding to a "strong RTL char" following the * Unicode Bidirectional Algorithm (UBA). */ diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index fd61cfdaf6b7..65f58421c9b3 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1985,10 +1985,14 @@ it is LTR if it contains any strong LTR characters. If there are neither, the paragraph direction is the view’s resolved layout direction. --> <enum name="anyRtl" value="2" /> - <!-- The text direction is left to right. --> - <enum name="ltr" value="3" /> - <!-- The text direction is right to left. --> - <enum name="rtl" value="4" /> + <!-- The paragraph direction is the same as the one held by a 60% majority of the + characters. If there is no majority then the paragraph direction is the resolved + layout direction of the View. --> + <enum name="charCount" value="3" /> + <!-- The paragraph direction is left to right. --> + <enum name="ltr" value="4" /> + <!-- The paragraph direction is right to left. --> + <enum name="rtl" value="5" /> </attr> </declare-styleable> diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java index a37f1a37e8dc..6db67c0de787 100644 --- a/core/tests/coretests/src/android/widget/TextViewTest.java +++ b/core/tests/coretests/src/android/widget/TextViewTest.java @@ -177,4 +177,38 @@ public class TextViewTest extends AndroidTestCase { tv.setTextDirection(View.TEXT_DIRECTION_RTL); assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection()); } + + @SmallTest + public void testCharCountHeuristic() { + LinearLayout ll = new LinearLayout(mContext); + ll.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); + + TextView tv = new TextView(mContext); + ll.addView(tv); + + tv.setTextDirection(View.TEXT_DIRECTION_CHAR_COUNT); + tv.setText("this is a test"); + assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection()); + + // resetResolvedTextDirection is not part of the public API so simply use setTextDirection + tv.setTextDirection(View.TEXT_DIRECTION_LTR); + tv.setTextDirection(View.TEXT_DIRECTION_CHAR_COUNT); + tv.setText("\u05DD\u05DE"); // hebrew + assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection()); + + tv.setTextDirection(View.TEXT_DIRECTION_LTR); + tv.setTextDirection(View.TEXT_DIRECTION_CHAR_COUNT); + tv.setText("this is a test \u05DD\u05DE"); // latin more than 60% + hebrew + assertEquals(View.TEXT_DIRECTION_LTR, tv.getResolvedTextDirection()); + + tv.setTextDirection(View.TEXT_DIRECTION_LTR); + tv.setTextDirection(View.TEXT_DIRECTION_CHAR_COUNT); + tv.setText("t \u05DD\u05DE"); // latin + hebrew more than 60% + assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection()); + + tv.setTextDirection(View.TEXT_DIRECTION_LTR); + tv.setTextDirection(View.TEXT_DIRECTION_CHAR_COUNT); + tv.setText("ab \u05DD\u05DE"); // latin + hebrew at 50% each + assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection()); + } } |