1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.app; 18 19 import static com.android.internal.app.AppLocaleStore.AppLocaleResult.LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.ArgumentMatchers.anyObject; 24 import static org.mockito.ArgumentMatchers.eq; 25 import static org.mockito.Mockito.doReturn; 26 import static org.mockito.Mockito.spy; 27 28 import android.os.LocaleList; 29 30 import androidx.test.InstrumentationRegistry; 31 import androidx.test.filters.SmallTest; 32 import androidx.test.runner.AndroidJUnit4; 33 34 import com.android.internal.app.LocaleStore.LocaleInfo; 35 36 import org.junit.Before; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.util.Collections; 41 import java.util.HashMap; 42 import java.util.HashSet; 43 import java.util.Locale; 44 import java.util.Set; 45 46 /** 47 * Unit tests for the {@link AppLocaleCollector}. 48 */ 49 @SmallTest 50 @RunWith(AndroidJUnit4.class) 51 public class AppLocaleCollectorTest { 52 private static final String TAG = "AppLocaleCollectorTest"; 53 private AppLocaleCollector mAppLocaleCollector; 54 private LocaleStore.LocaleInfo mAppCurrentLocale; 55 private Set<LocaleInfo> mAllAppActiveLocales; 56 private Set<LocaleInfo> mImeLocales; 57 private Set<LocaleInfo> mSystemCurrentLocales; 58 private Set<LocaleInfo> mSystemSupportedLocales; 59 private AppLocaleStore.AppLocaleResult mResult; 60 private static final String PKG1 = "pkg1"; 61 private static final int NONE = LocaleInfo.SUGGESTION_TYPE_NONE; 62 private static final int SIM = LocaleInfo.SUGGESTION_TYPE_SIM; 63 private static final int CFG = LocaleInfo.SUGGESTION_TYPE_CFG; 64 private static final int SIM_CFG = SIM | CFG; 65 private static final int CURRENT = LocaleInfo.SUGGESTION_TYPE_CURRENT; 66 private static final int SYSTEM = LocaleInfo.SUGGESTION_TYPE_SYSTEM_LANGUAGE; 67 private static final int OTHERAPP = LocaleInfo.SUGGESTION_TYPE_OTHER_APP_LANGUAGE; 68 private static final int IME = LocaleInfo.SUGGESTION_TYPE_IME_LANGUAGE; 69 private static final int SYSTEM_AVAILABLE = 70 LocaleInfo.SUGGESTION_TYPE_SYSTEM_AVAILABLE_LANGUAGE; 71 72 @Before setUp()73 public void setUp() throws Exception { 74 mAppLocaleCollector = spy( 75 new AppLocaleCollector(InstrumentationRegistry.getContext(), PKG1)); 76 } 77 78 @Test testGetSystemCurrentLocales()79 public void testGetSystemCurrentLocales() { 80 LocaleList.setDefault( 81 LocaleList.forLanguageTags("en-US-u-mu-fahrenhe,ar-JO-u-mu-fahrenhe-nu-latn")); 82 83 Set<LocaleStore.LocaleInfo> list = 84 mAppLocaleCollector.getSystemCurrentLocales(); 85 86 LocaleList expected = LocaleList.forLanguageTags("en-US,ar-JO-u-nu-latn"); 87 assertEquals(list.size(), expected.size()); 88 for (LocaleStore.LocaleInfo info : list) { 89 assertTrue(expected.indexOf(info.getLocale()) != -1); 90 } 91 } 92 93 @Test testGetSupportedLocaleList_filterNonAppsupportedSystemLanguage()94 public void testGetSupportedLocaleList_filterNonAppsupportedSystemLanguage() { 95 mAppCurrentLocale = createLocaleInfo("en-US", CURRENT); 96 97 // App supports five locales 98 HashSet<Locale> appSupported = 99 getAppSupportedLocales(new String[] { 100 "en-US", 101 "fr", 102 "ar", 103 "es", 104 "bn" 105 }); 106 // There are six locales in system current locales. 107 mSystemCurrentLocales = getSystemCurrentLocales(new String[] { 108 "en-US", 109 "fr-FR", 110 "ar-JO", 111 "ca-AD", 112 "da-DK", 113 "es-US" 114 }); 115 mAllAppActiveLocales = Collections.emptySet(); 116 mImeLocales = Collections.emptySet(); 117 mSystemSupportedLocales = Collections.emptySet(); 118 mResult = new AppLocaleStore.AppLocaleResult(GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG, 119 appSupported); 120 121 doReturn(mAppCurrentLocale).when(mAppLocaleCollector).getAppCurrentLocale(); 122 doReturn(mResult).when(mAppLocaleCollector).getAppSupportedLocales(); 123 doReturn(mAllAppActiveLocales).when(mAppLocaleCollector).getAllAppActiveLocales(); 124 doReturn(mImeLocales).when(mAppLocaleCollector).getActiveImeLocales(); 125 doReturn(mSystemSupportedLocales).when(mAppLocaleCollector).getSystemSupportedLocale( 126 anyObject(), eq(null), eq(true)); 127 doReturn(mSystemCurrentLocales).when( 128 mAppLocaleCollector).getSystemCurrentLocales(); 129 130 Set<LocaleInfo> result = mAppLocaleCollector.getSupportedLocaleList(null, true, false); 131 132 // The result would show four rather than six locales in the suggested region. 133 HashMap<String, Integer> expectedResult = new HashMap<>(); 134 expectedResult.put("en-US", CURRENT); // The locale current App activates. 135 expectedResult.put("ar-JO", SYSTEM_AVAILABLE); 136 expectedResult.put("fr-FR", SYSTEM_AVAILABLE); 137 expectedResult.put("es-US", SYSTEM_AVAILABLE); 138 expectedResult.put(createLocaleInfo("", SYSTEM).getId(), SYSTEM); // System language title 139 140 assertEquals(result.size(), expectedResult.size()); 141 for (LocaleStore.LocaleInfo info: result) { 142 int suggestionFlags = expectedResult.getOrDefault(info.getId(), -1); 143 assertEquals(info.mSuggestionFlags, suggestionFlags); 144 } 145 } 146 147 @Test testGetSupportedLocaleList_withActiveLocalesFromOtherAppAndIme()148 public void testGetSupportedLocaleList_withActiveLocalesFromOtherAppAndIme() { 149 mAppCurrentLocale = createLocaleInfo("en-US", CURRENT); 150 mAllAppActiveLocales = initAllAppActivatedLocales(); 151 mImeLocales = initImeLocales(); 152 mSystemSupportedLocales = initSystemSupportedLocales(); 153 mSystemCurrentLocales = initSystemCurrentLocales(); 154 mResult = new AppLocaleStore.AppLocaleResult(GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG, 155 initAppSupportedLocale()); 156 157 doReturn(mAppCurrentLocale).when(mAppLocaleCollector).getAppCurrentLocale(); 158 doReturn(mResult).when(mAppLocaleCollector).getAppSupportedLocales(); 159 doReturn(mAllAppActiveLocales).when(mAppLocaleCollector).getAllAppActiveLocales(); 160 doReturn(mImeLocales).when(mAppLocaleCollector).getActiveImeLocales(); 161 doReturn(mSystemSupportedLocales).when(mAppLocaleCollector).getSystemSupportedLocale( 162 anyObject(), eq(null), eq(true)); 163 doReturn(mSystemCurrentLocales).when( 164 mAppLocaleCollector).getSystemCurrentLocales(); 165 166 Set<LocaleInfo> result = mAppLocaleCollector.getSupportedLocaleList(null, true, false); 167 168 HashMap<String, Integer> expectedResult = getExpectedResult(); 169 assertEquals(result.size(), expectedResult.size()); 170 for (LocaleInfo source : result) { 171 int suggestionFlags = expectedResult.getOrDefault(source.getId(), -1); 172 assertEquals(source.mSuggestionFlags, suggestionFlags); 173 } 174 } 175 getExpectedResult()176 private HashMap<String, Integer> getExpectedResult() { 177 HashMap<String, Integer> map = new HashMap<>(); 178 map.put("en-US", CURRENT); // The locale current App activates. 179 map.put("fr", NONE); // The locale App and system support. 180 map.put("zu", NONE); // The locale App and system support. 181 map.put("en", NONE); // Use en because System supports en while APP supports en-CA, en-GB. 182 map.put("ko", NONE); // The locale App and system support. 183 map.put("en-AU", OTHERAPP); // The locale other App activates and current App supports. 184 map.put("en-CA", OTHERAPP); // The locale other App activates and current App supports. 185 map.put("en-IN", IME); // The locale IME supports. 186 map.put("ja-JP", 187 OTHERAPP | SYSTEM_AVAILABLE | IME); // The locale exists in OTHERAPP, SYSTEM and IME 188 map.put("zh-Hant-TW", SYSTEM_AVAILABLE); // The locale system activates. 189 map.put(createLocaleInfo("", SYSTEM).getId(), SYSTEM); // System language title 190 return map; 191 } 192 initSystemSupportedLocales()193 private Set<LocaleInfo> initSystemSupportedLocales() { 194 return Set.of( 195 createLocaleInfo("en", NONE), 196 createLocaleInfo("fr", NONE), 197 createLocaleInfo("zu", NONE), 198 createLocaleInfo("ko", NONE), 199 // will be filtered because current App doesn't support. 200 createLocaleInfo("es-US", SIM_CFG) 201 ); 202 } 203 initSystemCurrentLocales()204 private Set<LocaleInfo> initSystemCurrentLocales() { 205 return Set.of(createLocaleInfo("zh-Hant-TW", SYSTEM_AVAILABLE), 206 createLocaleInfo("ja-JP", SYSTEM_AVAILABLE), 207 // will be filtered because current App activates this locale. 208 createLocaleInfo("en-US", SYSTEM_AVAILABLE)); 209 } 210 initAllAppActivatedLocales()211 private Set<LocaleInfo> initAllAppActivatedLocales() { 212 return Set.of( 213 createLocaleInfo("en-CA", OTHERAPP), 214 createLocaleInfo("en-AU", OTHERAPP), 215 createLocaleInfo("ja-JP", OTHERAPP), 216 // will be filtered because current App activates this locale. 217 createLocaleInfo("en-US", OTHERAPP)); 218 } 219 initImeLocales()220 private Set<LocaleInfo> initImeLocales() { 221 return Set.of( 222 // will be filtered because system activates zh-Hant-TW. 223 createLocaleInfo("zh-TW", IME), 224 // will be filtered because current App's activats this locale. 225 createLocaleInfo("en-US", IME), 226 createLocaleInfo("ja-JP", IME), 227 createLocaleInfo("en-IN", IME)); 228 } 229 initAppSupportedLocale()230 private HashSet<Locale> initAppSupportedLocale() { 231 HashSet<Locale> hs = new HashSet(); 232 hs.add(Locale.forLanguageTag("en-US")); 233 hs.add(Locale.forLanguageTag("en-CA")); 234 hs.add(Locale.forLanguageTag("en-GB")); 235 hs.add(Locale.forLanguageTag("zh-TW")); 236 hs.add(Locale.forLanguageTag("ja")); 237 hs.add(Locale.forLanguageTag("fr")); 238 hs.add(Locale.forLanguageTag("zu")); 239 hs.add(Locale.forLanguageTag("ko")); 240 // will be filtered because it's not in the system language. 241 hs.add(Locale.forLanguageTag("mn")); 242 return hs; 243 } 244 getSystemCurrentLocales(String []languageTags)245 private Set<LocaleStore.LocaleInfo> getSystemCurrentLocales(String []languageTags) { 246 HashSet<LocaleStore.LocaleInfo> hs = new HashSet<>(languageTags.length); 247 for (String tag:languageTags) { 248 hs.add(createLocaleInfo(tag, SYSTEM_AVAILABLE)); 249 } 250 return hs; 251 } 252 getAppSupportedLocales(String []languageTags)253 private HashSet<Locale> getAppSupportedLocales(String []languageTags) { 254 HashSet<Locale> hs = new HashSet<>(languageTags.length); 255 for (String language:languageTags) { 256 hs.add(Locale.forLanguageTag(language)); 257 } 258 return hs; 259 } 260 createLocaleInfo(String languageTag, int suggestionFlag)261 private LocaleInfo createLocaleInfo(String languageTag, int suggestionFlag) { 262 LocaleInfo localeInfo = LocaleStore.fromLocale(Locale.forLanguageTag(languageTag)); 263 localeInfo.mSuggestionFlags = suggestionFlag; 264 localeInfo.setTranslated(true); 265 return localeInfo; 266 } 267 } 268