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

Commit 20312ddd authored by Maurice Lam's avatar Maurice Lam Committed by Gerrit Code Review
Browse files

Merge "Allow fallback translated languages in MccTable"

parents ff8c0eb6 3e55f0a3
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
    }
}