Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 463b4820 authored by Roozbeh Pournader's avatar Roozbeh Pournader
Browse files

Support all RTL scripts in getLayoutDirectionFromLocale().

Previously, only the languages written in Arabic and Hebrew were
considered right-to-left. Now, ICU is used to return the direction
of the language, which not only support other right-to-left scripts
(such as Thaana), but also has better logic to determine the
direction of the locale and uses caching to improve the speed.

Bug: 22559274
Change-Id: I760be7984a9b35ea77d59ca84a220798e205af36
parent 6e02fa01
Loading
Loading
Loading
Loading
+7 −42
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.text;

import android.annotation.Nullable;
import android.content.res.Resources;
import android.icu.util.ULocale;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemProperties;
@@ -1754,47 +1755,14 @@ public class TextUtils {
     * Be careful: this code will need to be updated when vertical scripts will be supported
     */
    public static int getLayoutDirectionFromLocale(Locale locale) {
        if (locale != null && !locale.equals(Locale.ROOT)) {
            final String scriptSubtag = ICU.addLikelySubtags(locale).getScript();
            if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);

            if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
                    scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
                return View.LAYOUT_DIRECTION_RTL;
            }
        }
        // If forcing into RTL layout mode, return RTL as default, else LTR
        return SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false)
        return ((locale != null && !locale.equals(Locale.ROOT)
                        && ULocale.forLocale(locale).isRightToLeft())
                // If forcing into RTL layout mode, return RTL as default
                || SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false))
            ? View.LAYOUT_DIRECTION_RTL
            : View.LAYOUT_DIRECTION_LTR;
    }

    /**
     * Fallback algorithm to detect the locale direction. Rely on the fist char of the
     * localized locale name. This will not work if the localized locale name is in English
     * (this is the case for ICU 4.4 and "Urdu" script)
     *
     * @param locale
     * @return the layout direction. This may be one of:
     * {@link View#LAYOUT_DIRECTION_LTR} or
     * {@link View#LAYOUT_DIRECTION_RTL}.
     *
     * Be careful: this code will need to be updated when vertical scripts will be supported
     *
     * @hide
     */
    private static int getLayoutDirectionFromFirstChar(Locale locale) {
        switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
                return View.LAYOUT_DIRECTION_RTL;

            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
            default:
                return View.LAYOUT_DIRECTION_LTR;
        }
    }

    /**
     * Return localized string representing the given number of selected items.
     *
@@ -1811,7 +1779,4 @@ public class TextUtils {
    private static String[] EMPTY_STRING_ARRAY = new String[]{};

    private static final char ZWNBS_CHAR = '\uFEFF';

    private static String ARAB_SCRIPT_SUBTAG = "Arab";
    private static String HEBR_SCRIPT_SUBTAG = "Hebr";
}
+44 −0
Original line number Diff line number Diff line
@@ -25,9 +25,11 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.text.style.StyleSpan;
import android.text.util.Rfc822Token;
import android.text.util.Rfc822Tokenizer;
import android.view.View;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import junit.framework.TestCase;

@@ -519,4 +521,46 @@ public class TextUtilsTest extends TestCase {
            return 0;
        }
    }

    @SmallTest
    public void testGetLayoutDirectionFromLocale() {
        assertEquals(View.LAYOUT_DIRECTION_LTR, TextUtils.getLayoutDirectionFromLocale(null));
        assertEquals(View.LAYOUT_DIRECTION_LTR,
                TextUtils.getLayoutDirectionFromLocale(Locale.ROOT));
        assertEquals(View.LAYOUT_DIRECTION_LTR,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("en")));
        assertEquals(View.LAYOUT_DIRECTION_LTR,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("en-US")));
        assertEquals(View.LAYOUT_DIRECTION_LTR,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az")));
        assertEquals(View.LAYOUT_DIRECTION_LTR,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-AZ")));
        assertEquals(View.LAYOUT_DIRECTION_LTR,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-Latn")));
        assertEquals(View.LAYOUT_DIRECTION_LTR,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("en-EG")));
        assertEquals(View.LAYOUT_DIRECTION_LTR,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("ar-Latn")));

        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("ar")));
        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("fa")));
        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("he")));
        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("iw")));
        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("ur")));
        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("dv")));
        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-Arab")));
        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-IR")));
        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("fa-US")));
        assertEquals(View.LAYOUT_DIRECTION_RTL,
                TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("tr-Arab")));
    }
}