Loading core/java/android/provider/Settings.java +19 −2 Original line number Diff line number Diff line Loading @@ -1060,14 +1060,31 @@ public final class Settings { * In some cases, a matching Activity may not exist, so ensure you * safeguard against this. * <p> * Input: Nothing. * <p> * Input: The optional {@code #EXTRA_EXPLICIT_LOCALES} with language tags that contains locales * to limit available locales. This is only supported when device is under demo mode. * If intent does not contain this extra, it will show system supported locale list. * <br/> * If {@code #EXTRA_EXPLICIT_LOCALES} contain a unsupported locale, it will still show this * locale on list, but may not be supported by the devcie. * * Output: Nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS"; /** * Activity Extra: Show explicit locales in launched locale picker activity. * * This can be passed as an extra field in an Activity Intent with one or more language tags * as a {@link LocaleList}. This must be passed as an extra field to the * {@link #ACTION_LOCALE_SETTINGS}. * * @hide */ public static final String EXTRA_EXPLICIT_LOCALES = "android.provider.extra.EXPLICIT_LOCALES"; /** * Activity Action: Show settings to allow configuration of per application locale. * <p> Loading core/java/com/android/internal/app/LocalePickerWithRegion.java +11 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.FragmentTransaction; import android.app.ListFragment; import android.content.Context; import android.os.Bundle; import android.os.LocaleList; import android.text.TextUtils; import android.view.Menu; import android.view.MenuInflater; Loading Loading @@ -102,15 +103,21 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O public static LocalePickerWithRegion createLanguagePicker(Context context, LocaleSelectedListener listener, boolean translatedOnly) { return createLanguagePicker(context, listener, translatedOnly, null, null); return createLanguagePicker(context, listener, translatedOnly, null, null, null); } public static LocalePickerWithRegion createLanguagePicker(Context context, LocaleSelectedListener listener, boolean translatedOnly, String appPackageName, OnActionExpandListener onActionExpandListener) { LocaleSelectedListener listener, boolean translatedOnly, LocaleList explicitLocales) { return createLanguagePicker(context, listener, translatedOnly, explicitLocales, null, null); } /** Creates language picker UI */ public static LocalePickerWithRegion createLanguagePicker(Context context, LocaleSelectedListener listener, boolean translatedOnly, LocaleList explicitLocales, String appPackageName, OnActionExpandListener onActionExpandListener) { LocaleCollectorBase localePickerController; if (TextUtils.isEmpty(appPackageName)) { localePickerController = new SystemLocaleCollector(context); localePickerController = new SystemLocaleCollector(context, explicitLocales); } else { localePickerController = new AppLocaleCollector(context, appPackageName); } Loading core/java/com/android/internal/app/LocaleStore.java +81 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.Context; import android.os.LocaleList; import android.provider.Settings; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.inputmethod.InputMethodSubtype; Loading @@ -29,6 +30,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.IllformedLocaleException; Loading Loading @@ -106,6 +108,9 @@ public class LocaleStore { return mParent; } /** * TODO: This method may rename to be more generic i.e. toLanguageTag(). */ @UnsupportedAppUsage public String getId() { return mId; Loading Loading @@ -456,11 +461,30 @@ public class LocaleStore { @UnsupportedAppUsage public static Set<LocaleInfo> getLevelLocales(Context context, Set<String> ignorables, LocaleInfo parent, boolean translatedOnly) { return getLevelLocales(context, ignorables, parent, translatedOnly, null); } /** * @param explicitLocales Indicates only the locales within this list should be shown in the * locale picker. * * Returns a list of locales for language or region selection. * If the parent is null, then it is the language list. * If it is not null, then the list will contain all the locales that belong to that parent. * Example: if the parent is "ar", then the region list will contain all Arabic locales. * (this is not language based, but language-script, so that it works for zh-Hant and so on. */ public static Set<LocaleInfo> getLevelLocales(Context context, Set<String> ignorables, LocaleInfo parent, boolean translatedOnly, LocaleList explicitLocales) { fillCache(context); String parentId = parent == null ? null : parent.getId(); HashSet<LocaleInfo> result = new HashSet<>(); for (LocaleStore.LocaleInfo li : sLocaleCache.values()) { HashMap<String, LocaleInfo> supportedLcoaleInfos = explicitLocales == null ? sLocaleCache : convertExplicitLocales(explicitLocales, sLocaleCache.values()); for (LocaleStore.LocaleInfo li : supportedLcoaleInfos.values()) { int level = getLevel(ignorables, li, translatedOnly); if (level == 2) { if (parent != null) { // region selection Loading @@ -479,6 +503,61 @@ public class LocaleStore { return result; } /** Converts string array of explicit locales to HashMap */ public static HashMap<String, LocaleInfo> convertExplicitLocales( LocaleList explicitLocales, Collection<LocaleInfo> localeinfo) { // Trys to find the matched locale within android supported locales. If there is no matched // locale, it will still keep the unsupported lcoale in list. // Note: This currently does not support unicode extension check. LocaleList localeList = matchLocaleFromSupportedLocaleList( explicitLocales, localeinfo); HashMap<String, LocaleInfo> localeInfos = new HashMap<>(); for (int i = 0; i < localeList.size(); i++) { Locale locale = localeList.get(i); if (locale.toString().isEmpty()) { throw new IllformedLocaleException("Bad locale entry"); } LocaleInfo li = new LocaleInfo(locale); if (localeInfos.containsKey(li.getId())) { continue; } localeInfos.put(li.getId(), li); Locale parent = li.getParent(); if (parent != null) { String parentId = parent.toLanguageTag(); if (!localeInfos.containsKey(parentId)) { localeInfos.put(parentId, new LocaleInfo(parent)); } } } return localeInfos; } private static LocaleList matchLocaleFromSupportedLocaleList( LocaleList explicitLocales, Collection<LocaleInfo> localeinfo) { //TODO: Adds a function for unicode extension if needed. Locale[] resultLocales = new Locale[explicitLocales.size()]; for (int i = 0; i < explicitLocales.size(); i++) { Locale locale = explicitLocales.get(i).stripExtensions(); if (!TextUtils.isEmpty(locale.getCountry())) { for (LocaleInfo localeInfo :localeinfo) { if (LocaleList.matchesLanguageAndScript(locale, localeInfo.getLocale()) && TextUtils.equals(locale.getCountry(), localeInfo.getLocale().getCountry())) { resultLocales[i] = localeInfo.getLocale(); continue; } } } if (resultLocales[i] == null) { resultLocales[i] = locale; } } return new LocaleList(resultLocales); } @UnsupportedAppUsage public static LocaleInfo getLocaleInfo(Locale locale) { String id = locale.toLanguageTag(); Loading core/java/com/android/internal/app/SystemLocaleCollector.java +8 −4 Original line number Diff line number Diff line Loading @@ -26,9 +26,15 @@ import java.util.Set; /** The Locale data collector for System language. */ class SystemLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBase { private final Context mContext; private LocaleList mExplicitLocales; SystemLocaleCollector(Context context) { this(context, null); } SystemLocaleCollector(Context context, LocaleList explicitLocales) { mContext = context; mExplicitLocales = explicitLocales; } @Override Loading @@ -47,18 +53,16 @@ class SystemLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBas boolean translatedOnly, boolean isForCountryMode) { Set<String> langTagsToIgnore = getIgnoredLocaleList(translatedOnly); Set<LocaleStore.LocaleInfo> localeList; if (isForCountryMode) { localeList = LocaleStore.getLevelLocales(mContext, langTagsToIgnore, parent, translatedOnly); langTagsToIgnore, parent, translatedOnly, mExplicitLocales); } else { localeList = LocaleStore.getLevelLocales(mContext, langTagsToIgnore, null /* no parent */, translatedOnly); null /* no parent */, translatedOnly, mExplicitLocales); } return localeList; } @Override public boolean hasSpecificPackageName() { return false; Loading tests/Internal/src/com/android/internal/app/LocaleStoreTest.java +103 −8 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package com.android.internal.app; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.os.LocaleList; import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; Loading @@ -27,23 +29,21 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.app.LocaleStore.LocaleInfo; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.IllformedLocaleException; import java.util.List; import java.util.Locale; import java.util.Set; /** * Unit tests for the {@link LocaleStore}. */ /** Unit tests for the {@link LocaleStore}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class LocaleStoreTest { @Before public void setUp() { } @Test public void testTransformImeLanguageTagToLocaleInfo() { List<InputMethodSubtype> list = List.of( Loading @@ -60,4 +60,99 @@ public class LocaleStoreTest { assertTrue(expectedLanguageTag.contains(info.getId())); } } @Test public void convertExplicitLocales_noExplicitLcoales_returnEmptyHashMap() { Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales( LocaleList.getEmptyLocaleList(), supportedLocale); assertTrue(result.isEmpty()); } @Test public void convertExplicitLocales_hasEmptyLocale_receiveException() { Locale[] locales = {Locale.forLanguageTag(""), Locale.forLanguageTag("en-US")}; LocaleList localelist = new LocaleList(locales); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); boolean isReceiveException = false; try { LocaleStore.convertExplicitLocales(localelist, supportedLocale); } catch (IllformedLocaleException e) { isReceiveException = true; } assertTrue(isReceiveException); } @Test public void convertExplicitLocales_hasSameLocale_returnNonSameLocales() { LocaleList locales = LocaleList.forLanguageTags("en-US,en-US"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); // Only has "en" and "en-US". assertTrue(result.size() == 2); } @Test public void convertExplicitLocales_hasEnUs_resultHasParentEn() { LocaleList locales = LocaleList.forLanguageTags("en-US,ja-JP"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); assertEquals(result.get("en").getId(), "en"); } @Test public void convertExplicitLocales_hasZhTw_resultZhHantTw() { LocaleList locales = LocaleList.forLanguageTags("zh-TW,en-US,en"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); assertEquals("zh-Hant-TW", result.get("zh-Hant-TW").getId()); } @Test public void convertExplicitLocales_nonRegularFormat_resultEmptyContry() { LocaleList locales = LocaleList.forLanguageTags("de-1996,de-1901"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); assertEquals("de-1996", result.get("de-1996").getId()); assertTrue(result.get("de-1996").getLocale().getCountry().isEmpty()); } @Test public void convertExplicitLocales_differentEnFormat() { LocaleList locales = LocaleList.forLanguageTags("en-Latn-US,en-US,en"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); assertEquals("en", result.get("en").getId()); assertEquals("en-US", result.get("en-US").getId()); assertNull(result.get("en-Latn-US")); } private ArrayList<LocaleInfo> getFakeSupportedLocales() { String[] locales = {"en-US", "zh-Hant-TW", "ja-JP", "en-GB"}; ArrayList<LocaleInfo> supportedLocales = new ArrayList<>(); for (String localeTag : locales) { supportedLocales.add(LocaleStore.fromLocale(Locale.forLanguageTag(localeTag))); } return supportedLocales; } } Loading
core/java/android/provider/Settings.java +19 −2 Original line number Diff line number Diff line Loading @@ -1060,14 +1060,31 @@ public final class Settings { * In some cases, a matching Activity may not exist, so ensure you * safeguard against this. * <p> * Input: Nothing. * <p> * Input: The optional {@code #EXTRA_EXPLICIT_LOCALES} with language tags that contains locales * to limit available locales. This is only supported when device is under demo mode. * If intent does not contain this extra, it will show system supported locale list. * <br/> * If {@code #EXTRA_EXPLICIT_LOCALES} contain a unsupported locale, it will still show this * locale on list, but may not be supported by the devcie. * * Output: Nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS"; /** * Activity Extra: Show explicit locales in launched locale picker activity. * * This can be passed as an extra field in an Activity Intent with one or more language tags * as a {@link LocaleList}. This must be passed as an extra field to the * {@link #ACTION_LOCALE_SETTINGS}. * * @hide */ public static final String EXTRA_EXPLICIT_LOCALES = "android.provider.extra.EXPLICIT_LOCALES"; /** * Activity Action: Show settings to allow configuration of per application locale. * <p> Loading
core/java/com/android/internal/app/LocalePickerWithRegion.java +11 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.FragmentTransaction; import android.app.ListFragment; import android.content.Context; import android.os.Bundle; import android.os.LocaleList; import android.text.TextUtils; import android.view.Menu; import android.view.MenuInflater; Loading Loading @@ -102,15 +103,21 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O public static LocalePickerWithRegion createLanguagePicker(Context context, LocaleSelectedListener listener, boolean translatedOnly) { return createLanguagePicker(context, listener, translatedOnly, null, null); return createLanguagePicker(context, listener, translatedOnly, null, null, null); } public static LocalePickerWithRegion createLanguagePicker(Context context, LocaleSelectedListener listener, boolean translatedOnly, String appPackageName, OnActionExpandListener onActionExpandListener) { LocaleSelectedListener listener, boolean translatedOnly, LocaleList explicitLocales) { return createLanguagePicker(context, listener, translatedOnly, explicitLocales, null, null); } /** Creates language picker UI */ public static LocalePickerWithRegion createLanguagePicker(Context context, LocaleSelectedListener listener, boolean translatedOnly, LocaleList explicitLocales, String appPackageName, OnActionExpandListener onActionExpandListener) { LocaleCollectorBase localePickerController; if (TextUtils.isEmpty(appPackageName)) { localePickerController = new SystemLocaleCollector(context); localePickerController = new SystemLocaleCollector(context, explicitLocales); } else { localePickerController = new AppLocaleCollector(context, appPackageName); } Loading
core/java/com/android/internal/app/LocaleStore.java +81 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.Context; import android.os.LocaleList; import android.provider.Settings; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.inputmethod.InputMethodSubtype; Loading @@ -29,6 +30,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.IllformedLocaleException; Loading Loading @@ -106,6 +108,9 @@ public class LocaleStore { return mParent; } /** * TODO: This method may rename to be more generic i.e. toLanguageTag(). */ @UnsupportedAppUsage public String getId() { return mId; Loading Loading @@ -456,11 +461,30 @@ public class LocaleStore { @UnsupportedAppUsage public static Set<LocaleInfo> getLevelLocales(Context context, Set<String> ignorables, LocaleInfo parent, boolean translatedOnly) { return getLevelLocales(context, ignorables, parent, translatedOnly, null); } /** * @param explicitLocales Indicates only the locales within this list should be shown in the * locale picker. * * Returns a list of locales for language or region selection. * If the parent is null, then it is the language list. * If it is not null, then the list will contain all the locales that belong to that parent. * Example: if the parent is "ar", then the region list will contain all Arabic locales. * (this is not language based, but language-script, so that it works for zh-Hant and so on. */ public static Set<LocaleInfo> getLevelLocales(Context context, Set<String> ignorables, LocaleInfo parent, boolean translatedOnly, LocaleList explicitLocales) { fillCache(context); String parentId = parent == null ? null : parent.getId(); HashSet<LocaleInfo> result = new HashSet<>(); for (LocaleStore.LocaleInfo li : sLocaleCache.values()) { HashMap<String, LocaleInfo> supportedLcoaleInfos = explicitLocales == null ? sLocaleCache : convertExplicitLocales(explicitLocales, sLocaleCache.values()); for (LocaleStore.LocaleInfo li : supportedLcoaleInfos.values()) { int level = getLevel(ignorables, li, translatedOnly); if (level == 2) { if (parent != null) { // region selection Loading @@ -479,6 +503,61 @@ public class LocaleStore { return result; } /** Converts string array of explicit locales to HashMap */ public static HashMap<String, LocaleInfo> convertExplicitLocales( LocaleList explicitLocales, Collection<LocaleInfo> localeinfo) { // Trys to find the matched locale within android supported locales. If there is no matched // locale, it will still keep the unsupported lcoale in list. // Note: This currently does not support unicode extension check. LocaleList localeList = matchLocaleFromSupportedLocaleList( explicitLocales, localeinfo); HashMap<String, LocaleInfo> localeInfos = new HashMap<>(); for (int i = 0; i < localeList.size(); i++) { Locale locale = localeList.get(i); if (locale.toString().isEmpty()) { throw new IllformedLocaleException("Bad locale entry"); } LocaleInfo li = new LocaleInfo(locale); if (localeInfos.containsKey(li.getId())) { continue; } localeInfos.put(li.getId(), li); Locale parent = li.getParent(); if (parent != null) { String parentId = parent.toLanguageTag(); if (!localeInfos.containsKey(parentId)) { localeInfos.put(parentId, new LocaleInfo(parent)); } } } return localeInfos; } private static LocaleList matchLocaleFromSupportedLocaleList( LocaleList explicitLocales, Collection<LocaleInfo> localeinfo) { //TODO: Adds a function for unicode extension if needed. Locale[] resultLocales = new Locale[explicitLocales.size()]; for (int i = 0; i < explicitLocales.size(); i++) { Locale locale = explicitLocales.get(i).stripExtensions(); if (!TextUtils.isEmpty(locale.getCountry())) { for (LocaleInfo localeInfo :localeinfo) { if (LocaleList.matchesLanguageAndScript(locale, localeInfo.getLocale()) && TextUtils.equals(locale.getCountry(), localeInfo.getLocale().getCountry())) { resultLocales[i] = localeInfo.getLocale(); continue; } } } if (resultLocales[i] == null) { resultLocales[i] = locale; } } return new LocaleList(resultLocales); } @UnsupportedAppUsage public static LocaleInfo getLocaleInfo(Locale locale) { String id = locale.toLanguageTag(); Loading
core/java/com/android/internal/app/SystemLocaleCollector.java +8 −4 Original line number Diff line number Diff line Loading @@ -26,9 +26,15 @@ import java.util.Set; /** The Locale data collector for System language. */ class SystemLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBase { private final Context mContext; private LocaleList mExplicitLocales; SystemLocaleCollector(Context context) { this(context, null); } SystemLocaleCollector(Context context, LocaleList explicitLocales) { mContext = context; mExplicitLocales = explicitLocales; } @Override Loading @@ -47,18 +53,16 @@ class SystemLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBas boolean translatedOnly, boolean isForCountryMode) { Set<String> langTagsToIgnore = getIgnoredLocaleList(translatedOnly); Set<LocaleStore.LocaleInfo> localeList; if (isForCountryMode) { localeList = LocaleStore.getLevelLocales(mContext, langTagsToIgnore, parent, translatedOnly); langTagsToIgnore, parent, translatedOnly, mExplicitLocales); } else { localeList = LocaleStore.getLevelLocales(mContext, langTagsToIgnore, null /* no parent */, translatedOnly); null /* no parent */, translatedOnly, mExplicitLocales); } return localeList; } @Override public boolean hasSpecificPackageName() { return false; Loading
tests/Internal/src/com/android/internal/app/LocaleStoreTest.java +103 −8 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package com.android.internal.app; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.os.LocaleList; import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; Loading @@ -27,23 +29,21 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.app.LocaleStore.LocaleInfo; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.IllformedLocaleException; import java.util.List; import java.util.Locale; import java.util.Set; /** * Unit tests for the {@link LocaleStore}. */ /** Unit tests for the {@link LocaleStore}. */ @SmallTest @RunWith(AndroidJUnit4.class) public class LocaleStoreTest { @Before public void setUp() { } @Test public void testTransformImeLanguageTagToLocaleInfo() { List<InputMethodSubtype> list = List.of( Loading @@ -60,4 +60,99 @@ public class LocaleStoreTest { assertTrue(expectedLanguageTag.contains(info.getId())); } } @Test public void convertExplicitLocales_noExplicitLcoales_returnEmptyHashMap() { Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales( LocaleList.getEmptyLocaleList(), supportedLocale); assertTrue(result.isEmpty()); } @Test public void convertExplicitLocales_hasEmptyLocale_receiveException() { Locale[] locales = {Locale.forLanguageTag(""), Locale.forLanguageTag("en-US")}; LocaleList localelist = new LocaleList(locales); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); boolean isReceiveException = false; try { LocaleStore.convertExplicitLocales(localelist, supportedLocale); } catch (IllformedLocaleException e) { isReceiveException = true; } assertTrue(isReceiveException); } @Test public void convertExplicitLocales_hasSameLocale_returnNonSameLocales() { LocaleList locales = LocaleList.forLanguageTags("en-US,en-US"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); // Only has "en" and "en-US". assertTrue(result.size() == 2); } @Test public void convertExplicitLocales_hasEnUs_resultHasParentEn() { LocaleList locales = LocaleList.forLanguageTags("en-US,ja-JP"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); assertEquals(result.get("en").getId(), "en"); } @Test public void convertExplicitLocales_hasZhTw_resultZhHantTw() { LocaleList locales = LocaleList.forLanguageTags("zh-TW,en-US,en"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); assertEquals("zh-Hant-TW", result.get("zh-Hant-TW").getId()); } @Test public void convertExplicitLocales_nonRegularFormat_resultEmptyContry() { LocaleList locales = LocaleList.forLanguageTags("de-1996,de-1901"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); assertEquals("de-1996", result.get("de-1996").getId()); assertTrue(result.get("de-1996").getLocale().getCountry().isEmpty()); } @Test public void convertExplicitLocales_differentEnFormat() { LocaleList locales = LocaleList.forLanguageTags("en-Latn-US,en-US,en"); Collection<LocaleInfo> supportedLocale = getFakeSupportedLocales(); HashMap<String, LocaleInfo> result = LocaleStore.convertExplicitLocales(locales, supportedLocale); assertEquals("en", result.get("en").getId()); assertEquals("en-US", result.get("en-US").getId()); assertNull(result.get("en-Latn-US")); } private ArrayList<LocaleInfo> getFakeSupportedLocales() { String[] locales = {"en-US", "zh-Hant-TW", "ja-JP", "en-GB"}; ArrayList<LocaleInfo> supportedLocales = new ArrayList<>(); for (String localeTag : locales) { supportedLocales.add(LocaleStore.fromLocale(Locale.forLanguageTag(localeTag))); } return supportedLocales; } }