diff options
5 files changed, 518 insertions, 39 deletions
diff --git a/core/java/com/android/internal/app/AppLocaleCollector.java b/core/java/com/android/internal/app/AppLocaleCollector.java index 65e8c646e17d..a50fbb81dc6b 100644 --- a/core/java/com/android/internal/app/AppLocaleCollector.java +++ b/core/java/com/android/internal/app/AppLocaleCollector.java @@ -19,49 +19,184 @@ package com.android.internal.app; import static com.android.internal.app.AppLocaleStore.AppLocaleResult.LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_ASSET; import static com.android.internal.app.AppLocaleStore.AppLocaleResult.LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG; +import android.app.LocaleManager; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.os.Build; import android.os.LocaleList; +import android.os.SystemProperties; +import android.provider.Settings; import android.util.Log; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.stream.Collectors; /** The Locale data collector for per-app language. */ -class AppLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBase { +public class AppLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBase { private static final String TAG = AppLocaleCollector.class.getSimpleName(); private final Context mContext; private final String mAppPackageName; - private final LocaleStore.LocaleInfo mAppCurrentLocale; + private LocaleStore.LocaleInfo mAppCurrentLocale; + private Set<LocaleStore.LocaleInfo> mAllAppActiveLocales; + private Set<LocaleStore.LocaleInfo> mImeLocales; + private static final String PROP_APP_LANGUAGE_SUGGESTION = + "android.app.language.suggestion.enhanced"; + private static final boolean ENABLED = true; - AppLocaleCollector(Context context, String appPackageName) { + public AppLocaleCollector(Context context, String appPackageName) { mContext = context; mAppPackageName = appPackageName; - mAppCurrentLocale = LocaleStore.getAppCurrentLocaleInfo( - mContext, mAppPackageName); + } + + @VisibleForTesting + public LocaleStore.LocaleInfo getAppCurrentLocale() { + return LocaleStore.getAppActivatedLocaleInfo(mContext, mAppPackageName, true); + } + + /** + * Get all applications' activated locales. + * @return A set which includes all applications' activated LocaleInfo. + */ + @VisibleForTesting + public Set<LocaleStore.LocaleInfo> getAllAppActiveLocales() { + PackageManager pm = mContext.getPackageManager(); + LocaleManager lm = mContext.getSystemService(LocaleManager.class); + HashSet<LocaleStore.LocaleInfo> result = new HashSet<>(); + if (pm != null && lm != null) { + HashMap<String, LocaleStore.LocaleInfo> map = new HashMap<>(); + for (ApplicationInfo appInfo : pm.getInstalledApplications( + PackageManager.ApplicationInfoFlags.of(0))) { + LocaleStore.LocaleInfo localeInfo = LocaleStore.getAppActivatedLocaleInfo( + mContext, appInfo.packageName, false); + // For the locale to be added into the suggestion area, its country could not be + // empty. + if (localeInfo != null && localeInfo.getLocale().getCountry().length() > 0) { + map.put(localeInfo.getId(), localeInfo); + } + } + map.forEach((language, localeInfo) -> result.add(localeInfo)); + } + return result; + } + + /** + * Get all locales that active IME supports. + * + * @return A set which includes all LocaleInfo that active IME supports. + */ + @VisibleForTesting + public Set<LocaleStore.LocaleInfo> getActiveImeLocales() { + Set<LocaleStore.LocaleInfo> activeImeLocales = null; + InputMethodManager imm = mContext.getSystemService(InputMethodManager.class); + if (imm != null) { + InputMethodInfo activeIme = getActiveIme(imm); + if (activeIme != null) { + activeImeLocales = LocaleStore.transformImeLanguageTagToLocaleInfo( + imm.getEnabledInputMethodSubtypeList(activeIme, true)); + } + } + if (activeImeLocales == null) { + return Set.of(); + } else { + return activeImeLocales.stream().filter( + // For the locale to be added into the suggestion area, its country could not be + // empty. + info -> info.getLocale().getCountry().length() > 0).collect( + Collectors.toSet()); + } + } + + private InputMethodInfo getActiveIme(InputMethodManager imm) { + InputMethodInfo activeIme = null; + List<InputMethodInfo> infoList = imm.getEnabledInputMethodList(); + String imeId = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, mContext.getUserId()); + for (InputMethodInfo method : infoList) { + if (method.getId().equals(imeId)) { + activeIme = method; + } + } + return activeIme; + } + + /** + * Get the AppLocaleResult that the application supports. + * @return The AppLocaleResult that the application supports. + */ + @VisibleForTesting + public AppLocaleStore.AppLocaleResult getAppSupportedLocales() { + return AppLocaleStore.getAppSupportedLocales(mContext, mAppPackageName); + } + + /** + * Get the locales that system supports excluding langTagsToIgnore. + * + * @param langTagsToIgnore A language set to be ignored. + * @param parent The parent locale. + * @param translatedOnly specified if is is only for translation. + * @return A set which includes the LocaleInfo that system supports, excluding langTagsToIgnore. + */ + @VisibleForTesting + public Set<LocaleStore.LocaleInfo> getSystemSupportedLocale(Set<String> langTagsToIgnore, + LocaleStore.LocaleInfo parent, boolean translatedOnly) { + return LocaleStore.getLevelLocales(mContext, langTagsToIgnore, parent, translatedOnly); + } + + /** + * Get the locales that system activates. + * @return A set which includes all the locales that system activates. + */ + @VisibleForTesting + public List<LocaleStore.LocaleInfo> getSystemCurrentLocale() { + return LocaleStore.getSystemCurrentLocaleInfo(); } @Override public HashSet<String> getIgnoredLocaleList(boolean translatedOnly) { HashSet<String> langTagsToIgnore = new HashSet<>(); - LocaleList systemLangList = LocaleList.getDefault(); - for(int i = 0; i < systemLangList.size(); i++) { - langTagsToIgnore.add(systemLangList.get(i).toLanguageTag()); - } - if (mAppCurrentLocale != null) { langTagsToIgnore.add(mAppCurrentLocale.getLocale().toLanguageTag()); } + + if (SystemProperties.getBoolean(PROP_APP_LANGUAGE_SUGGESTION, ENABLED)) { + // Add the locale that other App activated + mAllAppActiveLocales.forEach( + info -> langTagsToIgnore.add(info.getLocale().toLanguageTag())); + // Add the locale that active IME enabled + mImeLocales.forEach(info -> langTagsToIgnore.add(info.getLocale().toLanguageTag())); + } + + // Add System locales + LocaleList systemLangList = LocaleList.getDefault(); + for (int i = 0; i < systemLangList.size(); i++) { + langTagsToIgnore.add(systemLangList.get(i).toLanguageTag()); + } return langTagsToIgnore; } @Override public Set<LocaleStore.LocaleInfo> getSupportedLocaleList(LocaleStore.LocaleInfo parent, boolean translatedOnly, boolean isForCountryMode) { - AppLocaleStore.AppLocaleResult result = - AppLocaleStore.getAppSupportedLocales(mContext, mAppPackageName); + if (mAppCurrentLocale == null) { + mAppCurrentLocale = getAppCurrentLocale(); + } + if (mAllAppActiveLocales == null) { + mAllAppActiveLocales = getAllAppActiveLocales(); + } + if (mImeLocales == null) { + mImeLocales = getActiveImeLocales(); + } + AppLocaleStore.AppLocaleResult result = getAppSupportedLocales(); Set<String> langTagsToIgnore = getIgnoredLocaleList(translatedOnly); Set<LocaleStore.LocaleInfo> appLocaleList = new HashSet<>(); Set<LocaleStore.LocaleInfo> systemLocaleList; @@ -71,11 +206,9 @@ class AppLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBase { // Get system supported locale list if (isForCountryMode) { - systemLocaleList = LocaleStore.getLevelLocales(mContext, - langTagsToIgnore, parent, translatedOnly); + systemLocaleList = getSystemSupportedLocale(langTagsToIgnore, parent, translatedOnly); } else { - systemLocaleList = LocaleStore.getLevelLocales(mContext, langTagsToIgnore, - null /* no parent */, translatedOnly); + systemLocaleList = getSystemSupportedLocale(langTagsToIgnore, null, translatedOnly); } // Add current app locale @@ -84,19 +217,46 @@ class AppLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBase { } // Add current system language into suggestion list - for(LocaleStore.LocaleInfo localeInfo: - LocaleStore.getSystemCurrentLocaleInfo()) { - boolean isNotCurrentLocale = mAppCurrentLocale == null - || !localeInfo.getLocale().equals(mAppCurrentLocale.getLocale()); - if (!isForCountryMode && isNotCurrentLocale) { - appLocaleList.add(localeInfo); + if (!isForCountryMode) { + boolean isCurrentLocale, isInAppOrIme; + for (LocaleStore.LocaleInfo localeInfo : getSystemCurrentLocale()) { + isCurrentLocale = mAppCurrentLocale != null + && localeInfo.getLocale().equals(mAppCurrentLocale.getLocale()); + isInAppOrIme = existsInAppOrIme(localeInfo.getLocale()); + if (!isCurrentLocale && !isInAppOrIme) { + appLocaleList.add(localeInfo); + } } } - // Add the languages that included in system supported locale + // Add the languages that are included in system supported locale + Set<LocaleStore.LocaleInfo> suggestedSet = null; if (shouldShowList) { - appLocaleList.addAll(filterTheLanguagesNotIncludedInSystemLocale( - systemLocaleList, result.mAppSupportedLocales)); + appLocaleList.addAll(filterSupportedLocales(systemLocaleList, + result.mAppSupportedLocales)); + suggestedSet = getSuggestedLocales(appLocaleList); + } + + if (!isForCountryMode && SystemProperties.getBoolean(PROP_APP_LANGUAGE_SUGGESTION, + ENABLED)) { + // Add the language that other apps activate into the suggestion list. + Set<LocaleStore.LocaleInfo> localeSet = filterSupportedLocales(mAllAppActiveLocales, + result.mAppSupportedLocales); + if (suggestedSet != null) { + // Filter out the locale with the same language and country + // like zh-TW vs zh-Hant-TW. + localeSet = filterSameLanguageAndCountry(localeSet, suggestedSet); + } + appLocaleList.addAll(localeSet); + suggestedSet.addAll(localeSet); + + // Add the language that the active IME enables into the suggestion list. + localeSet = filterSupportedLocales(mImeLocales, result.mAppSupportedLocales); + if (suggestedSet != null) { + localeSet = filterSameLanguageAndCountry(localeSet, suggestedSet); + } + appLocaleList.addAll(localeSet); + suggestedSet.addAll(localeSet); } // Add "system language" option @@ -117,17 +277,55 @@ class AppLocaleCollector implements LocalePickerWithRegion.LocaleCollectorBase { return true; } - private Set<LocaleStore.LocaleInfo> filterTheLanguagesNotIncludedInSystemLocale( - Set<LocaleStore.LocaleInfo> systemLocaleList, + private Set<LocaleStore.LocaleInfo> getSuggestedLocales(Set<LocaleStore.LocaleInfo> localeSet) { + return localeSet.stream().filter(localeInfo -> localeInfo.isSuggested()).collect( + Collectors.toSet()); + } + + private Set<LocaleStore.LocaleInfo> filterSameLanguageAndCountry( + Set<LocaleStore.LocaleInfo> newLocaleList, + Set<LocaleStore.LocaleInfo> existingLocaleList) { + Set<LocaleStore.LocaleInfo> result = new HashSet<>(newLocaleList.size()); + for (LocaleStore.LocaleInfo appLocaleInfo : newLocaleList) { + boolean same = false; + Locale appLocale = appLocaleInfo.getLocale(); + for (LocaleStore.LocaleInfo localeInfo : existingLocaleList) { + Locale suggested = localeInfo.getLocale(); + if (appLocale.getLanguage().equals(suggested.getLanguage()) + && appLocale.getCountry().equals(suggested.getCountry())) { + same = true; + break; + } + } + if (!same) { + result.add(appLocaleInfo); + } + } + return result; + } + + private boolean existsInAppOrIme(Locale locale) { + boolean existInApp = mAllAppActiveLocales.stream().anyMatch( + localeInfo -> localeInfo.getLocale().equals(locale)); + if (existInApp) { + return true; + } else { + return mImeLocales.stream().anyMatch( + localeInfo -> localeInfo.getLocale().equals(locale)); + } + } + + private Set<LocaleStore.LocaleInfo> filterSupportedLocales( + Set<LocaleStore.LocaleInfo> suggestedLocales, HashSet<Locale> appSupportedLocales) { Set<LocaleStore.LocaleInfo> filteredList = new HashSet<>(); - for(LocaleStore.LocaleInfo li: systemLocaleList) { + for (LocaleStore.LocaleInfo li : suggestedLocales) { if (appSupportedLocales.contains(li.getLocale())) { filteredList.add(li); } else { - for(Locale l: appSupportedLocales) { - if(LocaleList.matchesLanguageAndScript(li.getLocale(), l)) { + for (Locale l : appSupportedLocales) { + if (LocaleList.matchesLanguageAndScript(li.getLocale(), l)) { filteredList.add(li); break; } diff --git a/core/java/com/android/internal/app/AppLocaleStore.java b/core/java/com/android/internal/app/AppLocaleStore.java index f3a322cac79a..a450a05dd315 100644 --- a/core/java/com/android/internal/app/AppLocaleStore.java +++ b/core/java/com/android/internal/app/AppLocaleStore.java @@ -30,7 +30,10 @@ import java.util.HashSet; import java.util.Locale; import java.util.stream.Collectors; -class AppLocaleStore { +/** + * A class used to access an application's supporting locales. + */ +public class AppLocaleStore { private static final String TAG = AppLocaleStore.class.getSimpleName(); public static AppLocaleResult getAppSupportedLocales( @@ -148,8 +151,11 @@ class AppLocaleStore { return false; } - static class AppLocaleResult { - enum LocaleStatus { + /** + * A class used to store an application's supporting locales. + */ + public static class AppLocaleResult { + public enum LocaleStatus { UNKNOWN_FAILURE, NO_SUPPORTED_LANGUAGE_IN_APP, ASSET_LOCALE_IS_EMPTY, @@ -158,7 +164,7 @@ class AppLocaleStore { } LocaleStatus mLocaleStatus; - HashSet<Locale> mAppSupportedLocales; + public HashSet<Locale> mAppSupportedLocales; public AppLocaleResult(LocaleStatus localeStatus, HashSet<Locale> appSupportedLocales) { this.mLocaleStatus = localeStatus; diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java index 689dec479c89..d2eee91d257f 100644 --- a/core/java/com/android/internal/app/LocaleStore.java +++ b/core/java/com/android/internal/app/LocaleStore.java @@ -23,6 +23,7 @@ import android.os.LocaleList; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.Log; +import android.view.inputmethod.InputMethodSubtype; import com.android.internal.annotations.VisibleForTesting; @@ -45,10 +46,11 @@ public class LocaleStore { @VisibleForTesting static final int SUGGESTION_TYPE_SIM = 1 << 0; @VisibleForTesting static final int SUGGESTION_TYPE_CFG = 1 << 1; // Only for per-app language picker - private static final int SUGGESTION_TYPE_CURRENT = 1 << 2; + @VisibleForTesting static final int SUGGESTION_TYPE_CURRENT = 1 << 2; // Only for per-app language picker - private static final int SUGGESTION_TYPE_SYSTEM_LANGUAGE = 1 << 3; - + @VisibleForTesting static final int SUGGESTION_TYPE_SYSTEM_LANGUAGE = 1 << 3; + // Only for per-app language picker + @VisibleForTesting static final int SUGGESTION_TYPE_OTHER_APP_LANGUAGE = 1 << 4; private final Locale mLocale; private final Locale mParent; private final String mId; @@ -259,7 +261,16 @@ public class LocaleStore { } } - public static LocaleInfo getAppCurrentLocaleInfo(Context context, String appPackageName) { + /** + * Get the application's activated locale. + * + * @param context UI activity's context. + * @param appPackageName The application's package name. + * @param isAppSelected True if the application is selected in the UI; false otherwise. + * @return A LocaleInfo with the application's activated locale. + */ + public static LocaleInfo getAppActivatedLocaleInfo(Context context, String appPackageName, + boolean isAppSelected) { if (appPackageName == null) { return null; } @@ -272,7 +283,11 @@ public class LocaleStore { if (locale != null) { LocaleInfo localeInfo = new LocaleInfo(locale); - localeInfo.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_CURRENT; + if (isAppSelected) { + localeInfo.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_CURRENT; + } else { + localeInfo.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_OTHER_APP_LANGUAGE; + } localeInfo.mIsTranslated = true; return localeInfo; } @@ -283,6 +298,24 @@ public class LocaleStore { } /** + * Transform IME's language tag to LocaleInfo. + * + * @param list A list which includes IME's subtype. + * @return A LocaleInfo set which includes IME's language tags. + */ + public static Set<LocaleInfo> transformImeLanguageTagToLocaleInfo( + List<InputMethodSubtype> list) { + Set<LocaleInfo> imeLocales = new HashSet<>(); + for (InputMethodSubtype subtype : list) { + LocaleInfo localeInfo = new LocaleInfo(subtype.getLanguageTag()); + localeInfo.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_OTHER_APP_LANGUAGE; + localeInfo.mIsTranslated = true; + imeLocales.add(localeInfo); + } + return imeLocales; + } + + /** * Returns a list of system languages with LocaleInfo */ public static List<LocaleInfo> getSystemCurrentLocaleInfo() { @@ -458,4 +491,13 @@ public class LocaleStore { } return result; } + + /** + * API for testing. + */ + @UnsupportedAppUsage + @VisibleForTesting + public static LocaleInfo fromLocale(Locale locale) { + return new LocaleInfo(locale); + } } diff --git a/tests/Internal/src/com/android/internal/app/AppLocaleCollectorTest.java b/tests/Internal/src/com/android/internal/app/AppLocaleCollectorTest.java new file mode 100644 index 000000000000..b24ac3cae795 --- /dev/null +++ b/tests/Internal/src/com/android/internal/app/AppLocaleCollectorTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2022 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 com.android.internal.app; + +import static com.android.internal.app.AppLocaleStore.AppLocaleResult.LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyObject; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +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.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +/** + * Unit tests for the {@link AppLocaleCollector}. + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class AppLocaleCollectorTest { + private static final String TAG = "AppLocaleCollectorTest"; + private AppLocaleCollector mAppLocaleCollector; + private LocaleStore.LocaleInfo mAppCurrentLocale; + private Set<LocaleInfo> mAllAppActiveLocales; + private Set<LocaleInfo> mImeLocales; + private List<LocaleInfo> mSystemCurrentLocales; + private Set<LocaleInfo> mSystemSupportedLocales; + private AppLocaleStore.AppLocaleResult mResult; + private static final String PKG1 = "pkg1"; + private static final int NONE = LocaleInfo.SUGGESTION_TYPE_NONE; + private static final int SIM = LocaleInfo.SUGGESTION_TYPE_SIM; + private static final int CFG = LocaleInfo.SUGGESTION_TYPE_CFG; + private static final int SIM_CFG = SIM | CFG; + private static final int CURRENT = LocaleInfo.SUGGESTION_TYPE_CURRENT; + private static final int SYSTEM = LocaleInfo.SUGGESTION_TYPE_SYSTEM_LANGUAGE; + private static final int OTHERAPP = LocaleInfo.SUGGESTION_TYPE_OTHER_APP_LANGUAGE; + + @Before + public void setUp() throws Exception { + mAppLocaleCollector = spy( + new AppLocaleCollector(InstrumentationRegistry.getContext(), PKG1)); + + mAppCurrentLocale = createLocaleInfo("en-US", CURRENT); + mAllAppActiveLocales = initAllAppActivatedLocales(); + mImeLocales = initImeLocales(); + mSystemSupportedLocales = initSystemSupportedLocales(); + mSystemCurrentLocales = initSystemCurrentLocales(); + mResult = new AppLocaleStore.AppLocaleResult(GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG, + initAppSupportedLocale()); + } + + @Test + public void testGetSupportedLocaleList() { + doReturn(mAppCurrentLocale).when(mAppLocaleCollector).getAppCurrentLocale(); + doReturn(mResult).when(mAppLocaleCollector).getAppSupportedLocales(); + doReturn(mAllAppActiveLocales).when(mAppLocaleCollector).getAllAppActiveLocales(); + doReturn(mImeLocales).when(mAppLocaleCollector).getActiveImeLocales(); + doReturn(mSystemSupportedLocales).when(mAppLocaleCollector).getSystemSupportedLocale( + anyObject(), eq(null), eq(true)); + doReturn(mSystemCurrentLocales).when(mAppLocaleCollector).getSystemCurrentLocale(); + + Set<LocaleInfo> result = mAppLocaleCollector.getSupportedLocaleList(null, true, false); + + HashMap<String, Integer> expectedResult = getExpectedResult(); + assertEquals(result.size(), expectedResult.size()); + for (LocaleInfo source : result) { + int suggestionFlags = expectedResult.getOrDefault(source.getId(), -1); + assertEquals(source.mSuggestionFlags, suggestionFlags); + } + } + + private HashMap<String, Integer> getExpectedResult() { + HashMap<String, Integer> map = new HashMap<>(); + map.put("en-US", CURRENT); // The locale current App activates. + map.put("fr", NONE); // The locale App and system support. + map.put("zu", NONE); // The locale App and system support. + map.put("en", NONE); // Use en because System supports en while APP supports en-CA, en-GB. + map.put("ko", NONE); // The locale App and system support. + map.put("en-AU", OTHERAPP); // The locale other App activates and current App supports. + map.put("en-CA", OTHERAPP); // The locale other App activates and current App supports. + map.put("ja-JP", OTHERAPP); // The locale other App activates and current App supports. + map.put("zh-Hant-TW", SIM); // The locale system activates. + map.put(createLocaleInfo("", SYSTEM).getId(), SYSTEM); // System language title + return map; + } + + private Set<LocaleInfo> initSystemSupportedLocales() { + return Set.of( + createLocaleInfo("en", NONE), + createLocaleInfo("fr", NONE), + createLocaleInfo("zu", NONE), + createLocaleInfo("ko", NONE), + // will be filtered because current App doesn't support. + createLocaleInfo("es-US", SIM_CFG) + ); + } + + private List<LocaleInfo> initSystemCurrentLocales() { + return List.of(createLocaleInfo("zh-Hant-TW", SIM), + // will be filtered because current App activates this locale. + createLocaleInfo("en-US", SIM)); + } + + private Set<LocaleInfo> initAllAppActivatedLocales() { + return Set.of( + createLocaleInfo("en-CA", OTHERAPP), + createLocaleInfo("en-AU", OTHERAPP), + createLocaleInfo("ja-JP", OTHERAPP), + // will be filtered because current App activates this locale. + createLocaleInfo("en-US", OTHERAPP)); + } + + private Set<LocaleInfo> initImeLocales() { + return Set.of( + // will be filtered because system activates zh-Hant-TW. + createLocaleInfo("zh-TW", OTHERAPP), + // will be filtered because current App's activats this locale. + createLocaleInfo("en-US", OTHERAPP)); + } + + private HashSet<Locale> initAppSupportedLocale() { + HashSet<Locale> hs = new HashSet(); + hs.add(Locale.forLanguageTag("en-US")); + hs.add(Locale.forLanguageTag("en-CA")); + hs.add(Locale.forLanguageTag("en-GB")); + hs.add(Locale.forLanguageTag("zh-TW")); + hs.add(Locale.forLanguageTag("ja")); + hs.add(Locale.forLanguageTag("fr")); + hs.add(Locale.forLanguageTag("zu")); + hs.add(Locale.forLanguageTag("ko")); + // will be filtered because it's not in the system language. + hs.add(Locale.forLanguageTag("mn")); + return hs; + } + + private LocaleInfo createLocaleInfo(String languageTag, int suggestionFlag) { + LocaleInfo localeInfo = LocaleStore.fromLocale(Locale.forLanguageTag(languageTag)); + localeInfo.mSuggestionFlags = suggestionFlag; + localeInfo.setTranslated(true); + return localeInfo; + } +} diff --git a/tests/Internal/src/com/android/internal/app/LocaleStoreTest.java b/tests/Internal/src/com/android/internal/app/LocaleStoreTest.java new file mode 100644 index 000000000000..bf6ece1ac19a --- /dev/null +++ b/tests/Internal/src/com/android/internal/app/LocaleStoreTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 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 com.android.internal.app; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.view.inputmethod.InputMethodSubtype; +import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; + +import androidx.test.filters.SmallTest; +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.List; +import java.util.Set; + +/** + * 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( + new InputMethodSubtypeBuilder().setLanguageTag("en-US").build(), + new InputMethodSubtypeBuilder().setLanguageTag("zh-TW").build(), + new InputMethodSubtypeBuilder().setLanguageTag("ja-JP").build()); + + Set<LocaleInfo> localeSet = LocaleStore.transformImeLanguageTagToLocaleInfo(list); + + Set<String> expectedLanguageTag = Set.of("en-US", "zh-TW", "ja-JP"); + assertEquals(localeSet.size(), expectedLanguageTag.size()); + for (LocaleInfo info : localeSet) { + assertEquals(info.mSuggestionFlags, LocaleInfo.SUGGESTION_TYPE_OTHER_APP_LANGUAGE); + assertTrue(expectedLanguageTag.contains(info.getId())); + } + } +} |