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

Commit 6d424490 authored by Maurice Lam's avatar Maurice Lam Committed by android-build-merger
Browse files

Merge "Allow fallback translated languages in MccTable"

am: 20312ddd

Change-Id: Iaf53e730f478c01982d2741c40d3ceb020c94db0
parents 138dbcd1 20312ddd
Loading
Loading
Loading
Loading
+51 −25
Original line number Diff line number Diff line
@@ -28,6 +28,12 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Slog;

import com.android.internal.app.LocaleStore;
import com.android.internal.app.LocaleStore.LocaleInfo;

import libcore.icu.ICU;
import libcore.icu.TimeZoneNames;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -36,9 +42,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;

import libcore.icu.ICU;
import libcore.icu.TimeZoneNames;

/**
 * Mobile Country Code
 *
@@ -235,21 +238,21 @@ public final class MccTable {
    static {
        // If we have English (without a country) explicitly prioritize en_US. http://b/28998094
        FALLBACKS.put(Locale.ENGLISH, Locale.US);
        FALLBACKS.put(Locale.CANADA, Locale.US);
    }

    /**
     * Find the best match we actually have a localization for. This function assumes we
     * couldn't find an exact match.
     * Finds a suitable locale among {@code candidates} to use as the fallback locale for
     * {@code target}. This looks through the list of {@link #FALLBACKS}, and follows the chain
     * until a locale in {@code candidates} is found.
     * This function assumes that {@code target} is not in {@code candidates}.
     *
     * TODO: This should really follow the CLDR chain of parent locales! That might be a bit
     * of a problem because we don't really have an en-001 locale on android.
     *
     * @return The fallback locale or {@code null} if there is no suitable fallback defined in the
     *         lookup.
     */
    private static Locale chooseBestFallback(Locale target, List<Locale> candidates) {
        if (candidates.isEmpty()) {
            return null;
        }

    private static Locale lookupFallback(Locale target, List<Locale> candidates) {
        Locale fallback = target;
        while ((fallback = FALLBACKS.get(fallback)) != null) {
            if (candidates.contains(fallback)) {
@@ -257,11 +260,7 @@ public final class MccTable {
            }
        }

        // Somewhat arbitrarily take the first locale for the language,
        // unless we get a perfect match later. Note that these come back in no
        // particular order, so there's no reason to think the first match is
        // a particularly good match.
        return candidates.get(0);
        return null;
    }

    /**
@@ -314,14 +313,40 @@ public final class MccTable {
                }
            }

            Locale bestMatch = chooseBestFallback(target, languageMatches);
            if (languageMatches.isEmpty()) {
                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: no locales for language " + language);
                return null;
            }

            Locale bestMatch = lookupFallback(target, languageMatches);
            if (bestMatch != null) {
                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got a language-only match: " +
                       bestMatch.toLanguageTag());
                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got a fallback match: "
                        + bestMatch.toLanguageTag());
                return bestMatch;
            } else {
                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: no locales for language " +
                       language);
                // Ask {@link LocaleStore} whether this locale is considered "translated".
                // LocaleStore has a broader definition of translated than just the asset locales
                // above: a locale is "translated" if it has translation assets, or another locale
                // with the same language and script has translation assets.
                // If a locale is "translated", it is selectable in setup wizard, and can therefore
                // be considerd a valid result for this method.
                if (!TextUtils.isEmpty(target.getCountry())) {
                    LocaleStore.fillCache(context);
                    LocaleInfo targetInfo = LocaleStore.getLocaleInfo(target);
                    if (targetInfo.isTranslated()) {
                        Slog.d(LOG_TAG, "getLocaleForLanguageCountry: "
                                + "target locale is translated: " + target);
                        return target;
                    }
                }

                // Somewhat arbitrarily take the first locale for the language,
                // unless we get a perfect match later. Note that these come back in no
                // particular order, so there's no reason to think the first match is
                // a particularly good match.
                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got language-only match: "
                        + language);
                return languageMatches.get(0);
            }
        } catch (Exception e) {
            Slog.d(LOG_TAG, "getLocaleForLanguageCountry: exception", e);
@@ -359,7 +384,8 @@ public final class MccTable {
     * @return locale for the mcc or null if none
     */
    public static Locale getLocaleFromMcc(Context context, int mcc, String simLanguage) {
        String language = (simLanguage == null) ? MccTable.defaultLanguageForMcc(mcc) : simLanguage;
        boolean hasSimLanguage = !TextUtils.isEmpty(simLanguage);
        String language = hasSimLanguage ? simLanguage : MccTable.defaultLanguageForMcc(mcc);
        String country = MccTable.countryCodeForMcc(mcc);

        Slog.d(LOG_TAG, "getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
@@ -367,10 +393,10 @@ public final class MccTable {

        // If we couldn't find a locale that matches the SIM language, give it a go again
        // with the "likely" language for the given country.
        if (locale == null && simLanguage != null) {
        if (locale == null && hasSimLanguage) {
            language = MccTable.defaultLanguageForMcc(mcc);
            Slog.d(LOG_TAG, "[retry ] getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
            return getLocaleForLanguageCountry(context, null, country);
            return getLocaleForLanguageCountry(context, language, country);
        }

        return locale;
+51 −37
Original line number Diff line number Diff line
@@ -16,67 +16,81 @@

package com.android.internal.telephony;

import com.android.internal.telephony.MccTable;

import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;

import android.telephony.Rlog;
import java.util.Locale;

public class MccTableTest extends AndroidTestCase {
    private final static String LOG_TAG = "GSM";

    @SmallTest
    public void testTimeZone() throws Exception {
        assertEquals(MccTable.defaultTimeZoneForMcc(208), "Europe/Paris");
        assertEquals(MccTable.defaultTimeZoneForMcc(232), "Europe/Vienna");
        assertEquals(MccTable.defaultTimeZoneForMcc(655), "Africa/Johannesburg");
        assertEquals(MccTable.defaultTimeZoneForMcc(440), "Asia/Tokyo");
        assertEquals(MccTable.defaultTimeZoneForMcc(441), "Asia/Tokyo");
        assertEquals(MccTable.defaultTimeZoneForMcc(525), "Asia/Singapore");
        assertEquals(MccTable.defaultTimeZoneForMcc(240), "Europe/Stockholm");
        assertEquals(MccTable.defaultTimeZoneForMcc(0), null);    // mcc not defined, hence default
        assertEquals(MccTable.defaultTimeZoneForMcc(2000), null); // mcc not defined, hence default
        assertEquals("Europe/Paris", MccTable.defaultTimeZoneForMcc(208));
        assertEquals("Europe/Vienna", MccTable.defaultTimeZoneForMcc(232));
        assertEquals("Africa/Johannesburg", MccTable.defaultTimeZoneForMcc(655));
        assertEquals("Asia/Tokyo", MccTable.defaultTimeZoneForMcc(440));
        assertEquals("Asia/Tokyo", MccTable.defaultTimeZoneForMcc(441));
        assertEquals("Asia/Singapore", MccTable.defaultTimeZoneForMcc(525));
        assertEquals("Europe/Stockholm", MccTable.defaultTimeZoneForMcc(240));
        assertEquals(null, MccTable.defaultTimeZoneForMcc(0));    // mcc not defined, hence default
        assertEquals(null, MccTable.defaultTimeZoneForMcc(2000)); // mcc not defined, hence default
    }

    @SmallTest
    public void testCountryCode() throws Exception {
        assertEquals(MccTable.countryCodeForMcc(270), "lu");
        assertEquals(MccTable.countryCodeForMcc(202), "gr");
        assertEquals(MccTable.countryCodeForMcc(750), "fk");
        assertEquals(MccTable.countryCodeForMcc(646), "mg");
        assertEquals(MccTable.countryCodeForMcc(314), "us");
        assertEquals(MccTable.countryCodeForMcc(300), "");  // mcc not defined, hence default
        assertEquals(MccTable.countryCodeForMcc(0), "");    // mcc not defined, hence default
        assertEquals(MccTable.countryCodeForMcc(2000), ""); // mcc not defined, hence default
        assertEquals("lu", MccTable.countryCodeForMcc(270));
        assertEquals("gr", MccTable.countryCodeForMcc(202));
        assertEquals("fk", MccTable.countryCodeForMcc(750));
        assertEquals("mg", MccTable.countryCodeForMcc(646));
        assertEquals("us", MccTable.countryCodeForMcc(314));
        assertEquals("", MccTable.countryCodeForMcc(300));  // mcc not defined, hence default
        assertEquals("", MccTable.countryCodeForMcc(0));    // mcc not defined, hence default
        assertEquals("", MccTable.countryCodeForMcc(2000)); // mcc not defined, hence default
    }

    @SmallTest
    public void testLang() throws Exception {
        assertEquals(MccTable.defaultLanguageForMcc(311), "en");
        assertEquals(MccTable.defaultLanguageForMcc(232), "de");
        assertEquals(MccTable.defaultLanguageForMcc(230), "cs");
        assertEquals(MccTable.defaultLanguageForMcc(204), "nl");
        assertEquals(MccTable.defaultLanguageForMcc(274), "is");
        assertEquals(MccTable.defaultLanguageForMcc(0), null);    // mcc not defined, hence default
        assertEquals(MccTable.defaultLanguageForMcc(2000), null); // mcc not defined, hence default
        assertEquals("en", MccTable.defaultLanguageForMcc(311));
        assertEquals("de", MccTable.defaultLanguageForMcc(232));
        assertEquals("cs", MccTable.defaultLanguageForMcc(230));
        assertEquals("nl", MccTable.defaultLanguageForMcc(204));
        assertEquals("is", MccTable.defaultLanguageForMcc(274));
        assertEquals(null, MccTable.defaultLanguageForMcc(0));    // mcc not defined, hence default
        assertEquals(null, MccTable.defaultLanguageForMcc(2000)); // mcc not defined, hence default
    }

    @SmallTest
    public void testLang_India() throws Exception {
        assertEquals(MccTable.defaultLanguageForMcc(404), "en");
        assertEquals(MccTable.defaultLanguageForMcc(405), "en");
        assertEquals(MccTable.defaultLanguageForMcc(406), "en");
        assertEquals("en", MccTable.defaultLanguageForMcc(404));
        assertEquals("en", MccTable.defaultLanguageForMcc(405));
        assertEquals("en", MccTable.defaultLanguageForMcc(406));
    }

    @SmallTest
    public void testLocale() throws Exception {
        assertEquals(Locale.forLanguageTag("en-CA"),
                MccTable.getLocaleFromMcc(getContext(), 302, null));
        assertEquals(Locale.forLanguageTag("en-GB"),
                MccTable.getLocaleFromMcc(getContext(), 234, null));
        assertEquals(Locale.forLanguageTag("en-US"),
                MccTable.getLocaleFromMcc(getContext(), 0, "en"));
        assertEquals(Locale.forLanguageTag("zh-HK"),
                MccTable.getLocaleFromMcc(getContext(), 454, null));
        assertEquals(Locale.forLanguageTag("en-HK"),
                MccTable.getLocaleFromMcc(getContext(), 454, "en"));
        assertEquals(Locale.forLanguageTag("zh-TW"),
                MccTable.getLocaleFromMcc(getContext(), 466, null));
    }

    @SmallTest
    public void testSmDigits() throws Exception {
        assertEquals(MccTable.smallestDigitsMccForMnc(312), 3);
        assertEquals(MccTable.smallestDigitsMccForMnc(430), 2);
        assertEquals(MccTable.smallestDigitsMccForMnc(365), 3);
        assertEquals(MccTable.smallestDigitsMccForMnc(536), 2);
        assertEquals(MccTable.smallestDigitsMccForMnc(352), 2);  // sd not defined, hence default
        assertEquals(MccTable.smallestDigitsMccForMnc(0), 2);    // mcc not defined, hence default
        assertEquals(MccTable.smallestDigitsMccForMnc(2000), 2); // mcc not defined, hence default
        assertEquals(3, MccTable.smallestDigitsMccForMnc(312));
        assertEquals(2, MccTable.smallestDigitsMccForMnc(430));
        assertEquals(3, MccTable.smallestDigitsMccForMnc(365));
        assertEquals(2, MccTable.smallestDigitsMccForMnc(536));
        assertEquals(2, MccTable.smallestDigitsMccForMnc(352));  // sd not defined, hence default
        assertEquals(2, MccTable.smallestDigitsMccForMnc(0));    // mcc not defined, hence default
        assertEquals(2, MccTable.smallestDigitsMccForMnc(2000)); // mcc not defined, hence default
    }
}