blob: 33cd328a6d806ebc5415fdbc75dd4c8c30ce241d [file] [log] [blame]
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09001/*
2 * Copyright (C) 2013 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
Yohei Yukawa35f74372015-08-12 20:14:08 -070017package com.android.internal.inputmethod;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090018
Yohei Yukawa8306fc42017-12-11 15:09:28 -080019import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.in;
21import static org.hamcrest.Matchers.not;
22import static org.hamcrest.core.Is.is;
23import static org.junit.Assert.assertEquals;
24import static org.junit.Assert.assertFalse;
25import static org.junit.Assert.assertNotNull;
26import static org.junit.Assert.assertTrue;
27
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090028import android.content.Context;
29import android.content.pm.ApplicationInfo;
30import android.content.pm.ResolveInfo;
31import android.content.pm.ServiceInfo;
Yohei Yukawa5d64399c2016-02-08 23:21:37 -080032import android.content.res.Configuration;
Yohei Yukawafc843712016-02-24 00:27:34 -080033import android.content.res.Resources;
Yohei Yukawa23cbe852016-05-17 16:42:58 -070034import android.os.LocaleList;
Yohei Yukawa35f74372015-08-12 20:14:08 -070035import android.os.Parcel;
Yohei Yukawa8306fc42017-12-11 15:09:28 -080036import android.support.test.InstrumentationRegistry;
37import android.support.test.filters.SmallTest;
38import android.support.test.runner.AndroidJUnit4;
Seigo Nonaka2028dda2015-07-06 17:41:24 +090039import android.util.ArrayMap;
40import android.util.ArraySet;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090041import android.view.inputmethod.InputMethodInfo;
Seigo Nonaka2028dda2015-07-06 17:41:24 +090042import android.view.inputmethod.InputMethodSubtype;
Yohei Yukawa8306fc42017-12-11 15:09:28 -080043import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
44
45import org.junit.Test;
46import org.junit.runner.RunWith;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090047
48import java.util.ArrayList;
49import java.util.List;
Yohei Yukawabca817b2014-09-11 16:59:31 +090050import java.util.Locale;
Yohei Yukawab21220e2014-11-01 21:04:30 +090051import java.util.Objects;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090052
Yohei Yukawa8306fc42017-12-11 15:09:28 -080053@SmallTest
54@RunWith(AndroidJUnit4.class)
55public class InputMethodUtilsTest {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090056 private static final boolean IS_AUX = true;
57 private static final boolean IS_DEFAULT = true;
Yohei Yukawae72d1c82015-02-20 20:55:21 +090058 private static final boolean IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE = true;
Yohei Yukawacfcbdda2014-09-10 17:53:51 +090059 private static final boolean IS_ASCII_CAPABLE = true;
Yohei Yukawae72d1c82015-02-20 20:55:21 +090060 private static final boolean IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE = true;
Yohei Yukawae72d1c82015-02-20 20:55:21 +090061 private static final Locale LOCALE_EN = new Locale("en");
Yohei Yukawabca817b2014-09-11 16:59:31 +090062 private static final Locale LOCALE_EN_US = new Locale("en", "US");
Yohei Yukawad77adfe2014-09-11 23:50:21 +090063 private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
64 private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
Yohei Yukawae72d1c82015-02-20 20:55:21 +090065 private static final Locale LOCALE_FI = new Locale("fi");
66 private static final Locale LOCALE_FI_FI = new Locale("fi", "FI");
67 private static final Locale LOCALE_FIL = new Locale("fil");
68 private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
69 private static final Locale LOCALE_FR = new Locale("fr");
70 private static final Locale LOCALE_FR_CA = new Locale("fr", "CA");
Yohei Yukawad77adfe2014-09-11 23:50:21 +090071 private static final Locale LOCALE_HI = new Locale("hi");
Yohei Yukawa174843a2015-06-26 18:02:54 -070072 private static final Locale LOCALE_JA = new Locale("ja");
Yohei Yukawa59cccf92014-09-12 23:21:54 +090073 private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
Yohei Yukawab21220e2014-11-01 21:04:30 +090074 private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN");
75 private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW");
Yohei Yukawae72d1c82015-02-20 20:55:21 +090076 private static final Locale LOCALE_IN = new Locale("in");
77 private static final Locale LOCALE_ID = new Locale("id");
Yohei Yukawa174843a2015-06-26 18:02:54 -070078 private static final Locale LOCALE_TH = new Locale("ht");
79 private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
80 private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
Yohei Yukawa59cccf92014-09-12 23:21:54 +090081 private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
82 private static final String SUBTYPE_MODE_VOICE = "voice";
Yohei Yukawa42275bc2016-03-03 00:34:27 -080083 private static final String SUBTYPE_MODE_HANDWRITING = "handwriting";
Yohei Yukawae72d1c82015-02-20 20:55:21 +090084 private static final String SUBTYPE_MODE_ANY = null;
85 private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
86 private static final String EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
87 private static final String EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE =
88 "EnabledWhenDefaultIsNotAsciiCapable";
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090089
Yohei Yukawa8306fc42017-12-11 15:09:28 -080090 @Test
Yohei Yukawa59cccf92014-09-12 23:21:54 +090091 public void testVoiceImes() throws Exception {
92 // locale: en_US
Yohei Yukawab21220e2014-11-01 21:04:30 +090093 assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -080094 "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
Yohei Yukawab21220e2014-11-01 21:04:30 +090095 assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -080096 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
Yohei Yukawab21220e2014-11-01 21:04:30 +090097 "DummyNonDefaultAutoVoiceIme1");
Yohei Yukawad77adfe2014-09-11 23:50:21 +090098
Yohei Yukawa59cccf92014-09-12 23:21:54 +090099 // locale: en_GB
Yohei Yukawab21220e2014-11-01 21:04:30 +0900100 assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800101 "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900102 assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800103 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900104 "DummyNonDefaultAutoVoiceIme1");
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900105
106 // locale: ja_JP
Yohei Yukawab21220e2014-11-01 21:04:30 +0900107 assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800108 "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900109 assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800110 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900111 "DummyNonDefaultAutoVoiceIme1");
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900112 }
113
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800114 @Test
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900115 public void testKeyboardImes() throws Exception {
116 // locale: en_US
Yohei Yukawab21220e2014-11-01 21:04:30 +0900117 assertDefaultEnabledImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800118 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Yohei Yukawabca817b2014-09-11 16:59:31 +0900119
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900120 // locale: en_GB
Yohei Yukawab21220e2014-11-01 21:04:30 +0900121 assertDefaultEnabledImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800122 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Yohei Yukawabca817b2014-09-11 16:59:31 +0900123
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900124 // locale: en_IN
Yohei Yukawab21220e2014-11-01 21:04:30 +0900125 assertDefaultEnabledImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800126 "com.android.apps.inputmethod.hindi",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900127 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Yohei Yukawad77adfe2014-09-11 23:50:21 +0900128
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900129 // locale: hi
Yohei Yukawab21220e2014-11-01 21:04:30 +0900130 assertDefaultEnabledImes(getSamplePreinstalledImes("hi"), LOCALE_HI,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800131 "com.android.apps.inputmethod.hindi", "com.android.apps.inputmethod.latin",
132 "com.android.apps.inputmethod.voice");
Yohei Yukawad77adfe2014-09-11 23:50:21 +0900133
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900134 // locale: ja_JP
Yohei Yukawab21220e2014-11-01 21:04:30 +0900135 assertDefaultEnabledImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800136 "com.android.apps.inputmethod.japanese", "com.android.apps.inputmethod.voice");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900137
138 // locale: zh_CN
139 assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800140 "com.android.apps.inputmethod.pinyin", "com.android.apps.inputmethod.voice");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900141
142 // locale: zh_TW
143 // Note: In this case, no IME is suitable for the system locale. Hence we will pick up a
144 // fallback IME regardless of the "default" attribute.
145 assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800146 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900147 }
148
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800149 @Test
Yohei Yukawa58980042014-02-27 17:10:00 +0900150 public void testParcelable() throws Exception {
Yohei Yukawab21220e2014-11-01 21:04:30 +0900151 final ArrayList<InputMethodInfo> originalList = getSamplePreinstalledImes("en-rUS");
Yohei Yukawa58980042014-02-27 17:10:00 +0900152 final List<InputMethodInfo> clonedList = cloneViaParcel(originalList);
153 assertNotNull(clonedList);
Yohei Yukawac18cd392014-03-03 13:08:34 +0900154 final List<InputMethodInfo> clonedClonedList = cloneViaParcel(clonedList);
155 assertNotNull(clonedClonedList);
Yohei Yukawa58980042014-02-27 17:10:00 +0900156 assertEquals(originalList, clonedList);
Yohei Yukawac18cd392014-03-03 13:08:34 +0900157 assertEquals(clonedList, clonedClonedList);
158 assertEquals(originalList.size(), clonedList.size());
159 assertEquals(clonedList.size(), clonedClonedList.size());
Yohei Yukawa58980042014-02-27 17:10:00 +0900160 for (int imeIndex = 0; imeIndex < originalList.size(); ++imeIndex) {
Yohei Yukawac18cd392014-03-03 13:08:34 +0900161 verifyEquality(originalList.get(imeIndex), clonedList.get(imeIndex));
162 verifyEquality(clonedList.get(imeIndex), clonedClonedList.get(imeIndex));
Yohei Yukawa58980042014-02-27 17:10:00 +0900163 }
164 }
165
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800166 @Test
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900167 public void testGetImplicitlyApplicableSubtypesLocked() throws Exception {
168 final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
169 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
170 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
171 final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
172 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
173 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawae985c242016-02-24 18:27:04 -0800174 final InputMethodSubtype nonAutoEnIN = createDummyInputMethodSubtype("en_IN",
175 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
176 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900177 final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA",
178 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
179 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
180 final InputMethodSubtype nonAutoFr = createDummyInputMethodSubtype("fr_CA",
181 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
182 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
183 final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
184 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
185 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
186 final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
187 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
188 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
189 final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
190 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
191 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
192 final InputMethodSubtype autoSubtype = createDummyInputMethodSubtype("auto",
193 SUBTYPE_MODE_KEYBOARD, !IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
194 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
195 final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja",
196 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
197 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800198 final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi",
199 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
200 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa238faad2016-03-11 10:39:51 -0800201 final InputMethodSubtype nonAutoSrCyrl = createDummyInputMethodSubtype("sr",
202 "sr-Cyrl", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
203 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
204 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
205 final InputMethodSubtype nonAutoSrLatn = createDummyInputMethodSubtype("sr_ZZ",
206 "sr-Latn", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
207 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
208 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800209 final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en",
210 SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
211 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800212 final InputMethodSubtype nonAutoHandwritingFr = createDummyInputMethodSubtype("fr",
213 SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
214 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa238faad2016-03-11 10:39:51 -0800215 final InputMethodSubtype nonAutoHandwritingSrCyrl = createDummyInputMethodSubtype("sr",
216 "sr-Cyrl", SUBTYPE_MODE_HANDWRITING, !IS_AUX,
217 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
218 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
219 final InputMethodSubtype nonAutoHandwritingSrLatn = createDummyInputMethodSubtype("sr_ZZ",
220 "sr-Latn", SUBTYPE_MODE_HANDWRITING, !IS_AUX,
221 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
222 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900223 final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype =
224 createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
225 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
226 IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
227 final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2 =
228 createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
229 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
230 IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
231
232 // Make sure that an automatic subtype (overridesImplicitlyEnabledSubtype:true) is
233 // selected no matter what locale is specified.
234 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800235 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900236 subtypes.add(nonAutoEnUS);
237 subtypes.add(nonAutoEnGB);
238 subtypes.add(nonAutoJa);
239 subtypes.add(nonAutoFil);
240 subtypes.add(autoSubtype); // overridesImplicitlyEnabledSubtype == true
241 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
242 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800243 subtypes.add(nonAutoHandwritingEn);
244 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900245 final InputMethodInfo imi = createDummyInputMethodInfo(
246 "com.android.apps.inputmethod.latin",
247 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
248 subtypes);
249 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800250 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800251 getResourcesForLocales(LOCALE_EN_US), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900252 assertEquals(1, result.size());
253 verifyEquality(autoSubtype, result.get(0));
254 }
255
256 // Make sure that a subtype whose locale is exactly equal to the specified locale is
257 // selected as long as there is no no automatic subtype
258 // (overridesImplicitlyEnabledSubtype:true) in the given list.
259 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800260 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900261 subtypes.add(nonAutoEnUS); // locale == "en_US"
262 subtypes.add(nonAutoEnGB);
263 subtypes.add(nonAutoJa);
264 subtypes.add(nonAutoFil);
265 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
266 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800267 subtypes.add(nonAutoHandwritingEn);
268 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900269 final InputMethodInfo imi = createDummyInputMethodInfo(
270 "com.android.apps.inputmethod.latin",
271 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
272 subtypes);
273 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800274 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800275 getResourcesForLocales(LOCALE_EN_US), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800276 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900277 verifyEquality(nonAutoEnUS, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800278 verifyEquality(nonAutoHandwritingEn, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900279 }
280
281 // Make sure that a subtype whose locale is exactly equal to the specified locale is
282 // selected as long as there is no automatic subtype
283 // (overridesImplicitlyEnabledSubtype:true) in the given list.
284 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800285 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900286 subtypes.add(nonAutoEnUS);
287 subtypes.add(nonAutoEnGB); // locale == "en_GB"
288 subtypes.add(nonAutoJa);
289 subtypes.add(nonAutoFil);
290 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800291 subtypes.add(nonAutoHandwritingEn);
292 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900293 final InputMethodInfo imi = createDummyInputMethodInfo(
294 "com.android.apps.inputmethod.latin",
295 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
296 subtypes);
297 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800298 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800299 getResourcesForLocales(LOCALE_EN_GB), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800300 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900301 verifyEquality(nonAutoEnGB, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800302 verifyEquality(nonAutoHandwritingEn, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900303 }
304
305 // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and
306 // any subtype whose locale is exactly equal to the specified locale in the given list,
307 // try to find a subtype whose language is equal to the language part of the given locale.
308 // Here make sure that a subtype (locale: "fr_CA") can be found with locale: "fr".
309 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800310 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900311 subtypes.add(nonAutoFrCA); // locale == "fr_CA"
312 subtypes.add(nonAutoJa);
313 subtypes.add(nonAutoFil);
314 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
315 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800316 subtypes.add(nonAutoHandwritingEn);
317 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900318 final InputMethodInfo imi = createDummyInputMethodInfo(
319 "com.android.apps.inputmethod.latin",
320 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
321 subtypes);
322 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800323 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800324 getResourcesForLocales(LOCALE_FR), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800325 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900326 verifyEquality(nonAutoFrCA, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800327 verifyEquality(nonAutoHandwritingFr, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900328 }
329 // Then make sure that a subtype (locale: "fr") can be found with locale: "fr_CA".
330 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800331 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900332 subtypes.add(nonAutoFr); // locale == "fr"
333 subtypes.add(nonAutoJa);
334 subtypes.add(nonAutoFil);
335 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
336 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800337 subtypes.add(nonAutoHandwritingEn);
338 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900339 final InputMethodInfo imi = createDummyInputMethodInfo(
340 "com.android.apps.inputmethod.latin",
341 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
342 subtypes);
343 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800344 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800345 getResourcesForLocales(LOCALE_FR_CA), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800346 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900347 verifyEquality(nonAutoFrCA, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800348 verifyEquality(nonAutoHandwritingFr, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900349 }
350
351 // Make sure that subtypes which have "EnabledWhenDefaultIsNotAsciiCapable" in its
352 // extra value is selected if and only if all other selected IMEs are not AsciiCapable.
353 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800354 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900355 subtypes.add(nonAutoEnUS);
356 subtypes.add(nonAutoJa); // not ASCII capable
357 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
358 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800359 subtypes.add(nonAutoHandwritingEn);
360 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900361 final InputMethodInfo imi = createDummyInputMethodInfo(
362 "com.android.apps.inputmethod.latin",
363 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
364 subtypes);
365 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800366 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800367 getResourcesForLocales(LOCALE_JA_JP), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900368 assertEquals(3, result.size());
369 verifyEquality(nonAutoJa, result.get(0));
370 verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, result.get(1));
371 verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2, result.get(2));
372 }
373
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800374 // Make sure that if there is no subtype that matches the language requested, then we just
375 // use the first keyboard subtype.
376 {
377 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
378 subtypes.add(nonAutoHi);
379 subtypes.add(nonAutoEnUS);
380 subtypes.add(nonAutoHandwritingEn);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800381 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800382 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
383 final InputMethodInfo imi = createDummyInputMethodInfo(
384 "com.android.apps.inputmethod.latin",
385 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
386 subtypes);
387 final ArrayList<InputMethodSubtype> result =
388 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
389 getResourcesForLocales(LOCALE_JA_JP), imi);
390 assertEquals(1, result.size());
391 verifyEquality(nonAutoHi, result.get(0));
392 }
393 {
394 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
395 subtypes.add(nonAutoEnUS);
396 subtypes.add(nonAutoHi);
397 subtypes.add(nonAutoHandwritingEn);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800398 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800399 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
400 final InputMethodInfo imi = createDummyInputMethodInfo(
401 "com.android.apps.inputmethod.latin",
402 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
403 subtypes);
404 final ArrayList<InputMethodSubtype> result =
405 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
406 getResourcesForLocales(LOCALE_JA_JP), imi);
407 assertEquals(1, result.size());
408 verifyEquality(nonAutoEnUS, result.get(0));
409 }
410 {
411 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
412 subtypes.add(nonAutoHandwritingEn);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800413 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800414 subtypes.add(nonAutoEnUS);
415 subtypes.add(nonAutoHi);
416 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
417 final InputMethodInfo imi = createDummyInputMethodInfo(
418 "com.android.apps.inputmethod.latin",
419 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
420 subtypes);
421 final ArrayList<InputMethodSubtype> result =
422 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
423 getResourcesForLocales(LOCALE_JA_JP), imi);
424 assertEquals(1, result.size());
425 verifyEquality(nonAutoEnUS, result.get(0));
426 }
427
Yohei Yukawa238faad2016-03-11 10:39:51 -0800428 // Make sure that both language and script are taken into account to find the best matching
429 // subtype.
430 {
431 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
432 subtypes.add(nonAutoEnUS);
433 subtypes.add(nonAutoSrCyrl);
434 subtypes.add(nonAutoSrLatn);
435 subtypes.add(nonAutoHandwritingEn);
436 subtypes.add(nonAutoHandwritingFr);
437 subtypes.add(nonAutoHandwritingSrCyrl);
438 subtypes.add(nonAutoHandwritingSrLatn);
439 final InputMethodInfo imi = createDummyInputMethodInfo(
440 "com.android.apps.inputmethod.latin",
441 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
442 subtypes);
443 final ArrayList<InputMethodSubtype> result =
444 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
445 getResourcesForLocales(Locale.forLanguageTag("sr-Latn-RS")), imi);
446 assertEquals(2, result.size());
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800447 assertThat(nonAutoSrLatn, is(in(result)));
448 assertThat(nonAutoHandwritingSrLatn, is(in(result)));
Yohei Yukawa238faad2016-03-11 10:39:51 -0800449 }
450 {
451 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
452 subtypes.add(nonAutoEnUS);
453 subtypes.add(nonAutoSrCyrl);
454 subtypes.add(nonAutoSrLatn);
455 subtypes.add(nonAutoHandwritingEn);
456 subtypes.add(nonAutoHandwritingFr);
457 subtypes.add(nonAutoHandwritingSrCyrl);
458 subtypes.add(nonAutoHandwritingSrLatn);
459 final InputMethodInfo imi = createDummyInputMethodInfo(
460 "com.android.apps.inputmethod.latin",
461 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
462 subtypes);
463 final ArrayList<InputMethodSubtype> result =
464 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
465 getResourcesForLocales(Locale.forLanguageTag("sr-Cyrl-RS")), imi);
466 assertEquals(2, result.size());
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800467 assertThat(nonAutoSrCyrl, is(in(result)));
468 assertThat(nonAutoHandwritingSrCyrl, is(in(result)));
Yohei Yukawa238faad2016-03-11 10:39:51 -0800469 }
470
471 // Make sure that secondary locales are taken into account to find the best matching
472 // subtype.
473 {
474 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
475 subtypes.add(nonAutoEnUS);
476 subtypes.add(nonAutoEnGB);
477 subtypes.add(nonAutoSrCyrl);
478 subtypes.add(nonAutoSrLatn);
479 subtypes.add(nonAutoFr);
480 subtypes.add(nonAutoFrCA);
481 subtypes.add(nonAutoHandwritingEn);
482 subtypes.add(nonAutoHandwritingFr);
483 subtypes.add(nonAutoHandwritingSrCyrl);
484 subtypes.add(nonAutoHandwritingSrLatn);
485 final InputMethodInfo imi = createDummyInputMethodInfo(
486 "com.android.apps.inputmethod.latin",
487 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
488 subtypes);
489 final ArrayList<InputMethodSubtype> result =
490 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
491 getResourcesForLocales(
492 Locale.forLanguageTag("sr-Latn-RS-x-android"),
493 Locale.forLanguageTag("ja-JP"),
494 Locale.forLanguageTag("fr-FR"),
495 Locale.forLanguageTag("en-GB"),
496 Locale.forLanguageTag("en-US")),
497 imi);
498 assertEquals(6, result.size());
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800499 assertThat(nonAutoEnGB, is(in(result)));
500 assertThat(nonAutoFr, is(in(result)));
501 assertThat(nonAutoSrLatn, is(in(result)));
502 assertThat(nonAutoHandwritingEn, is(in(result)));
503 assertThat(nonAutoHandwritingFr, is(in(result)));
504 assertThat(nonAutoHandwritingSrLatn, is(in(result)));
Yohei Yukawa238faad2016-03-11 10:39:51 -0800505 }
506
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900507 // Make sure that 3-letter language code can be handled.
508 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800509 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900510 subtypes.add(nonAutoEnUS);
511 subtypes.add(nonAutoFil);
512 final InputMethodInfo imi = createDummyInputMethodInfo(
513 "com.android.apps.inputmethod.latin",
514 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
515 subtypes);
516 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800517 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800518 getResourcesForLocales(LOCALE_FIL_PH), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900519 assertEquals(1, result.size());
520 verifyEquality(nonAutoFil, result.get(0));
521 }
522
523 // Make sure that we never end up matching "fi" (finnish) with "fil" (filipino).
524 // Also make sure that the first subtype will be used as the last-resort candidate.
525 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800526 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900527 subtypes.add(nonAutoJa);
528 subtypes.add(nonAutoEnUS);
529 subtypes.add(nonAutoFil);
530 final InputMethodInfo imi = createDummyInputMethodInfo(
531 "com.android.apps.inputmethod.latin",
532 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
533 subtypes);
534 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800535 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800536 getResourcesForLocales(LOCALE_FI), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900537 assertEquals(1, result.size());
538 verifyEquality(nonAutoJa, result.get(0));
539 }
540
541 // Make sure that "in" and "id" conversion is taken into account.
542 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800543 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900544 subtypes.add(nonAutoIn);
545 subtypes.add(nonAutoEnUS);
546 final InputMethodInfo imi = createDummyInputMethodInfo(
547 "com.android.apps.inputmethod.latin",
548 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
549 subtypes);
550 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800551 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800552 getResourcesForLocales(LOCALE_IN), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900553 assertEquals(1, result.size());
554 verifyEquality(nonAutoIn, result.get(0));
555 }
556 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800557 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900558 subtypes.add(nonAutoIn);
559 subtypes.add(nonAutoEnUS);
560 final InputMethodInfo imi = createDummyInputMethodInfo(
561 "com.android.apps.inputmethod.latin",
562 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
563 subtypes);
564 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800565 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800566 getResourcesForLocales(LOCALE_ID), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900567 assertEquals(1, result.size());
568 verifyEquality(nonAutoIn, result.get(0));
569 }
570 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800571 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900572 subtypes.add(nonAutoId);
573 subtypes.add(nonAutoEnUS);
574 final InputMethodInfo imi = createDummyInputMethodInfo(
575 "com.android.apps.inputmethod.latin",
576 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
577 subtypes);
578 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800579 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800580 getResourcesForLocales(LOCALE_IN), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900581 assertEquals(1, result.size());
582 verifyEquality(nonAutoId, result.get(0));
583 }
584 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800585 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900586 subtypes.add(nonAutoId);
587 subtypes.add(nonAutoEnUS);
588 final InputMethodInfo imi = createDummyInputMethodInfo(
589 "com.android.apps.inputmethod.latin",
590 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
591 subtypes);
592 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800593 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800594 getResourcesForLocales(LOCALE_ID), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900595 assertEquals(1, result.size());
596 verifyEquality(nonAutoId, result.get(0));
597 }
Yohei Yukawae985c242016-02-24 18:27:04 -0800598
599 // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and the system
600 // provides multiple locales, we try to enable multiple subtypes.
601 {
602 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
603 subtypes.add(nonAutoEnUS);
604 subtypes.add(nonAutoFrCA);
605 subtypes.add(nonAutoIn);
606 subtypes.add(nonAutoJa);
607 subtypes.add(nonAutoFil);
608 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
609 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
610 final InputMethodInfo imi = createDummyInputMethodInfo(
611 "com.android.apps.inputmethod.latin",
612 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
613 subtypes);
614 final ArrayList<InputMethodSubtype> result =
615 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
616 getResourcesForLocales(LOCALE_FR, LOCALE_EN_US, LOCALE_JA_JP), imi);
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800617 assertThat(nonAutoFrCA, is(in(result)));
618 assertThat(nonAutoEnUS, is(in(result)));
619 assertThat(nonAutoJa, is(in(result)));
620 assertThat(nonAutoIn, not(is(in(result))));
621 assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(is(in(result))));
622 assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(is(in(result))));
Yohei Yukawae985c242016-02-24 18:27:04 -0800623 }
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900624 }
625
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800626 @Test
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900627 public void testContainsSubtypeOf() throws Exception {
628 final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
629 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
630 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
631 final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
632 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
633 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
634 final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
635 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
636 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
637 final InputMethodSubtype nonAutoFilPH = createDummyInputMethodSubtype("fil_PH",
638 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
639 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
640 final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
641 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
642 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
643 final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
644 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
645 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
646
647 final boolean CHECK_COUNTRY = true;
648
649 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800650 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900651 subtypes.add(nonAutoEnUS);
652 final InputMethodInfo imi = createDummyInputMethodInfo(
653 "com.android.apps.inputmethod.latin",
654 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
655 subtypes);
656
657 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY,
658 SUBTYPE_MODE_KEYBOARD));
659 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, CHECK_COUNTRY,
660 SUBTYPE_MODE_KEYBOARD));
661 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
662 SUBTYPE_MODE_KEYBOARD));
663 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
664 SUBTYPE_MODE_KEYBOARD));
665 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
666 SUBTYPE_MODE_VOICE));
667 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
668 SUBTYPE_MODE_VOICE));
669 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
670 SUBTYPE_MODE_ANY));
671 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
672 SUBTYPE_MODE_ANY));
673
674 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, !CHECK_COUNTRY,
675 SUBTYPE_MODE_KEYBOARD));
676 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, CHECK_COUNTRY,
677 SUBTYPE_MODE_KEYBOARD));
678 }
679
680 // Make sure that 3-letter language code ("fil") can be handled.
681 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800682 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900683 subtypes.add(nonAutoFil);
684 final InputMethodInfo imi = createDummyInputMethodInfo(
685 "com.android.apps.inputmethod.latin",
686 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
687 subtypes);
688 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
689 SUBTYPE_MODE_KEYBOARD));
690 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
691 SUBTYPE_MODE_KEYBOARD));
692 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
693 SUBTYPE_MODE_KEYBOARD));
694 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
695 SUBTYPE_MODE_KEYBOARD));
696
697 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
698 SUBTYPE_MODE_KEYBOARD));
699 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
700 SUBTYPE_MODE_KEYBOARD));
701 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
702 SUBTYPE_MODE_KEYBOARD));
703 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
704 SUBTYPE_MODE_KEYBOARD));
705 }
706
707 // Make sure that 3-letter language code ("fil_PH") can be handled.
708 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800709 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900710 subtypes.add(nonAutoFilPH);
711 final InputMethodInfo imi = createDummyInputMethodInfo(
712 "com.android.apps.inputmethod.latin",
713 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
714 subtypes);
715 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
716 SUBTYPE_MODE_KEYBOARD));
717 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
718 SUBTYPE_MODE_KEYBOARD));
719 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
720 SUBTYPE_MODE_KEYBOARD));
721 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
722 SUBTYPE_MODE_KEYBOARD));
723
724 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
725 SUBTYPE_MODE_KEYBOARD));
726 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
727 SUBTYPE_MODE_KEYBOARD));
728 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
729 SUBTYPE_MODE_KEYBOARD));
730 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
731 SUBTYPE_MODE_KEYBOARD));
732 }
733
734 // Make sure that a subtype whose locale is "in" can be queried with "id".
735 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800736 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900737 subtypes.add(nonAutoIn);
738 subtypes.add(nonAutoEnUS);
739 final InputMethodInfo imi = createDummyInputMethodInfo(
740 "com.android.apps.inputmethod.latin",
741 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
742 subtypes);
743 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
744 SUBTYPE_MODE_KEYBOARD));
745 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
746 SUBTYPE_MODE_KEYBOARD));
747 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
748 SUBTYPE_MODE_KEYBOARD));
749 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
750 SUBTYPE_MODE_KEYBOARD));
751 }
752
753 // Make sure that a subtype whose locale is "id" can be queried with "in".
754 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800755 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900756 subtypes.add(nonAutoId);
757 subtypes.add(nonAutoEnUS);
758 final InputMethodInfo imi = createDummyInputMethodInfo(
759 "com.android.apps.inputmethod.latin",
760 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
761 subtypes);
762 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
763 SUBTYPE_MODE_KEYBOARD));
Yohei Yukawaf487e0e2015-02-21 02:15:48 +0900764 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900765 SUBTYPE_MODE_KEYBOARD));
766 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
767 SUBTYPE_MODE_KEYBOARD));
Yohei Yukawaf487e0e2015-02-21 02:15:48 +0900768 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900769 SUBTYPE_MODE_KEYBOARD));
770 }
771 }
772
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900773 private void assertDefaultEnabledImes(final ArrayList<InputMethodInfo> preinstalledImes,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800774 final Locale systemLocale, String... expectedImeNames) {
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800775 final Context context = createTargetContextWithLocales(new LocaleList(systemLocale));
776 final String[] actualImeNames = getPackageNames(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800777 InputMethodUtils.getDefaultEnabledImes(context, preinstalledImes));
Yohei Yukawab21220e2014-11-01 21:04:30 +0900778 assertEquals(expectedImeNames.length, actualImeNames.length);
779 for (int i = 0; i < expectedImeNames.length; ++i) {
780 assertEquals(expectedImeNames[i], actualImeNames[i]);
781 }
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900782 }
783
Yohei Yukawa58980042014-02-27 17:10:00 +0900784 private static List<InputMethodInfo> cloneViaParcel(final List<InputMethodInfo> list) {
785 Parcel p = null;
786 try {
787 p = Parcel.obtain();
788 p.writeTypedList(list);
789 p.setDataPosition(0);
790 return p.createTypedArrayList(InputMethodInfo.CREATOR);
791 } finally {
792 if (p != null) {
793 p.recycle();
794 }
795 }
796 }
797
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800798 private Context createTargetContextWithLocales(final LocaleList locales) {
799 final Configuration resourceConfiguration = new Configuration();
800 resourceConfiguration.setLocales(locales);
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800801 return InstrumentationRegistry.getInstrumentation()
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800802 .getTargetContext()
803 .createConfigurationContext(resourceConfiguration);
Yohei Yukawabca817b2014-09-11 16:59:31 +0900804 }
805
Yohei Yukawafc843712016-02-24 00:27:34 -0800806 private Resources getResourcesForLocales(Locale... locales) {
807 return createTargetContextWithLocales(new LocaleList(locales)).getResources();
808 }
809
Yohei Yukawab21220e2014-11-01 21:04:30 +0900810 private String[] getPackageNames(final ArrayList<InputMethodInfo> imis) {
811 final String[] packageNames = new String[imis.size()];
812 for (int i = 0; i < imis.size(); ++i) {
813 packageNames[i] = imis.get(i).getPackageName();
Yohei Yukawabca817b2014-09-11 16:59:31 +0900814 }
815 return packageNames;
816 }
817
Yohei Yukawac18cd392014-03-03 13:08:34 +0900818 private static void verifyEquality(InputMethodInfo expected, InputMethodInfo actual) {
819 assertEquals(expected, actual);
820 assertEquals(expected.getSubtypeCount(), actual.getSubtypeCount());
821 for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) {
822 final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex);
823 final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900824 verifyEquality(expectedSubtype, actualSubtype);
Yohei Yukawac18cd392014-03-03 13:08:34 +0900825 }
826 }
827
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900828 private static void verifyEquality(InputMethodSubtype expected, InputMethodSubtype actual) {
829 assertEquals(expected, actual);
830 assertEquals(expected.hashCode(), actual.hashCode());
831 }
832
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900833 private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
834 CharSequence label, boolean isAuxIme, boolean isDefault,
835 List<InputMethodSubtype> subtypes) {
836 final ResolveInfo ri = new ResolveInfo();
837 final ServiceInfo si = new ServiceInfo();
838 final ApplicationInfo ai = new ApplicationInfo();
839 ai.packageName = packageName;
840 ai.enabled = true;
841 ai.flags |= ApplicationInfo.FLAG_SYSTEM;
842 si.applicationInfo = ai;
843 si.enabled = true;
844 si.packageName = packageName;
845 si.name = name;
846 si.exported = true;
847 si.nonLocalizedLabel = label;
848 ri.serviceInfo = si;
849 return new InputMethodInfo(ri, isAuxIme, "", subtypes, 1, isDefault);
850 }
851
852 private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
Yohei Yukawacfcbdda2014-09-10 17:53:51 +0900853 boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900854 boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) {
Yohei Yukawa238faad2016-03-11 10:39:51 -0800855 return createDummyInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary,
856 overridesImplicitlyEnabledSubtype, isAsciiCapable,
857 isEnabledWhenDefaultIsNotAsciiCapable);
858 }
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900859
Yohei Yukawa238faad2016-03-11 10:39:51 -0800860 private static InputMethodSubtype createDummyInputMethodSubtype(String locale,
861 String languageTag, String mode, boolean isAuxiliary,
862 boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable,
863 boolean isEnabledWhenDefaultIsNotAsciiCapable) {
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900864 final StringBuilder subtypeExtraValue = new StringBuilder();
865 if (isEnabledWhenDefaultIsNotAsciiCapable) {
866 subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
867 subtypeExtraValue.append(EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
868 }
869
870 // TODO: Remove following code. InputMethodSubtype#isAsciiCapable() has been publicly
871 // available since API level 19 (KitKat). We no longer need to rely on extra value.
872 if (isAsciiCapable) {
873 subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
874 subtypeExtraValue.append(EXTRA_VALUE_ASCII_CAPABLE);
875 }
876
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900877 return new InputMethodSubtypeBuilder()
878 .setSubtypeNameResId(0)
879 .setSubtypeIconResId(0)
880 .setSubtypeLocale(locale)
Yohei Yukawa238faad2016-03-11 10:39:51 -0800881 .setLanguageTag(languageTag)
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900882 .setSubtypeMode(mode)
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900883 .setSubtypeExtraValue(subtypeExtraValue.toString())
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900884 .setIsAuxiliary(isAuxiliary)
885 .setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype)
Yohei Yukawacfcbdda2014-09-10 17:53:51 +0900886 .setIsAsciiCapable(isAsciiCapable)
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900887 .build();
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900888 }
889
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900890 private static ArrayList<InputMethodInfo> getImesWithDefaultVoiceIme() {
891 ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
892 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800893 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900894 subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
895 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
896 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900897 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900898 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
899 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900900 preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultAutoVoiceIme",
901 "dummy.voice0", "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes));
902 }
903 preinstalledImes.addAll(getImesWithoutDefaultVoiceIme());
904 return preinstalledImes;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900905 }
906
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900907 private static ArrayList<InputMethodInfo> getImesWithoutDefaultVoiceIme() {
908 ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
909 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800910 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900911 subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
912 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
913 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900914 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900915 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
916 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900917 preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0",
918 "dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes));
919 }
920 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800921 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900922 subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
923 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
924 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900925 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900926 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
927 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900928 preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1",
929 "dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes));
930 }
931 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800932 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900933 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900934 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
935 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900936 preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultVoiceIme2",
937 "dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes));
938 }
939 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800940 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900941 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900942 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
943 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900944 preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultEnKeyboardIme",
945 "dummy.keyboard0", "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes));
946 }
947 return preinstalledImes;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900948 }
949
Yohei Yukawab21220e2014-11-01 21:04:30 +0900950 private static boolean contains(final String[] textList, final String textToBeChecked) {
951 if (textList == null) {
952 return false;
953 }
954 for (final String text : textList) {
955 if (Objects.equals(textToBeChecked, text)) {
956 return true;
957 }
958 }
959 return false;
960 }
961
962 private static ArrayList<InputMethodInfo> getSamplePreinstalledImes(final String localeString) {
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900963 ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900964
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900965 // a dummy Voice IME
966 {
Yohei Yukawab21220e2014-11-01 21:04:30 +0900967 final boolean isDefaultIme = false;
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800968 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900969 subtypes.add(createDummyInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900970 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
971 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900972 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.voice",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900973 "com.android.inputmethod.voice", "DummyVoiceIme", IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900974 subtypes));
975 }
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900976 // a dummy Hindi IME
977 {
Yohei Yukawab21220e2014-11-01 21:04:30 +0900978 final boolean isDefaultIme = contains(new String[]{ "hi", "en-rIN" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800979 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900980 // TODO: This subtype should be marked as IS_ASCII_CAPABLE
981 subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900982 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
983 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900984 subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900985 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
986 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900987 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.hindi",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900988 "com.android.inputmethod.hindi", "DummyHindiIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900989 subtypes));
990 }
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900991
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900992 // a dummy Pinyin IME
993 {
Yohei Yukawab21220e2014-11-01 21:04:30 +0900994 final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800995 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900996 subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900997 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
998 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawab21220e2014-11-01 21:04:30 +0900999 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.pinyin",
1000 "com.android.apps.inputmethod.pinyin", "DummyPinyinIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001001 subtypes));
1002 }
Yohei Yukawa58980042014-02-27 17:10:00 +09001003
Yohei Yukawab21220e2014-11-01 21:04:30 +09001004 // a dummy Korean IME
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001005 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001006 final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001007 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001008 subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001009 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1010 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001011 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.korean",
Yohei Yukawab21220e2014-11-01 21:04:30 +09001012 "com.android.apps.inputmethod.korean", "DummyKoreanIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001013 subtypes));
1014 }
Yohei Yukawad77adfe2014-09-11 23:50:21 +09001015
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001016 // a dummy Latin IME
1017 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001018 final boolean isDefaultIme = contains(
1019 new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001020 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001021 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001022 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1023 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001024 subtypes.add(createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001025 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1026 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001027 subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001028 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1029 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001030 subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001031 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1032 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001033 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.latin",
Yohei Yukawab21220e2014-11-01 21:04:30 +09001034 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001035 subtypes));
1036 }
1037
1038 // a dummy Japanese IME
1039 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001040 final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001041 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001042 subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001043 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1044 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001045 subtypes.add(createDummyInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001046 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1047 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001048 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.japanese",
1049 "com.android.apps.inputmethod.japanese", "DummyJapaneseIme", !IS_AUX,
Yohei Yukawab21220e2014-11-01 21:04:30 +09001050 isDefaultIme, subtypes));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001051 }
1052
1053 return preinstalledImes;
Yohei Yukawad77adfe2014-09-11 23:50:21 +09001054 }
Yohei Yukawa174843a2015-06-26 18:02:54 -07001055
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001056 @Test
Yohei Yukawa174843a2015-06-26 18:02:54 -07001057 public void testGetSuitableLocalesForSpellChecker() throws Exception {
1058 {
1059 final ArrayList<Locale> locales =
1060 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US);
1061 assertEquals(3, locales.size());
1062 assertEquals(LOCALE_EN_US, locales.get(0));
1063 assertEquals(LOCALE_EN_GB, locales.get(1));
1064 assertEquals(LOCALE_EN, locales.get(2));
1065 }
1066
1067 {
1068 final ArrayList<Locale> locales =
1069 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB);
1070 assertEquals(3, locales.size());
1071 assertEquals(LOCALE_EN_GB, locales.get(0));
1072 assertEquals(LOCALE_EN_US, locales.get(1));
1073 assertEquals(LOCALE_EN, locales.get(2));
1074 }
1075
1076 {
1077 final ArrayList<Locale> locales =
1078 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN);
1079 assertEquals(3, locales.size());
1080 assertEquals(LOCALE_EN, locales.get(0));
1081 assertEquals(LOCALE_EN_US, locales.get(1));
1082 assertEquals(LOCALE_EN_GB, locales.get(2));
1083 }
1084
1085 {
1086 final ArrayList<Locale> locales =
1087 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN);
1088 assertEquals(4, locales.size());
1089 assertEquals(LOCALE_EN_IN, locales.get(0));
1090 assertEquals(LOCALE_EN_US, locales.get(1));
1091 assertEquals(LOCALE_EN_GB, locales.get(2));
1092 assertEquals(LOCALE_EN, locales.get(3));
1093 }
1094
1095 {
1096 final ArrayList<Locale> locales =
1097 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP);
1098 assertEquals(5, locales.size());
1099 assertEquals(LOCALE_JA_JP, locales.get(0));
1100 assertEquals(LOCALE_JA, locales.get(1));
1101 assertEquals(LOCALE_EN_US, locales.get(2));
1102 assertEquals(LOCALE_EN_GB, locales.get(3));
1103 assertEquals(Locale.ENGLISH, locales.get(4));
1104 }
1105
1106 // Test 3-letter language code.
1107 {
1108 final ArrayList<Locale> locales =
1109 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH);
1110 assertEquals(5, locales.size());
1111 assertEquals(LOCALE_FIL_PH, locales.get(0));
1112 assertEquals(LOCALE_FIL, locales.get(1));
1113 assertEquals(LOCALE_EN_US, locales.get(2));
1114 assertEquals(LOCALE_EN_GB, locales.get(3));
1115 assertEquals(Locale.ENGLISH, locales.get(4));
1116 }
1117
1118 // Test variant.
1119 {
1120 final ArrayList<Locale> locales =
1121 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH);
1122 assertEquals(6, locales.size());
1123 assertEquals(LOCALE_TH_TH_TH, locales.get(0));
1124 assertEquals(LOCALE_TH_TH, locales.get(1));
1125 assertEquals(LOCALE_TH, locales.get(2));
1126 assertEquals(LOCALE_EN_US, locales.get(3));
1127 assertEquals(LOCALE_EN_GB, locales.get(4));
1128 assertEquals(Locale.ENGLISH, locales.get(5));
1129 }
1130
1131 // Test Locale extension.
1132 {
1133 final Locale localeWithoutVariant = LOCALE_JA_JP;
1134 final Locale localeWithVariant = new Locale.Builder()
1135 .setLocale(LOCALE_JA_JP)
1136 .setExtension('x', "android")
1137 .build();
1138 assertFalse(localeWithoutVariant.equals(localeWithVariant));
1139
1140 final ArrayList<Locale> locales =
1141 InputMethodUtils.getSuitableLocalesForSpellChecker(localeWithVariant);
1142 assertEquals(5, locales.size());
1143 assertEquals(LOCALE_JA_JP, locales.get(0));
1144 assertEquals(LOCALE_JA, locales.get(1));
1145 assertEquals(LOCALE_EN_US, locales.get(2));
1146 assertEquals(LOCALE_EN_GB, locales.get(3));
1147 assertEquals(Locale.ENGLISH, locales.get(4));
1148 }
1149 }
Seigo Nonaka2028dda2015-07-06 17:41:24 +09001150
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001151 @Test
Seigo Nonaka2028dda2015-07-06 17:41:24 +09001152 public void testParseInputMethodsAndSubtypesString() {
1153 // Trivial cases.
1154 {
1155 assertTrue(InputMethodUtils.parseInputMethodsAndSubtypesString("").isEmpty());
1156 assertTrue(InputMethodUtils.parseInputMethodsAndSubtypesString(null).isEmpty());
1157 }
1158
1159 // No subtype cases.
1160 {
1161 ArrayMap<String, ArraySet<String>> r =
1162 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0");
1163 assertEquals(1, r.size());
1164 assertTrue(r.containsKey("ime0"));
1165 assertTrue(r.get("ime0").isEmpty());
1166 }
1167 {
1168 ArrayMap<String, ArraySet<String>> r =
1169 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0:ime1");
1170 assertEquals(2, r.size());
1171 assertTrue(r.containsKey("ime0"));
1172 assertTrue(r.get("ime0").isEmpty());
1173 assertTrue(r.containsKey("ime1"));
1174 assertTrue(r.get("ime1").isEmpty());
1175 }
1176
1177 // Input metho IDs and their subtypes.
1178 {
1179 ArrayMap<String, ArraySet<String>> r =
1180 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0");
1181 assertEquals(1, r.size());
1182 assertTrue(r.containsKey("ime0"));
1183 ArraySet<String> subtypes = r.get("ime0");
1184 assertEquals(1, subtypes.size());
1185 assertTrue(subtypes.contains("subtype0"));
1186 }
1187 {
1188 ArrayMap<String, ArraySet<String>> r =
1189 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0;subtype0");
1190 assertEquals(1, r.size());
1191 assertTrue(r.containsKey("ime0"));
1192 ArraySet<String> subtypes = r.get("ime0");
1193 assertEquals(1, subtypes.size());
1194 assertTrue(subtypes.contains("subtype0"));
1195 }
1196 {
1197 ArrayMap<String, ArraySet<String>> r =
1198 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0;subtype1");
1199 assertEquals(1, r.size());
1200 assertTrue(r.containsKey("ime0"));
1201 ArraySet<String> subtypes = r.get("ime0");
1202 assertEquals(2, subtypes.size());
1203 assertTrue(subtypes.contains("subtype0"));
1204 assertTrue(subtypes.contains("subtype1"));
1205 }
1206 {
1207 ArrayMap<String, ArraySet<String>> r =
1208 InputMethodUtils.parseInputMethodsAndSubtypesString(
1209 "ime0;subtype0:ime1;subtype1");
1210 assertEquals(2, r.size());
1211 assertTrue(r.containsKey("ime0"));
1212 assertTrue(r.containsKey("ime1"));
1213 ArraySet<String> subtypes0 = r.get("ime0");
1214 assertEquals(1, subtypes0.size());
1215 assertTrue(subtypes0.contains("subtype0"));
1216
1217 ArraySet<String> subtypes1 = r.get("ime1");
1218 assertEquals(1, subtypes1.size());
1219 assertTrue(subtypes1.contains("subtype1"));
1220 }
1221 {
1222 ArrayMap<String, ArraySet<String>> r =
1223 InputMethodUtils.parseInputMethodsAndSubtypesString(
1224 "ime0;subtype0;subtype1:ime1;subtype2");
1225 assertEquals(2, r.size());
1226 assertTrue(r.containsKey("ime0"));
1227 assertTrue(r.containsKey("ime1"));
1228 ArraySet<String> subtypes0 = r.get("ime0");
1229 assertEquals(2, subtypes0.size());
1230 assertTrue(subtypes0.contains("subtype0"));
1231 assertTrue(subtypes0.contains("subtype1"));
1232
1233 ArraySet<String> subtypes1 = r.get("ime1");
1234 assertEquals(1, subtypes1.size());
1235 assertTrue(subtypes1.contains("subtype2"));
1236 }
1237 {
1238 ArrayMap<String, ArraySet<String>> r =
1239 InputMethodUtils.parseInputMethodsAndSubtypesString(
1240 "ime0;subtype0;subtype1:ime1;subtype1;subtype2");
1241 assertEquals(2, r.size());
1242 assertTrue(r.containsKey("ime0"));
1243 assertTrue(r.containsKey("ime1"));
1244 ArraySet<String> subtypes0 = r.get("ime0");
1245 assertEquals(2, subtypes0.size());
1246 assertTrue(subtypes0.contains("subtype0"));
1247 assertTrue(subtypes0.contains("subtype1"));
1248
1249 ArraySet<String> subtypes1 = r.get("ime1");
1250 assertEquals(2, subtypes1.size());
1251 assertTrue(subtypes0.contains("subtype1"));
1252 assertTrue(subtypes1.contains("subtype2"));
1253 }
1254 {
1255 ArrayMap<String, ArraySet<String>> r =
1256 InputMethodUtils.parseInputMethodsAndSubtypesString(
1257 "ime0;subtype0;subtype1:ime1;subtype1;subtype2:ime2");
1258 assertEquals(3, r.size());
1259 assertTrue(r.containsKey("ime0"));
1260 assertTrue(r.containsKey("ime1"));
1261 assertTrue(r.containsKey("ime2"));
1262 ArraySet<String> subtypes0 = r.get("ime0");
1263 assertEquals(2, subtypes0.size());
1264 assertTrue(subtypes0.contains("subtype0"));
1265 assertTrue(subtypes0.contains("subtype1"));
1266
1267 ArraySet<String> subtypes1 = r.get("ime1");
1268 assertEquals(2, subtypes1.size());
1269 assertTrue(subtypes0.contains("subtype1"));
1270 assertTrue(subtypes1.contains("subtype2"));
1271
1272 ArraySet<String> subtypes2 = r.get("ime2");
1273 assertTrue(subtypes2.isEmpty());
1274 }
1275 }
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001276
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001277 @Test
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001278 public void testbuildInputMethodsAndSubtypesString() {
1279 {
1280 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1281 assertEquals("", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
1282 }
1283 {
1284 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001285 map.put("ime0", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001286 assertEquals("ime0", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
1287 }
1288 {
1289 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1290 ArraySet<String> subtypes1 = new ArraySet<>();
1291 subtypes1.add("subtype0");
1292 map.put("ime0", subtypes1);
1293 assertEquals("ime0;subtype0", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
1294 }
1295 {
1296 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1297 ArraySet<String> subtypes1 = new ArraySet<>();
1298 subtypes1.add("subtype0");
1299 subtypes1.add("subtype1");
1300 map.put("ime0", subtypes1);
1301
1302 // We do not expect what order will be used to concatenate items in
1303 // InputMethodUtils.buildInputMethodsAndSubtypesString() hence enumerate all possible
1304 // permutations here.
1305 ArraySet<String> validSequences = new ArraySet<>();
1306 validSequences.add("ime0;subtype0;subtype1");
1307 validSequences.add("ime0;subtype1;subtype0");
1308 assertTrue(validSequences.contains(
1309 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1310 }
1311 {
1312 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001313 map.put("ime0", new ArraySet<>());
1314 map.put("ime1", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001315
1316 ArraySet<String> validSequences = new ArraySet<>();
1317 validSequences.add("ime0:ime1");
1318 validSequences.add("ime1:ime0");
1319 assertTrue(validSequences.contains(
1320 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1321 }
1322 {
1323 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1324 ArraySet<String> subtypes1 = new ArraySet<>();
1325 subtypes1.add("subtype0");
1326 map.put("ime0", subtypes1);
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001327 map.put("ime1", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001328
1329 ArraySet<String> validSequences = new ArraySet<>();
1330 validSequences.add("ime0;subtype0:ime1");
1331 validSequences.add("ime1;ime0;subtype0");
1332 assertTrue(validSequences.contains(
1333 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1334 }
1335 {
1336 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1337 ArraySet<String> subtypes1 = new ArraySet<>();
1338 subtypes1.add("subtype0");
1339 subtypes1.add("subtype1");
1340 map.put("ime0", subtypes1);
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001341 map.put("ime1", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001342
1343 ArraySet<String> validSequences = new ArraySet<>();
1344 validSequences.add("ime0;subtype0;subtype1:ime1");
1345 validSequences.add("ime0;subtype1;subtype0:ime1");
1346 validSequences.add("ime1:ime0;subtype0;subtype1");
1347 validSequences.add("ime1:ime0;subtype1;subtype0");
1348 assertTrue(validSequences.contains(
1349 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1350 }
1351 {
1352 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1353 ArraySet<String> subtypes1 = new ArraySet<>();
1354 subtypes1.add("subtype0");
1355 map.put("ime0", subtypes1);
1356
1357 ArraySet<String> subtypes2 = new ArraySet<>();
1358 subtypes2.add("subtype1");
1359 map.put("ime1", subtypes2);
1360
1361 ArraySet<String> validSequences = new ArraySet<>();
1362 validSequences.add("ime0;subtype0:ime1;subtype1");
1363 validSequences.add("ime1;subtype1:ime0;subtype0");
1364 assertTrue(validSequences.contains(
1365 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1366 }
1367 {
1368 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1369 ArraySet<String> subtypes1 = new ArraySet<>();
1370 subtypes1.add("subtype0");
1371 subtypes1.add("subtype1");
1372 map.put("ime0", subtypes1);
1373
1374 ArraySet<String> subtypes2 = new ArraySet<>();
1375 subtypes2.add("subtype2");
1376 subtypes2.add("subtype3");
1377 map.put("ime1", subtypes2);
1378
1379 ArraySet<String> validSequences = new ArraySet<>();
1380 validSequences.add("ime0;subtype0;subtype1:ime1;subtype2;subtype3");
1381 validSequences.add("ime0;subtype1;subtype0:ime1;subtype2;subtype3");
1382 validSequences.add("ime0;subtype0;subtype1:ime1;subtype3;subtype2");
1383 validSequences.add("ime0;subtype1;subtype0:ime1;subtype3;subtype2");
1384 validSequences.add("ime1;subtype2;subtype3:ime0;subtype0;subtype1");
1385 validSequences.add("ime2;subtype3;subtype2:ime0;subtype0;subtype1");
1386 validSequences.add("ime3;subtype2;subtype3:ime0;subtype1;subtype0");
1387 validSequences.add("ime4;subtype3;subtype2:ime0;subtype1;subtype0");
1388 assertTrue(validSequences.contains(
1389 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1390 }
1391 }
Yohei Yukawa226c4bb2015-12-03 15:21:15 -08001392
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001393 @Test
Yohei Yukawa226c4bb2015-12-03 15:21:15 -08001394 public void testConstructLocaleFromString() throws Exception {
1395 assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en"));
1396 assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US"));
1397 assertEquals(new Locale("en", "US", "POSIX"),
1398 InputMethodUtils.constructLocaleFromString("en_US_POSIX"));
1399
1400 // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
1401 // support three letter language codes, and used "tl" (Tagalog) as the language string for
1402 // "fil" (Filipino).
1403 assertEquals(new Locale("fil"), InputMethodUtils.constructLocaleFromString("tl"));
1404 assertEquals(new Locale("fil", "PH"), InputMethodUtils.constructLocaleFromString("tl_PH"));
1405 assertEquals(new Locale("fil", "PH", "POSIX"),
1406 InputMethodUtils.constructLocaleFromString("tl_PH_POSIX"));
1407
1408 // So far rejecting an invalid/unexpected locale string is out of the scope of this method.
1409 assertEquals(new Locale("a"), InputMethodUtils.constructLocaleFromString("a"));
1410 assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c"));
1411 assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US"));
1412 }
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09001413}