blob: e6ac68294564c4fe54881f946555a3148b5433b1 [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 Yukawacf68d522017-12-12 09:33:26 -080019import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR;
20import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS;
21
Yohei Yukawa8306fc42017-12-11 15:09:28 -080022import static org.hamcrest.MatcherAssert.assertThat;
23import static org.hamcrest.Matchers.in;
24import static org.hamcrest.Matchers.not;
25import static org.hamcrest.core.Is.is;
26import static org.junit.Assert.assertEquals;
27import static org.junit.Assert.assertFalse;
28import static org.junit.Assert.assertNotNull;
29import static org.junit.Assert.assertTrue;
30
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090031import android.content.Context;
32import android.content.pm.ApplicationInfo;
33import android.content.pm.ResolveInfo;
34import android.content.pm.ServiceInfo;
Yohei Yukawa5d64399c2016-02-08 23:21:37 -080035import android.content.res.Configuration;
Yohei Yukawafc843712016-02-24 00:27:34 -080036import android.content.res.Resources;
Yohei Yukawacf68d522017-12-12 09:33:26 -080037import android.os.Build;
Yohei Yukawa23cbe852016-05-17 16:42:58 -070038import android.os.LocaleList;
Yohei Yukawa35f74372015-08-12 20:14:08 -070039import android.os.Parcel;
Yohei Yukawa8306fc42017-12-11 15:09:28 -080040import android.support.test.InstrumentationRegistry;
41import android.support.test.filters.SmallTest;
42import android.support.test.runner.AndroidJUnit4;
Seigo Nonaka2028dda2015-07-06 17:41:24 +090043import android.util.ArrayMap;
44import android.util.ArraySet;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090045import android.view.inputmethod.InputMethodInfo;
Seigo Nonaka2028dda2015-07-06 17:41:24 +090046import android.view.inputmethod.InputMethodSubtype;
Yohei Yukawa8306fc42017-12-11 15:09:28 -080047import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
48
49import org.junit.Test;
50import org.junit.runner.RunWith;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090051
52import java.util.ArrayList;
53import java.util.List;
Yohei Yukawabca817b2014-09-11 16:59:31 +090054import java.util.Locale;
Yohei Yukawab21220e2014-11-01 21:04:30 +090055import java.util.Objects;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090056
Yohei Yukawa8306fc42017-12-11 15:09:28 -080057@SmallTest
58@RunWith(AndroidJUnit4.class)
59public class InputMethodUtilsTest {
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090060 private static final boolean IS_AUX = true;
61 private static final boolean IS_DEFAULT = true;
Yohei Yukawae72d1c82015-02-20 20:55:21 +090062 private static final boolean IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE = true;
Yohei Yukawacfcbdda2014-09-10 17:53:51 +090063 private static final boolean IS_ASCII_CAPABLE = true;
Yohei Yukawae72d1c82015-02-20 20:55:21 +090064 private static final boolean IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE = true;
Yohei Yukawae72d1c82015-02-20 20:55:21 +090065 private static final Locale LOCALE_EN = new Locale("en");
Yohei Yukawabca817b2014-09-11 16:59:31 +090066 private static final Locale LOCALE_EN_US = new Locale("en", "US");
Yohei Yukawad77adfe2014-09-11 23:50:21 +090067 private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
68 private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
Yohei Yukawae72d1c82015-02-20 20:55:21 +090069 private static final Locale LOCALE_FI = new Locale("fi");
70 private static final Locale LOCALE_FI_FI = new Locale("fi", "FI");
71 private static final Locale LOCALE_FIL = new Locale("fil");
72 private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
73 private static final Locale LOCALE_FR = new Locale("fr");
74 private static final Locale LOCALE_FR_CA = new Locale("fr", "CA");
Yohei Yukawad77adfe2014-09-11 23:50:21 +090075 private static final Locale LOCALE_HI = new Locale("hi");
Yohei Yukawa174843a2015-06-26 18:02:54 -070076 private static final Locale LOCALE_JA = new Locale("ja");
Yohei Yukawa59cccf92014-09-12 23:21:54 +090077 private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
Yohei Yukawab21220e2014-11-01 21:04:30 +090078 private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN");
79 private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW");
Yohei Yukawae72d1c82015-02-20 20:55:21 +090080 private static final Locale LOCALE_IN = new Locale("in");
81 private static final Locale LOCALE_ID = new Locale("id");
Yohei Yukawa174843a2015-06-26 18:02:54 -070082 private static final Locale LOCALE_TH = new Locale("ht");
83 private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
84 private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
Yohei Yukawa59cccf92014-09-12 23:21:54 +090085 private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
86 private static final String SUBTYPE_MODE_VOICE = "voice";
Yohei Yukawa42275bc2016-03-03 00:34:27 -080087 private static final String SUBTYPE_MODE_HANDWRITING = "handwriting";
Yohei Yukawae72d1c82015-02-20 20:55:21 +090088 private static final String SUBTYPE_MODE_ANY = null;
89 private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
90 private static final String EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
91 private static final String EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE =
92 "EnabledWhenDefaultIsNotAsciiCapable";
Satoshi Kataokaf1367b72013-01-25 17:20:12 +090093
Yohei Yukawa8306fc42017-12-11 15:09:28 -080094 @Test
Yohei Yukawa59cccf92014-09-12 23:21:54 +090095 public void testVoiceImes() throws Exception {
96 // locale: en_US
Yohei Yukawab21220e2014-11-01 21:04:30 +090097 assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -080098 "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
Yohei Yukawab21220e2014-11-01 21:04:30 +090099 assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800100 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900101 "DummyNonDefaultAutoVoiceIme1");
Yohei Yukawad77adfe2014-09-11 23:50:21 +0900102
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900103 // locale: en_GB
Yohei Yukawab21220e2014-11-01 21:04:30 +0900104 assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800105 "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900106 assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800107 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900108 "DummyNonDefaultAutoVoiceIme1");
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900109
110 // locale: ja_JP
Yohei Yukawab21220e2014-11-01 21:04:30 +0900111 assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800112 "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900113 assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800114 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900115 "DummyNonDefaultAutoVoiceIme1");
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900116 }
117
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800118 @Test
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900119 public void testKeyboardImes() throws Exception {
120 // locale: en_US
Yohei Yukawab21220e2014-11-01 21:04:30 +0900121 assertDefaultEnabledImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US,
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_GB
Yohei Yukawab21220e2014-11-01 21:04:30 +0900125 assertDefaultEnabledImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800126 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Yohei Yukawabca817b2014-09-11 16:59:31 +0900127
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900128 // locale: en_IN
Yohei Yukawab21220e2014-11-01 21:04:30 +0900129 assertDefaultEnabledImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800130 "com.android.apps.inputmethod.hindi",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900131 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Yohei Yukawad77adfe2014-09-11 23:50:21 +0900132
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900133 // locale: hi
Yohei Yukawab21220e2014-11-01 21:04:30 +0900134 assertDefaultEnabledImes(getSamplePreinstalledImes("hi"), LOCALE_HI,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800135 "com.android.apps.inputmethod.hindi", "com.android.apps.inputmethod.latin",
136 "com.android.apps.inputmethod.voice");
Yohei Yukawad77adfe2014-09-11 23:50:21 +0900137
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900138 // locale: ja_JP
Yohei Yukawab21220e2014-11-01 21:04:30 +0900139 assertDefaultEnabledImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800140 "com.android.apps.inputmethod.japanese", "com.android.apps.inputmethod.voice");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900141
142 // locale: zh_CN
143 assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800144 "com.android.apps.inputmethod.pinyin", "com.android.apps.inputmethod.voice");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900145
146 // locale: zh_TW
147 // Note: In this case, no IME is suitable for the system locale. Hence we will pick up a
148 // fallback IME regardless of the "default" attribute.
149 assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800150 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900151 }
152
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800153 @Test
Yohei Yukawa58980042014-02-27 17:10:00 +0900154 public void testParcelable() throws Exception {
Yohei Yukawab21220e2014-11-01 21:04:30 +0900155 final ArrayList<InputMethodInfo> originalList = getSamplePreinstalledImes("en-rUS");
Yohei Yukawa58980042014-02-27 17:10:00 +0900156 final List<InputMethodInfo> clonedList = cloneViaParcel(originalList);
157 assertNotNull(clonedList);
Yohei Yukawac18cd392014-03-03 13:08:34 +0900158 final List<InputMethodInfo> clonedClonedList = cloneViaParcel(clonedList);
159 assertNotNull(clonedClonedList);
Yohei Yukawa58980042014-02-27 17:10:00 +0900160 assertEquals(originalList, clonedList);
Yohei Yukawac18cd392014-03-03 13:08:34 +0900161 assertEquals(clonedList, clonedClonedList);
162 assertEquals(originalList.size(), clonedList.size());
163 assertEquals(clonedList.size(), clonedClonedList.size());
Yohei Yukawa58980042014-02-27 17:10:00 +0900164 for (int imeIndex = 0; imeIndex < originalList.size(); ++imeIndex) {
Yohei Yukawac18cd392014-03-03 13:08:34 +0900165 verifyEquality(originalList.get(imeIndex), clonedList.get(imeIndex));
166 verifyEquality(clonedList.get(imeIndex), clonedClonedList.get(imeIndex));
Yohei Yukawa58980042014-02-27 17:10:00 +0900167 }
168 }
169
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800170 @Test
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900171 public void testGetImplicitlyApplicableSubtypesLocked() throws Exception {
172 final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
173 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
174 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
175 final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
176 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
177 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawae985c242016-02-24 18:27:04 -0800178 final InputMethodSubtype nonAutoEnIN = createDummyInputMethodSubtype("en_IN",
179 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
180 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900181 final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA",
182 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
183 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
184 final InputMethodSubtype nonAutoFr = createDummyInputMethodSubtype("fr_CA",
185 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
186 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
187 final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
188 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
189 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
190 final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
191 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
192 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
193 final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
194 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
195 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
196 final InputMethodSubtype autoSubtype = createDummyInputMethodSubtype("auto",
197 SUBTYPE_MODE_KEYBOARD, !IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
198 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
199 final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja",
200 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
201 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800202 final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi",
203 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
204 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa238faad2016-03-11 10:39:51 -0800205 final InputMethodSubtype nonAutoSrCyrl = createDummyInputMethodSubtype("sr",
206 "sr-Cyrl", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
207 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
208 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
209 final InputMethodSubtype nonAutoSrLatn = createDummyInputMethodSubtype("sr_ZZ",
210 "sr-Latn", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
211 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
212 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800213 final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en",
214 SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
215 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800216 final InputMethodSubtype nonAutoHandwritingFr = createDummyInputMethodSubtype("fr",
217 SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
218 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa238faad2016-03-11 10:39:51 -0800219 final InputMethodSubtype nonAutoHandwritingSrCyrl = createDummyInputMethodSubtype("sr",
220 "sr-Cyrl", SUBTYPE_MODE_HANDWRITING, !IS_AUX,
221 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
222 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
223 final InputMethodSubtype nonAutoHandwritingSrLatn = createDummyInputMethodSubtype("sr_ZZ",
224 "sr-Latn", SUBTYPE_MODE_HANDWRITING, !IS_AUX,
225 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
226 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900227 final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype =
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 final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2 =
232 createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
233 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
234 IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
235
236 // Make sure that an automatic subtype (overridesImplicitlyEnabledSubtype:true) is
237 // selected no matter what locale is specified.
238 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800239 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900240 subtypes.add(nonAutoEnUS);
241 subtypes.add(nonAutoEnGB);
242 subtypes.add(nonAutoJa);
243 subtypes.add(nonAutoFil);
244 subtypes.add(autoSubtype); // overridesImplicitlyEnabledSubtype == true
245 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
246 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800247 subtypes.add(nonAutoHandwritingEn);
248 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900249 final InputMethodInfo imi = createDummyInputMethodInfo(
250 "com.android.apps.inputmethod.latin",
251 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
252 subtypes);
253 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800254 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800255 getResourcesForLocales(LOCALE_EN_US), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900256 assertEquals(1, result.size());
257 verifyEquality(autoSubtype, result.get(0));
258 }
259
260 // Make sure that a subtype whose locale is exactly equal to the specified locale is
261 // selected as long as there is no no automatic subtype
262 // (overridesImplicitlyEnabledSubtype:true) in the given list.
263 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800264 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900265 subtypes.add(nonAutoEnUS); // locale == "en_US"
266 subtypes.add(nonAutoEnGB);
267 subtypes.add(nonAutoJa);
268 subtypes.add(nonAutoFil);
269 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
270 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800271 subtypes.add(nonAutoHandwritingEn);
272 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900273 final InputMethodInfo imi = createDummyInputMethodInfo(
274 "com.android.apps.inputmethod.latin",
275 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
276 subtypes);
277 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800278 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800279 getResourcesForLocales(LOCALE_EN_US), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800280 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900281 verifyEquality(nonAutoEnUS, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800282 verifyEquality(nonAutoHandwritingEn, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900283 }
284
285 // Make sure that a subtype whose locale is exactly equal to the specified locale is
286 // selected as long as there is no automatic subtype
287 // (overridesImplicitlyEnabledSubtype:true) in the given list.
288 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800289 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900290 subtypes.add(nonAutoEnUS);
291 subtypes.add(nonAutoEnGB); // locale == "en_GB"
292 subtypes.add(nonAutoJa);
293 subtypes.add(nonAutoFil);
294 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800295 subtypes.add(nonAutoHandwritingEn);
296 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900297 final InputMethodInfo imi = createDummyInputMethodInfo(
298 "com.android.apps.inputmethod.latin",
299 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
300 subtypes);
301 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800302 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800303 getResourcesForLocales(LOCALE_EN_GB), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800304 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900305 verifyEquality(nonAutoEnGB, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800306 verifyEquality(nonAutoHandwritingEn, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900307 }
308
309 // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and
310 // any subtype whose locale is exactly equal to the specified locale in the given list,
311 // try to find a subtype whose language is equal to the language part of the given locale.
312 // Here make sure that a subtype (locale: "fr_CA") can be found with locale: "fr".
313 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800314 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900315 subtypes.add(nonAutoFrCA); // locale == "fr_CA"
316 subtypes.add(nonAutoJa);
317 subtypes.add(nonAutoFil);
318 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
319 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800320 subtypes.add(nonAutoHandwritingEn);
321 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900322 final InputMethodInfo imi = createDummyInputMethodInfo(
323 "com.android.apps.inputmethod.latin",
324 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
325 subtypes);
326 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800327 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800328 getResourcesForLocales(LOCALE_FR), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800329 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900330 verifyEquality(nonAutoFrCA, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800331 verifyEquality(nonAutoHandwritingFr, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900332 }
333 // Then make sure that a subtype (locale: "fr") can be found with locale: "fr_CA".
334 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800335 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900336 subtypes.add(nonAutoFr); // locale == "fr"
337 subtypes.add(nonAutoJa);
338 subtypes.add(nonAutoFil);
339 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
340 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800341 subtypes.add(nonAutoHandwritingEn);
342 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900343 final InputMethodInfo imi = createDummyInputMethodInfo(
344 "com.android.apps.inputmethod.latin",
345 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
346 subtypes);
347 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800348 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800349 getResourcesForLocales(LOCALE_FR_CA), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800350 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900351 verifyEquality(nonAutoFrCA, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800352 verifyEquality(nonAutoHandwritingFr, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900353 }
354
355 // Make sure that subtypes which have "EnabledWhenDefaultIsNotAsciiCapable" in its
356 // extra value is selected if and only if all other selected IMEs are not AsciiCapable.
357 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800358 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900359 subtypes.add(nonAutoEnUS);
360 subtypes.add(nonAutoJa); // not ASCII capable
361 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
362 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800363 subtypes.add(nonAutoHandwritingEn);
364 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900365 final InputMethodInfo imi = createDummyInputMethodInfo(
366 "com.android.apps.inputmethod.latin",
367 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
368 subtypes);
369 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800370 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800371 getResourcesForLocales(LOCALE_JA_JP), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900372 assertEquals(3, result.size());
373 verifyEquality(nonAutoJa, result.get(0));
374 verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, result.get(1));
375 verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2, result.get(2));
376 }
377
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800378 // Make sure that if there is no subtype that matches the language requested, then we just
379 // use the first keyboard subtype.
380 {
381 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
382 subtypes.add(nonAutoHi);
383 subtypes.add(nonAutoEnUS);
384 subtypes.add(nonAutoHandwritingEn);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800385 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800386 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
387 final InputMethodInfo imi = createDummyInputMethodInfo(
388 "com.android.apps.inputmethod.latin",
389 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
390 subtypes);
391 final ArrayList<InputMethodSubtype> result =
392 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
393 getResourcesForLocales(LOCALE_JA_JP), imi);
394 assertEquals(1, result.size());
395 verifyEquality(nonAutoHi, result.get(0));
396 }
397 {
398 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
399 subtypes.add(nonAutoEnUS);
400 subtypes.add(nonAutoHi);
401 subtypes.add(nonAutoHandwritingEn);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800402 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800403 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
404 final InputMethodInfo imi = createDummyInputMethodInfo(
405 "com.android.apps.inputmethod.latin",
406 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
407 subtypes);
408 final ArrayList<InputMethodSubtype> result =
409 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
410 getResourcesForLocales(LOCALE_JA_JP), imi);
411 assertEquals(1, result.size());
412 verifyEquality(nonAutoEnUS, result.get(0));
413 }
414 {
415 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
416 subtypes.add(nonAutoHandwritingEn);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800417 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800418 subtypes.add(nonAutoEnUS);
419 subtypes.add(nonAutoHi);
420 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
421 final InputMethodInfo imi = createDummyInputMethodInfo(
422 "com.android.apps.inputmethod.latin",
423 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
424 subtypes);
425 final ArrayList<InputMethodSubtype> result =
426 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
427 getResourcesForLocales(LOCALE_JA_JP), imi);
428 assertEquals(1, result.size());
429 verifyEquality(nonAutoEnUS, result.get(0));
430 }
431
Yohei Yukawa238faad2016-03-11 10:39:51 -0800432 // Make sure that both language and script are taken into account to find the best matching
433 // subtype.
434 {
435 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
436 subtypes.add(nonAutoEnUS);
437 subtypes.add(nonAutoSrCyrl);
438 subtypes.add(nonAutoSrLatn);
439 subtypes.add(nonAutoHandwritingEn);
440 subtypes.add(nonAutoHandwritingFr);
441 subtypes.add(nonAutoHandwritingSrCyrl);
442 subtypes.add(nonAutoHandwritingSrLatn);
443 final InputMethodInfo imi = createDummyInputMethodInfo(
444 "com.android.apps.inputmethod.latin",
445 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
446 subtypes);
447 final ArrayList<InputMethodSubtype> result =
448 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
449 getResourcesForLocales(Locale.forLanguageTag("sr-Latn-RS")), imi);
450 assertEquals(2, result.size());
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800451 assertThat(nonAutoSrLatn, is(in(result)));
452 assertThat(nonAutoHandwritingSrLatn, is(in(result)));
Yohei Yukawa238faad2016-03-11 10:39:51 -0800453 }
454 {
455 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
456 subtypes.add(nonAutoEnUS);
457 subtypes.add(nonAutoSrCyrl);
458 subtypes.add(nonAutoSrLatn);
459 subtypes.add(nonAutoHandwritingEn);
460 subtypes.add(nonAutoHandwritingFr);
461 subtypes.add(nonAutoHandwritingSrCyrl);
462 subtypes.add(nonAutoHandwritingSrLatn);
463 final InputMethodInfo imi = createDummyInputMethodInfo(
464 "com.android.apps.inputmethod.latin",
465 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
466 subtypes);
467 final ArrayList<InputMethodSubtype> result =
468 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
469 getResourcesForLocales(Locale.forLanguageTag("sr-Cyrl-RS")), imi);
470 assertEquals(2, result.size());
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800471 assertThat(nonAutoSrCyrl, is(in(result)));
472 assertThat(nonAutoHandwritingSrCyrl, is(in(result)));
Yohei Yukawa238faad2016-03-11 10:39:51 -0800473 }
474
475 // Make sure that secondary locales are taken into account to find the best matching
476 // subtype.
477 {
478 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
479 subtypes.add(nonAutoEnUS);
480 subtypes.add(nonAutoEnGB);
481 subtypes.add(nonAutoSrCyrl);
482 subtypes.add(nonAutoSrLatn);
483 subtypes.add(nonAutoFr);
484 subtypes.add(nonAutoFrCA);
485 subtypes.add(nonAutoHandwritingEn);
486 subtypes.add(nonAutoHandwritingFr);
487 subtypes.add(nonAutoHandwritingSrCyrl);
488 subtypes.add(nonAutoHandwritingSrLatn);
489 final InputMethodInfo imi = createDummyInputMethodInfo(
490 "com.android.apps.inputmethod.latin",
491 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
492 subtypes);
493 final ArrayList<InputMethodSubtype> result =
494 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
495 getResourcesForLocales(
496 Locale.forLanguageTag("sr-Latn-RS-x-android"),
497 Locale.forLanguageTag("ja-JP"),
498 Locale.forLanguageTag("fr-FR"),
499 Locale.forLanguageTag("en-GB"),
500 Locale.forLanguageTag("en-US")),
501 imi);
502 assertEquals(6, result.size());
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800503 assertThat(nonAutoEnGB, is(in(result)));
504 assertThat(nonAutoFr, is(in(result)));
505 assertThat(nonAutoSrLatn, is(in(result)));
506 assertThat(nonAutoHandwritingEn, is(in(result)));
507 assertThat(nonAutoHandwritingFr, is(in(result)));
508 assertThat(nonAutoHandwritingSrLatn, is(in(result)));
Yohei Yukawa238faad2016-03-11 10:39:51 -0800509 }
510
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900511 // Make sure that 3-letter language code can be handled.
512 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800513 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900514 subtypes.add(nonAutoEnUS);
515 subtypes.add(nonAutoFil);
516 final InputMethodInfo imi = createDummyInputMethodInfo(
517 "com.android.apps.inputmethod.latin",
518 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
519 subtypes);
520 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800521 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800522 getResourcesForLocales(LOCALE_FIL_PH), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900523 assertEquals(1, result.size());
524 verifyEquality(nonAutoFil, result.get(0));
525 }
526
527 // Make sure that we never end up matching "fi" (finnish) with "fil" (filipino).
528 // Also make sure that the first subtype will be used as the last-resort candidate.
529 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800530 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900531 subtypes.add(nonAutoJa);
532 subtypes.add(nonAutoEnUS);
533 subtypes.add(nonAutoFil);
534 final InputMethodInfo imi = createDummyInputMethodInfo(
535 "com.android.apps.inputmethod.latin",
536 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
537 subtypes);
538 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800539 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800540 getResourcesForLocales(LOCALE_FI), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900541 assertEquals(1, result.size());
542 verifyEquality(nonAutoJa, result.get(0));
543 }
544
545 // Make sure that "in" and "id" conversion is taken into account.
546 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800547 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900548 subtypes.add(nonAutoIn);
549 subtypes.add(nonAutoEnUS);
550 final InputMethodInfo imi = createDummyInputMethodInfo(
551 "com.android.apps.inputmethod.latin",
552 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
553 subtypes);
554 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800555 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800556 getResourcesForLocales(LOCALE_IN), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900557 assertEquals(1, result.size());
558 verifyEquality(nonAutoIn, result.get(0));
559 }
560 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800561 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900562 subtypes.add(nonAutoIn);
563 subtypes.add(nonAutoEnUS);
564 final InputMethodInfo imi = createDummyInputMethodInfo(
565 "com.android.apps.inputmethod.latin",
566 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
567 subtypes);
568 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800569 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800570 getResourcesForLocales(LOCALE_ID), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900571 assertEquals(1, result.size());
572 verifyEquality(nonAutoIn, result.get(0));
573 }
574 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800575 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900576 subtypes.add(nonAutoId);
577 subtypes.add(nonAutoEnUS);
578 final InputMethodInfo imi = createDummyInputMethodInfo(
579 "com.android.apps.inputmethod.latin",
580 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
581 subtypes);
582 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800583 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800584 getResourcesForLocales(LOCALE_IN), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900585 assertEquals(1, result.size());
586 verifyEquality(nonAutoId, result.get(0));
587 }
588 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800589 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900590 subtypes.add(nonAutoId);
591 subtypes.add(nonAutoEnUS);
592 final InputMethodInfo imi = createDummyInputMethodInfo(
593 "com.android.apps.inputmethod.latin",
594 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
595 subtypes);
596 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800597 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800598 getResourcesForLocales(LOCALE_ID), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900599 assertEquals(1, result.size());
600 verifyEquality(nonAutoId, result.get(0));
601 }
Yohei Yukawae985c242016-02-24 18:27:04 -0800602
603 // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and the system
604 // provides multiple locales, we try to enable multiple subtypes.
605 {
606 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
607 subtypes.add(nonAutoEnUS);
608 subtypes.add(nonAutoFrCA);
609 subtypes.add(nonAutoIn);
610 subtypes.add(nonAutoJa);
611 subtypes.add(nonAutoFil);
612 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
613 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
614 final InputMethodInfo imi = createDummyInputMethodInfo(
615 "com.android.apps.inputmethod.latin",
616 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
617 subtypes);
618 final ArrayList<InputMethodSubtype> result =
619 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
620 getResourcesForLocales(LOCALE_FR, LOCALE_EN_US, LOCALE_JA_JP), imi);
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800621 assertThat(nonAutoFrCA, is(in(result)));
622 assertThat(nonAutoEnUS, is(in(result)));
623 assertThat(nonAutoJa, is(in(result)));
624 assertThat(nonAutoIn, not(is(in(result))));
625 assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(is(in(result))));
626 assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(is(in(result))));
Yohei Yukawae985c242016-02-24 18:27:04 -0800627 }
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900628 }
629
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800630 @Test
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900631 public void testContainsSubtypeOf() throws Exception {
632 final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
633 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
634 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
635 final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
636 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
637 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
638 final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
639 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
640 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
641 final InputMethodSubtype nonAutoFilPH = createDummyInputMethodSubtype("fil_PH",
642 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
643 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
644 final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
645 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
646 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
647 final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
648 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
649 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
650
651 final boolean CHECK_COUNTRY = true;
652
653 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800654 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900655 subtypes.add(nonAutoEnUS);
656 final InputMethodInfo imi = createDummyInputMethodInfo(
657 "com.android.apps.inputmethod.latin",
658 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
659 subtypes);
660
661 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY,
662 SUBTYPE_MODE_KEYBOARD));
663 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, CHECK_COUNTRY,
664 SUBTYPE_MODE_KEYBOARD));
665 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
666 SUBTYPE_MODE_KEYBOARD));
667 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
668 SUBTYPE_MODE_KEYBOARD));
669 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
670 SUBTYPE_MODE_VOICE));
671 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
672 SUBTYPE_MODE_VOICE));
673 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
674 SUBTYPE_MODE_ANY));
675 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
676 SUBTYPE_MODE_ANY));
677
678 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, !CHECK_COUNTRY,
679 SUBTYPE_MODE_KEYBOARD));
680 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, CHECK_COUNTRY,
681 SUBTYPE_MODE_KEYBOARD));
682 }
683
684 // Make sure that 3-letter language code ("fil") can be handled.
685 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800686 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900687 subtypes.add(nonAutoFil);
688 final InputMethodInfo imi = createDummyInputMethodInfo(
689 "com.android.apps.inputmethod.latin",
690 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
691 subtypes);
692 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
693 SUBTYPE_MODE_KEYBOARD));
694 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
695 SUBTYPE_MODE_KEYBOARD));
696 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
697 SUBTYPE_MODE_KEYBOARD));
698 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
699 SUBTYPE_MODE_KEYBOARD));
700
701 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
702 SUBTYPE_MODE_KEYBOARD));
703 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
704 SUBTYPE_MODE_KEYBOARD));
705 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
706 SUBTYPE_MODE_KEYBOARD));
707 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
708 SUBTYPE_MODE_KEYBOARD));
709 }
710
711 // Make sure that 3-letter language code ("fil_PH") can be handled.
712 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800713 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900714 subtypes.add(nonAutoFilPH);
715 final InputMethodInfo imi = createDummyInputMethodInfo(
716 "com.android.apps.inputmethod.latin",
717 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
718 subtypes);
719 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
720 SUBTYPE_MODE_KEYBOARD));
721 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
722 SUBTYPE_MODE_KEYBOARD));
723 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
724 SUBTYPE_MODE_KEYBOARD));
725 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
726 SUBTYPE_MODE_KEYBOARD));
727
728 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
729 SUBTYPE_MODE_KEYBOARD));
730 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
731 SUBTYPE_MODE_KEYBOARD));
732 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
733 SUBTYPE_MODE_KEYBOARD));
734 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
735 SUBTYPE_MODE_KEYBOARD));
736 }
737
738 // Make sure that a subtype whose locale is "in" can be queried with "id".
739 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800740 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900741 subtypes.add(nonAutoIn);
742 subtypes.add(nonAutoEnUS);
743 final InputMethodInfo imi = createDummyInputMethodInfo(
744 "com.android.apps.inputmethod.latin",
745 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
746 subtypes);
747 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
748 SUBTYPE_MODE_KEYBOARD));
749 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
750 SUBTYPE_MODE_KEYBOARD));
751 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
752 SUBTYPE_MODE_KEYBOARD));
753 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
754 SUBTYPE_MODE_KEYBOARD));
755 }
756
757 // Make sure that a subtype whose locale is "id" can be queried with "in".
758 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800759 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900760 subtypes.add(nonAutoId);
761 subtypes.add(nonAutoEnUS);
762 final InputMethodInfo imi = createDummyInputMethodInfo(
763 "com.android.apps.inputmethod.latin",
764 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
765 subtypes);
766 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
767 SUBTYPE_MODE_KEYBOARD));
Yohei Yukawaf487e0e2015-02-21 02:15:48 +0900768 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900769 SUBTYPE_MODE_KEYBOARD));
770 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
771 SUBTYPE_MODE_KEYBOARD));
Yohei Yukawaf487e0e2015-02-21 02:15:48 +0900772 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900773 SUBTYPE_MODE_KEYBOARD));
774 }
775 }
776
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900777 private void assertDefaultEnabledImes(final ArrayList<InputMethodInfo> preinstalledImes,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800778 final Locale systemLocale, String... expectedImeNames) {
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800779 final Context context = createTargetContextWithLocales(new LocaleList(systemLocale));
780 final String[] actualImeNames = getPackageNames(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800781 InputMethodUtils.getDefaultEnabledImes(context, preinstalledImes));
Yohei Yukawab21220e2014-11-01 21:04:30 +0900782 assertEquals(expectedImeNames.length, actualImeNames.length);
783 for (int i = 0; i < expectedImeNames.length; ++i) {
784 assertEquals(expectedImeNames[i], actualImeNames[i]);
785 }
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900786 }
787
Yohei Yukawa58980042014-02-27 17:10:00 +0900788 private static List<InputMethodInfo> cloneViaParcel(final List<InputMethodInfo> list) {
789 Parcel p = null;
790 try {
791 p = Parcel.obtain();
792 p.writeTypedList(list);
793 p.setDataPosition(0);
794 return p.createTypedArrayList(InputMethodInfo.CREATOR);
795 } finally {
796 if (p != null) {
797 p.recycle();
798 }
799 }
800 }
801
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800802 private Context createTargetContextWithLocales(final LocaleList locales) {
803 final Configuration resourceConfiguration = new Configuration();
804 resourceConfiguration.setLocales(locales);
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800805 return InstrumentationRegistry.getInstrumentation()
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800806 .getTargetContext()
807 .createConfigurationContext(resourceConfiguration);
Yohei Yukawabca817b2014-09-11 16:59:31 +0900808 }
809
Yohei Yukawafc843712016-02-24 00:27:34 -0800810 private Resources getResourcesForLocales(Locale... locales) {
811 return createTargetContextWithLocales(new LocaleList(locales)).getResources();
812 }
813
Yohei Yukawab21220e2014-11-01 21:04:30 +0900814 private String[] getPackageNames(final ArrayList<InputMethodInfo> imis) {
815 final String[] packageNames = new String[imis.size()];
816 for (int i = 0; i < imis.size(); ++i) {
817 packageNames[i] = imis.get(i).getPackageName();
Yohei Yukawabca817b2014-09-11 16:59:31 +0900818 }
819 return packageNames;
820 }
821
Yohei Yukawac18cd392014-03-03 13:08:34 +0900822 private static void verifyEquality(InputMethodInfo expected, InputMethodInfo actual) {
823 assertEquals(expected, actual);
824 assertEquals(expected.getSubtypeCount(), actual.getSubtypeCount());
825 for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) {
826 final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex);
827 final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900828 verifyEquality(expectedSubtype, actualSubtype);
Yohei Yukawac18cd392014-03-03 13:08:34 +0900829 }
830 }
831
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900832 private static void verifyEquality(InputMethodSubtype expected, InputMethodSubtype actual) {
833 assertEquals(expected, actual);
834 assertEquals(expected.hashCode(), actual.hashCode());
835 }
836
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900837 private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
838 CharSequence label, boolean isAuxIme, boolean isDefault,
839 List<InputMethodSubtype> subtypes) {
840 final ResolveInfo ri = new ResolveInfo();
841 final ServiceInfo si = new ServiceInfo();
842 final ApplicationInfo ai = new ApplicationInfo();
843 ai.packageName = packageName;
844 ai.enabled = true;
845 ai.flags |= ApplicationInfo.FLAG_SYSTEM;
846 si.applicationInfo = ai;
847 si.enabled = true;
848 si.packageName = packageName;
849 si.name = name;
850 si.exported = true;
851 si.nonLocalizedLabel = label;
852 ri.serviceInfo = si;
853 return new InputMethodInfo(ri, isAuxIme, "", subtypes, 1, isDefault);
854 }
855
856 private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
Yohei Yukawacfcbdda2014-09-10 17:53:51 +0900857 boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900858 boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) {
Yohei Yukawa238faad2016-03-11 10:39:51 -0800859 return createDummyInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary,
860 overridesImplicitlyEnabledSubtype, isAsciiCapable,
861 isEnabledWhenDefaultIsNotAsciiCapable);
862 }
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900863
Yohei Yukawa238faad2016-03-11 10:39:51 -0800864 private static InputMethodSubtype createDummyInputMethodSubtype(String locale,
865 String languageTag, String mode, boolean isAuxiliary,
866 boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable,
867 boolean isEnabledWhenDefaultIsNotAsciiCapable) {
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900868 final StringBuilder subtypeExtraValue = new StringBuilder();
869 if (isEnabledWhenDefaultIsNotAsciiCapable) {
870 subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
871 subtypeExtraValue.append(EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
872 }
873
874 // TODO: Remove following code. InputMethodSubtype#isAsciiCapable() has been publicly
875 // available since API level 19 (KitKat). We no longer need to rely on extra value.
876 if (isAsciiCapable) {
877 subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
878 subtypeExtraValue.append(EXTRA_VALUE_ASCII_CAPABLE);
879 }
880
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900881 return new InputMethodSubtypeBuilder()
882 .setSubtypeNameResId(0)
883 .setSubtypeIconResId(0)
884 .setSubtypeLocale(locale)
Yohei Yukawa238faad2016-03-11 10:39:51 -0800885 .setLanguageTag(languageTag)
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900886 .setSubtypeMode(mode)
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900887 .setSubtypeExtraValue(subtypeExtraValue.toString())
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900888 .setIsAuxiliary(isAuxiliary)
889 .setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype)
Yohei Yukawacfcbdda2014-09-10 17:53:51 +0900890 .setIsAsciiCapable(isAsciiCapable)
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900891 .build();
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900892 }
893
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900894 private static ArrayList<InputMethodInfo> getImesWithDefaultVoiceIme() {
895 ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
896 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800897 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900898 subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
899 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
900 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900901 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900902 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
903 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900904 preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultAutoVoiceIme",
905 "dummy.voice0", "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes));
906 }
907 preinstalledImes.addAll(getImesWithoutDefaultVoiceIme());
908 return preinstalledImes;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900909 }
910
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900911 private static ArrayList<InputMethodInfo> getImesWithoutDefaultVoiceIme() {
912 ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
913 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800914 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900915 subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
916 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
917 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900918 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900919 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
920 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900921 preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0",
922 "dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes));
923 }
924 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800925 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900926 subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
927 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
928 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900929 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900930 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
931 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900932 preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1",
933 "dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes));
934 }
935 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800936 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900937 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900938 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
939 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900940 preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultVoiceIme2",
941 "dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes));
942 }
943 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800944 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900945 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900946 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
947 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900948 preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultEnKeyboardIme",
949 "dummy.keyboard0", "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes));
950 }
951 return preinstalledImes;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900952 }
953
Yohei Yukawab21220e2014-11-01 21:04:30 +0900954 private static boolean contains(final String[] textList, final String textToBeChecked) {
955 if (textList == null) {
956 return false;
957 }
958 for (final String text : textList) {
959 if (Objects.equals(textToBeChecked, text)) {
960 return true;
961 }
962 }
963 return false;
964 }
965
966 private static ArrayList<InputMethodInfo> getSamplePreinstalledImes(final String localeString) {
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900967 ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900968
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900969 // a dummy Voice IME
970 {
Yohei Yukawab21220e2014-11-01 21:04:30 +0900971 final boolean isDefaultIme = false;
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800972 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900973 subtypes.add(createDummyInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900974 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
975 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900976 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.voice",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900977 "com.android.inputmethod.voice", "DummyVoiceIme", IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900978 subtypes));
979 }
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900980 // a dummy Hindi IME
981 {
Yohei Yukawab21220e2014-11-01 21:04:30 +0900982 final boolean isDefaultIme = contains(new String[]{ "hi", "en-rIN" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800983 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900984 // TODO: This subtype should be marked as IS_ASCII_CAPABLE
985 subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900986 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
987 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900988 subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900989 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
990 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900991 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.hindi",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900992 "com.android.inputmethod.hindi", "DummyHindiIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900993 subtypes));
994 }
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900995
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900996 // a dummy Pinyin IME
997 {
Yohei Yukawab21220e2014-11-01 21:04:30 +0900998 final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800999 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001000 subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001001 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1002 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawab21220e2014-11-01 21:04:30 +09001003 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.pinyin",
1004 "com.android.apps.inputmethod.pinyin", "DummyPinyinIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001005 subtypes));
1006 }
Yohei Yukawa58980042014-02-27 17:10:00 +09001007
Yohei Yukawab21220e2014-11-01 21:04:30 +09001008 // a dummy Korean IME
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001009 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001010 final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001011 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001012 subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001013 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1014 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001015 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.korean",
Yohei Yukawab21220e2014-11-01 21:04:30 +09001016 "com.android.apps.inputmethod.korean", "DummyKoreanIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001017 subtypes));
1018 }
Yohei Yukawad77adfe2014-09-11 23:50:21 +09001019
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001020 // a dummy Latin IME
1021 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001022 final boolean isDefaultIme = contains(
1023 new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001024 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001025 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001026 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1027 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001028 subtypes.add(createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001029 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1030 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001031 subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001032 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1033 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001034 subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001035 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1036 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001037 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.latin",
Yohei Yukawab21220e2014-11-01 21:04:30 +09001038 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001039 subtypes));
1040 }
1041
1042 // a dummy Japanese IME
1043 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001044 final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001045 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001046 subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001047 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1048 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001049 subtypes.add(createDummyInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001050 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1051 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001052 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.japanese",
1053 "com.android.apps.inputmethod.japanese", "DummyJapaneseIme", !IS_AUX,
Yohei Yukawab21220e2014-11-01 21:04:30 +09001054 isDefaultIme, subtypes));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001055 }
1056
1057 return preinstalledImes;
Yohei Yukawad77adfe2014-09-11 23:50:21 +09001058 }
Yohei Yukawa174843a2015-06-26 18:02:54 -07001059
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001060 @Test
Yohei Yukawa174843a2015-06-26 18:02:54 -07001061 public void testGetSuitableLocalesForSpellChecker() throws Exception {
1062 {
1063 final ArrayList<Locale> locales =
1064 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US);
1065 assertEquals(3, locales.size());
1066 assertEquals(LOCALE_EN_US, locales.get(0));
1067 assertEquals(LOCALE_EN_GB, locales.get(1));
1068 assertEquals(LOCALE_EN, locales.get(2));
1069 }
1070
1071 {
1072 final ArrayList<Locale> locales =
1073 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB);
1074 assertEquals(3, locales.size());
1075 assertEquals(LOCALE_EN_GB, locales.get(0));
1076 assertEquals(LOCALE_EN_US, locales.get(1));
1077 assertEquals(LOCALE_EN, locales.get(2));
1078 }
1079
1080 {
1081 final ArrayList<Locale> locales =
1082 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN);
1083 assertEquals(3, locales.size());
1084 assertEquals(LOCALE_EN, locales.get(0));
1085 assertEquals(LOCALE_EN_US, locales.get(1));
1086 assertEquals(LOCALE_EN_GB, locales.get(2));
1087 }
1088
1089 {
1090 final ArrayList<Locale> locales =
1091 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN);
1092 assertEquals(4, locales.size());
1093 assertEquals(LOCALE_EN_IN, locales.get(0));
1094 assertEquals(LOCALE_EN_US, locales.get(1));
1095 assertEquals(LOCALE_EN_GB, locales.get(2));
1096 assertEquals(LOCALE_EN, locales.get(3));
1097 }
1098
1099 {
1100 final ArrayList<Locale> locales =
1101 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP);
1102 assertEquals(5, locales.size());
1103 assertEquals(LOCALE_JA_JP, locales.get(0));
1104 assertEquals(LOCALE_JA, locales.get(1));
1105 assertEquals(LOCALE_EN_US, locales.get(2));
1106 assertEquals(LOCALE_EN_GB, locales.get(3));
1107 assertEquals(Locale.ENGLISH, locales.get(4));
1108 }
1109
1110 // Test 3-letter language code.
1111 {
1112 final ArrayList<Locale> locales =
1113 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH);
1114 assertEquals(5, locales.size());
1115 assertEquals(LOCALE_FIL_PH, locales.get(0));
1116 assertEquals(LOCALE_FIL, locales.get(1));
1117 assertEquals(LOCALE_EN_US, locales.get(2));
1118 assertEquals(LOCALE_EN_GB, locales.get(3));
1119 assertEquals(Locale.ENGLISH, locales.get(4));
1120 }
1121
1122 // Test variant.
1123 {
1124 final ArrayList<Locale> locales =
1125 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH);
1126 assertEquals(6, locales.size());
1127 assertEquals(LOCALE_TH_TH_TH, locales.get(0));
1128 assertEquals(LOCALE_TH_TH, locales.get(1));
1129 assertEquals(LOCALE_TH, locales.get(2));
1130 assertEquals(LOCALE_EN_US, locales.get(3));
1131 assertEquals(LOCALE_EN_GB, locales.get(4));
1132 assertEquals(Locale.ENGLISH, locales.get(5));
1133 }
1134
1135 // Test Locale extension.
1136 {
1137 final Locale localeWithoutVariant = LOCALE_JA_JP;
1138 final Locale localeWithVariant = new Locale.Builder()
1139 .setLocale(LOCALE_JA_JP)
1140 .setExtension('x', "android")
1141 .build();
1142 assertFalse(localeWithoutVariant.equals(localeWithVariant));
1143
1144 final ArrayList<Locale> locales =
1145 InputMethodUtils.getSuitableLocalesForSpellChecker(localeWithVariant);
1146 assertEquals(5, locales.size());
1147 assertEquals(LOCALE_JA_JP, locales.get(0));
1148 assertEquals(LOCALE_JA, locales.get(1));
1149 assertEquals(LOCALE_EN_US, locales.get(2));
1150 assertEquals(LOCALE_EN_GB, locales.get(3));
1151 assertEquals(Locale.ENGLISH, locales.get(4));
1152 }
1153 }
Seigo Nonaka2028dda2015-07-06 17:41:24 +09001154
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001155 @Test
Seigo Nonaka2028dda2015-07-06 17:41:24 +09001156 public void testParseInputMethodsAndSubtypesString() {
1157 // Trivial cases.
1158 {
1159 assertTrue(InputMethodUtils.parseInputMethodsAndSubtypesString("").isEmpty());
1160 assertTrue(InputMethodUtils.parseInputMethodsAndSubtypesString(null).isEmpty());
1161 }
1162
1163 // No subtype cases.
1164 {
1165 ArrayMap<String, ArraySet<String>> r =
1166 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0");
1167 assertEquals(1, r.size());
1168 assertTrue(r.containsKey("ime0"));
1169 assertTrue(r.get("ime0").isEmpty());
1170 }
1171 {
1172 ArrayMap<String, ArraySet<String>> r =
1173 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0:ime1");
1174 assertEquals(2, r.size());
1175 assertTrue(r.containsKey("ime0"));
1176 assertTrue(r.get("ime0").isEmpty());
1177 assertTrue(r.containsKey("ime1"));
1178 assertTrue(r.get("ime1").isEmpty());
1179 }
1180
1181 // Input metho IDs and their subtypes.
1182 {
1183 ArrayMap<String, ArraySet<String>> r =
1184 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0");
1185 assertEquals(1, r.size());
1186 assertTrue(r.containsKey("ime0"));
1187 ArraySet<String> subtypes = r.get("ime0");
1188 assertEquals(1, subtypes.size());
1189 assertTrue(subtypes.contains("subtype0"));
1190 }
1191 {
1192 ArrayMap<String, ArraySet<String>> r =
1193 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0;subtype0");
1194 assertEquals(1, r.size());
1195 assertTrue(r.containsKey("ime0"));
1196 ArraySet<String> subtypes = r.get("ime0");
1197 assertEquals(1, subtypes.size());
1198 assertTrue(subtypes.contains("subtype0"));
1199 }
1200 {
1201 ArrayMap<String, ArraySet<String>> r =
1202 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0;subtype1");
1203 assertEquals(1, r.size());
1204 assertTrue(r.containsKey("ime0"));
1205 ArraySet<String> subtypes = r.get("ime0");
1206 assertEquals(2, subtypes.size());
1207 assertTrue(subtypes.contains("subtype0"));
1208 assertTrue(subtypes.contains("subtype1"));
1209 }
1210 {
1211 ArrayMap<String, ArraySet<String>> r =
1212 InputMethodUtils.parseInputMethodsAndSubtypesString(
1213 "ime0;subtype0:ime1;subtype1");
1214 assertEquals(2, r.size());
1215 assertTrue(r.containsKey("ime0"));
1216 assertTrue(r.containsKey("ime1"));
1217 ArraySet<String> subtypes0 = r.get("ime0");
1218 assertEquals(1, subtypes0.size());
1219 assertTrue(subtypes0.contains("subtype0"));
1220
1221 ArraySet<String> subtypes1 = r.get("ime1");
1222 assertEquals(1, subtypes1.size());
1223 assertTrue(subtypes1.contains("subtype1"));
1224 }
1225 {
1226 ArrayMap<String, ArraySet<String>> r =
1227 InputMethodUtils.parseInputMethodsAndSubtypesString(
1228 "ime0;subtype0;subtype1:ime1;subtype2");
1229 assertEquals(2, r.size());
1230 assertTrue(r.containsKey("ime0"));
1231 assertTrue(r.containsKey("ime1"));
1232 ArraySet<String> subtypes0 = r.get("ime0");
1233 assertEquals(2, subtypes0.size());
1234 assertTrue(subtypes0.contains("subtype0"));
1235 assertTrue(subtypes0.contains("subtype1"));
1236
1237 ArraySet<String> subtypes1 = r.get("ime1");
1238 assertEquals(1, subtypes1.size());
1239 assertTrue(subtypes1.contains("subtype2"));
1240 }
1241 {
1242 ArrayMap<String, ArraySet<String>> r =
1243 InputMethodUtils.parseInputMethodsAndSubtypesString(
1244 "ime0;subtype0;subtype1:ime1;subtype1;subtype2");
1245 assertEquals(2, r.size());
1246 assertTrue(r.containsKey("ime0"));
1247 assertTrue(r.containsKey("ime1"));
1248 ArraySet<String> subtypes0 = r.get("ime0");
1249 assertEquals(2, subtypes0.size());
1250 assertTrue(subtypes0.contains("subtype0"));
1251 assertTrue(subtypes0.contains("subtype1"));
1252
1253 ArraySet<String> subtypes1 = r.get("ime1");
1254 assertEquals(2, subtypes1.size());
1255 assertTrue(subtypes0.contains("subtype1"));
1256 assertTrue(subtypes1.contains("subtype2"));
1257 }
1258 {
1259 ArrayMap<String, ArraySet<String>> r =
1260 InputMethodUtils.parseInputMethodsAndSubtypesString(
1261 "ime0;subtype0;subtype1:ime1;subtype1;subtype2:ime2");
1262 assertEquals(3, r.size());
1263 assertTrue(r.containsKey("ime0"));
1264 assertTrue(r.containsKey("ime1"));
1265 assertTrue(r.containsKey("ime2"));
1266 ArraySet<String> subtypes0 = r.get("ime0");
1267 assertEquals(2, subtypes0.size());
1268 assertTrue(subtypes0.contains("subtype0"));
1269 assertTrue(subtypes0.contains("subtype1"));
1270
1271 ArraySet<String> subtypes1 = r.get("ime1");
1272 assertEquals(2, subtypes1.size());
1273 assertTrue(subtypes0.contains("subtype1"));
1274 assertTrue(subtypes1.contains("subtype2"));
1275
1276 ArraySet<String> subtypes2 = r.get("ime2");
1277 assertTrue(subtypes2.isEmpty());
1278 }
1279 }
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001280
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001281 @Test
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001282 public void testbuildInputMethodsAndSubtypesString() {
1283 {
1284 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1285 assertEquals("", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
1286 }
1287 {
1288 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001289 map.put("ime0", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001290 assertEquals("ime0", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
1291 }
1292 {
1293 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1294 ArraySet<String> subtypes1 = new ArraySet<>();
1295 subtypes1.add("subtype0");
1296 map.put("ime0", subtypes1);
1297 assertEquals("ime0;subtype0", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
1298 }
1299 {
1300 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1301 ArraySet<String> subtypes1 = new ArraySet<>();
1302 subtypes1.add("subtype0");
1303 subtypes1.add("subtype1");
1304 map.put("ime0", subtypes1);
1305
1306 // We do not expect what order will be used to concatenate items in
1307 // InputMethodUtils.buildInputMethodsAndSubtypesString() hence enumerate all possible
1308 // permutations here.
1309 ArraySet<String> validSequences = new ArraySet<>();
1310 validSequences.add("ime0;subtype0;subtype1");
1311 validSequences.add("ime0;subtype1;subtype0");
1312 assertTrue(validSequences.contains(
1313 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1314 }
1315 {
1316 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001317 map.put("ime0", new ArraySet<>());
1318 map.put("ime1", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001319
1320 ArraySet<String> validSequences = new ArraySet<>();
1321 validSequences.add("ime0:ime1");
1322 validSequences.add("ime1:ime0");
1323 assertTrue(validSequences.contains(
1324 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1325 }
1326 {
1327 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1328 ArraySet<String> subtypes1 = new ArraySet<>();
1329 subtypes1.add("subtype0");
1330 map.put("ime0", subtypes1);
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001331 map.put("ime1", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001332
1333 ArraySet<String> validSequences = new ArraySet<>();
1334 validSequences.add("ime0;subtype0:ime1");
1335 validSequences.add("ime1;ime0;subtype0");
1336 assertTrue(validSequences.contains(
1337 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1338 }
1339 {
1340 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1341 ArraySet<String> subtypes1 = new ArraySet<>();
1342 subtypes1.add("subtype0");
1343 subtypes1.add("subtype1");
1344 map.put("ime0", subtypes1);
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001345 map.put("ime1", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001346
1347 ArraySet<String> validSequences = new ArraySet<>();
1348 validSequences.add("ime0;subtype0;subtype1:ime1");
1349 validSequences.add("ime0;subtype1;subtype0:ime1");
1350 validSequences.add("ime1:ime0;subtype0;subtype1");
1351 validSequences.add("ime1:ime0;subtype1;subtype0");
1352 assertTrue(validSequences.contains(
1353 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1354 }
1355 {
1356 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1357 ArraySet<String> subtypes1 = new ArraySet<>();
1358 subtypes1.add("subtype0");
1359 map.put("ime0", subtypes1);
1360
1361 ArraySet<String> subtypes2 = new ArraySet<>();
1362 subtypes2.add("subtype1");
1363 map.put("ime1", subtypes2);
1364
1365 ArraySet<String> validSequences = new ArraySet<>();
1366 validSequences.add("ime0;subtype0:ime1;subtype1");
1367 validSequences.add("ime1;subtype1:ime0;subtype0");
1368 assertTrue(validSequences.contains(
1369 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1370 }
1371 {
1372 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1373 ArraySet<String> subtypes1 = new ArraySet<>();
1374 subtypes1.add("subtype0");
1375 subtypes1.add("subtype1");
1376 map.put("ime0", subtypes1);
1377
1378 ArraySet<String> subtypes2 = new ArraySet<>();
1379 subtypes2.add("subtype2");
1380 subtypes2.add("subtype3");
1381 map.put("ime1", subtypes2);
1382
1383 ArraySet<String> validSequences = new ArraySet<>();
1384 validSequences.add("ime0;subtype0;subtype1:ime1;subtype2;subtype3");
1385 validSequences.add("ime0;subtype1;subtype0:ime1;subtype2;subtype3");
1386 validSequences.add("ime0;subtype0;subtype1:ime1;subtype3;subtype2");
1387 validSequences.add("ime0;subtype1;subtype0:ime1;subtype3;subtype2");
1388 validSequences.add("ime1;subtype2;subtype3:ime0;subtype0;subtype1");
1389 validSequences.add("ime2;subtype3;subtype2:ime0;subtype0;subtype1");
1390 validSequences.add("ime3;subtype2;subtype3:ime0;subtype1;subtype0");
1391 validSequences.add("ime4;subtype3;subtype2:ime0;subtype1;subtype0");
1392 assertTrue(validSequences.contains(
1393 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1394 }
1395 }
Yohei Yukawa226c4bb2015-12-03 15:21:15 -08001396
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001397 @Test
Yohei Yukawa226c4bb2015-12-03 15:21:15 -08001398 public void testConstructLocaleFromString() throws Exception {
1399 assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en"));
1400 assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US"));
1401 assertEquals(new Locale("en", "US", "POSIX"),
1402 InputMethodUtils.constructLocaleFromString("en_US_POSIX"));
1403
1404 // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
1405 // support three letter language codes, and used "tl" (Tagalog) as the language string for
1406 // "fil" (Filipino).
1407 assertEquals(new Locale("fil"), InputMethodUtils.constructLocaleFromString("tl"));
1408 assertEquals(new Locale("fil", "PH"), InputMethodUtils.constructLocaleFromString("tl_PH"));
1409 assertEquals(new Locale("fil", "PH", "POSIX"),
1410 InputMethodUtils.constructLocaleFromString("tl_PH_POSIX"));
1411
1412 // So far rejecting an invalid/unexpected locale string is out of the scope of this method.
1413 assertEquals(new Locale("a"), InputMethodUtils.constructLocaleFromString("a"));
1414 assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c"));
1415 assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US"));
1416 }
Yohei Yukawacf68d522017-12-12 09:33:26 -08001417
1418 @Test
1419 public void testIsSoftInputModeStateVisibleAllowed() {
1420 // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always
1421 // allowed, regardless of the focused view state.
1422 assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1423 Build.VERSION_CODES.O_MR1, 0));
1424 assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1425 Build.VERSION_CODES.O_MR1, CONTROL_WINDOW_VIEW_HAS_FOCUS));
1426 assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1427 Build.VERSION_CODES.O_MR1,
1428 CONTROL_WINDOW_VIEW_HAS_FOCUS | CONTROL_WINDOW_IS_TEXT_EDITOR));
1429
1430 // On P+ devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are allowed only
1431 // when there is a focused View and its View#onCheckIsTextEditor() returns true.
1432 assertFalse(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1433 Build.VERSION_CODES.P, 0));
1434 assertFalse(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1435 Build.VERSION_CODES.P, CONTROL_WINDOW_VIEW_HAS_FOCUS));
1436 assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1437 Build.VERSION_CODES.P,
1438 CONTROL_WINDOW_VIEW_HAS_FOCUS | CONTROL_WINDOW_IS_TEXT_EDITOR));
1439
1440 }
1441
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09001442}