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

Commit a47f45e4 authored by Fabrice Di Meglio's avatar Fabrice Di Meglio
Browse files

Introduce LocalUtil and getLayoutDirectionFromLocale() now use likelySubtags

- move code from Configuration to LocaleUtil
- move unit tests

Change-Id: Ic14b0131894a0c5618f00d4acb3edb0daadefe01
parent 67f8de04
Loading
Loading
Loading
Loading
+5 −44
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.content.res;
import android.content.pm.ActivityInfo;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.LocaleUtil;

import java.util.Locale;

@@ -276,21 +277,6 @@ public final class Configuration implements Parcelable, Comparable<Configuration
    /** @hide Hack to get this information from WM to app running in compat mode. */
    public int compatSmallestScreenWidthDp;

    /**
     * @hide Do not use. Implementation not finished.
     */
    public static final int TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE = -1;

    /**
     * @hide Do not use. Implementation not finished.
     */
    public static final int TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE = 0;

    /**
     * @hide Do not use. Implementation not finished.
     */
    public static final int TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE = 1;

    /**
     * @hide The text layout direction associated to the current Locale
     */
@@ -359,8 +345,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
            sb.append(" (no locale)");
        }
        switch (textLayoutDirection) {
            case TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE: sb.append(" ?layoutdir"); break;
            case TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
            case LocaleUtil.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE: sb.append(" ?layoutdir"); break;
            case LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
            default: sb.append(" layoutdir="); sb.append(textLayoutDirection); break;
        }
        if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
@@ -483,7 +469,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
        screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
        smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
        textLayoutDirection = TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
        textLayoutDirection = LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
        seq = 0;
    }

@@ -519,7 +505,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
            changed |= ActivityInfo.CONFIG_LOCALE;
            locale = delta.locale != null
                    ? (Locale) delta.locale.clone() : null;
            textLayoutDirection = getLayoutDirectionFromLocale(locale);
            textLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
        }
        if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
        {
@@ -608,31 +594,6 @@ public final class Configuration implements Parcelable, Comparable<Configuration
        return changed;
    }

    /**
     * Return the layout direction for a given Locale
     * @param locale the Locale for which we want the layout direction. Can be null.
     * @return the layout direction. This may be one of:
     * {@link #TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE} or
     * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
     * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
     *
     * @hide
     */
    public static int getLayoutDirectionFromLocale(Locale locale) {
        if (locale == null || locale.equals(Locale.ROOT)) return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
        // Be careful: this code will need to be changed when vertical scripts will be supported
        // OR if ICU4C is updated to have the "likelySubtags" file
        switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
                return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
                return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
            default:
                return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
        }
    }

    /**
     * Return a bit mask of the differences between this Configuration
     * object and the given one.  Does not change the values of either.  Any
+114 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.util;

import java.util.Locale;

import libcore.icu.ICU;

/**
 * Various utilities for Locales
 *
 * @hide
 */
public class LocaleUtil {

    private LocaleUtil() { /* cannot be instantiated */ }

    /**
     * @hide Do not use. Implementation not finished.
     */
    public static final int TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE = -1;

    /**
     * @hide Do not use. Implementation not finished.
     */
    public static final int TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE = 0;

    /**
     * @hide Do not use. Implementation not finished.
     */
    public static final int TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE = 1;

    private static final char UNDERSCORE_CHAR = '_';

    private static String ARAB_SCRIPT_SUBTAG = "Arab";
    private static String HEBR_SCRIPT_SUBTAG = "Hebr";

    /**
     * Return the layout direction for a given Locale
     *
     * @param locale the Locale for which we want the layout direction. Can be null.
     * @return the layout direction. This may be one of:
     * {@link #TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE} or
     * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
     * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
     *
     * Be careful: this code will need to be changed when vertical scripts will be supported
     *
     * @hide
     */
    public static int getLayoutDirectionFromLocale(Locale locale) {
        if (locale == null || locale.equals(Locale.ROOT)) {
            return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
        }

        final String localeWithSubtags = ICU.addLikelySubtags(locale.toString());
        if (localeWithSubtags == null) return getLayoutDirectionFromFirstChar(locale);

        // Need to check if we can extract the script subtag. For example, "Latn" in  "en_Latn_US"
        if (localeWithSubtags.charAt(2) != UNDERSCORE_CHAR ||
                localeWithSubtags.charAt(7) != UNDERSCORE_CHAR) {
            return getLayoutDirectionFromFirstChar(locale);
        }
        // Extract the script subtag
        final String scriptSubtag = localeWithSubtags.substring(3, 7);

        if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
                scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
            return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
        }
        return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
    }

    /**
     * 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 #TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE} or
     * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
     * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
     *
     * Be careful: this code will need to be changed when vertical scripts will be supported
     *
     * @hide
     */
    private static int getLayoutDirectionFromFirstChar(Locale locale) {
        switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
                return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
                return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
            default:
                return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
        }
    }
}
+3 −12
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.view;

import android.util.FloatProperty;
import android.util.LocaleUtil;
import android.util.Property;
import com.android.internal.R;
import com.android.internal.util.Predicate;
@@ -8772,18 +8773,8 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
     * @return true if a Locale is corresponding to a RTL script.
     */
    private static boolean isLayoutDirectionRtl(Locale locale) {
        if (locale == null || locale.equals(Locale.ROOT)) return false;
        // Be careful: this code will need to be changed when vertical scripts will be supported
        // OR if ICU4C is updated to have the "likelySubtags" file
        switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
                return false;
            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
                return true;
            default:
                return false;
        }
        return (LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE ==
                LocaleUtil.getLayoutDirectionFromLocale(locale));
    }

    /**
+0 −198
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content.res;

import java.util.Locale;

import android.test.AndroidTestCase;
import dalvik.annotation.TestLevel;
import dalvik.annotation.TestTargetNew;

public class ConfigurationTest extends AndroidTestCase {

    @TestTargetNew(
        level = TestLevel.COMPLETE,
        method = "getLayoutDirectionFromLocale",
        args = {Locale.class}
    )
    public void testGetLayoutDirectionFromLocale() {
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(null));

        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.ENGLISH));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.CANADA));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.CANADA_FRENCH));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.FRANCE));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.FRENCH));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.GERMAN));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.GERMANY));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.ITALIAN));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.ITALY));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.UK));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.US));

        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.ROOT));

        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.CHINA));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.CHINESE));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.JAPAN));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.JAPANESE));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.KOREA));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.KOREAN));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.PRC));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.SIMPLIFIED_CHINESE));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.TAIWAN));
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(Locale.TRADITIONAL_CHINESE));

        Locale locale = new Locale("ar");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "AE");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "BH");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "DZ");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "EG");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "IQ");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "JO");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "KW");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "LB");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "LY");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "MA");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "OM");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "QA");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "SA");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "SD");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "SY");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "TN");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ar", "YE");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));

        locale = new Locale("fa");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("fa", "AF");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("fa", "IR");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));

        locale = new Locale("iw");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("iw", "IL");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("he");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("he", "IL");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));

        // The following test will not pass until we are able to take care about the scrip subtag
        // thru having the "likelySubTags" file into ICU4C
//        locale = new Locale("pa_Arab");
//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
//            Configuration.getLayoutDirectionFromLocale(locale));
//        locale = new Locale("pa_Arab", "PK");
//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
//            Configuration.getLayoutDirectionFromLocale(locale));

        locale = new Locale("ps");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));
        locale = new Locale("ps", "AF");
        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
            Configuration.getLayoutDirectionFromLocale(locale));

        // The following test will not work as the localized display name would be "Urdu" with ICU 4.4
        // We will need ICU 4.6 to get the correct localized display name
//        locale = new Locale("ur");
//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
//            Configuration.getLayoutDirectionFromLocale(locale));
//        locale = new Locale("ur", "IN");
//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
//            Configuration.getLayoutDirectionFromLocale(locale));
//        locale = new Locale("ur", "PK");
//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
//            Configuration.getLayoutDirectionFromLocale(locale));

        // The following test will not pass until we are able to take care about the scrip subtag
        // thru having the "likelySubTags" file into ICU4C
//        locale = new Locale("uz_Arab");
//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
//            Configuration.getLayoutDirectionFromLocale(locale));
//        locale = new Locale("uz_Arab", "AF");
//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
//            Configuration.getLayoutDirectionFromLocale(locale));
    }
}
+197 −0

File added.

Preview size limit exceeded, changes collapsed.