blob: 1fd24e3f237ecc121c581b206b8423279da70539 [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 Yukawa9c372192018-03-20 22:54:56 -0700102 assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US,
103 "DummyDefaultEnKeyboardIme");
104 assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US,
105 "DummyDefaultEnKeyboardIme");
Yohei Yukawad77adfe2014-09-11 23:50:21 +0900106
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900107 // locale: en_GB
Yohei Yukawab21220e2014-11-01 21:04:30 +0900108 assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800109 "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900110 assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800111 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900112 "DummyNonDefaultAutoVoiceIme1");
Yohei Yukawa9c372192018-03-20 22:54:56 -0700113 assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB,
114 "DummyDefaultEnKeyboardIme");
115 assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB,
116 "DummyDefaultEnKeyboardIme");
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900117
118 // locale: ja_JP
Yohei Yukawab21220e2014-11-01 21:04:30 +0900119 assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800120 "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900121 assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800122 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900123 "DummyNonDefaultAutoVoiceIme1");
Yohei Yukawa9c372192018-03-20 22:54:56 -0700124 assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP,
125 "DummyDefaultEnKeyboardIme");
126 assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP,
127 "DummyDefaultEnKeyboardIme");
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900128 }
129
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800130 @Test
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900131 public void testKeyboardImes() throws Exception {
132 // locale: en_US
Yohei Yukawab21220e2014-11-01 21:04:30 +0900133 assertDefaultEnabledImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800134 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Yohei Yukawa9c372192018-03-20 22:54:56 -0700135 assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US,
136 "com.android.apps.inputmethod.latin");
Yohei Yukawabca817b2014-09-11 16:59:31 +0900137
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900138 // locale: en_GB
Yohei Yukawab21220e2014-11-01 21:04:30 +0900139 assertDefaultEnabledImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800140 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Yohei Yukawa9c372192018-03-20 22:54:56 -0700141 assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB,
142 "com.android.apps.inputmethod.latin");
Yohei Yukawabca817b2014-09-11 16:59:31 +0900143
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900144 // locale: en_IN
Yohei Yukawab21220e2014-11-01 21:04:30 +0900145 assertDefaultEnabledImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800146 "com.android.apps.inputmethod.hindi",
Yohei Yukawab21220e2014-11-01 21:04:30 +0900147 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Yohei Yukawa9c372192018-03-20 22:54:56 -0700148 assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN,
149 "com.android.apps.inputmethod.hindi",
150 "com.android.apps.inputmethod.latin");
Yohei Yukawad77adfe2014-09-11 23:50:21 +0900151
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900152 // locale: hi
Yohei Yukawab21220e2014-11-01 21:04:30 +0900153 assertDefaultEnabledImes(getSamplePreinstalledImes("hi"), LOCALE_HI,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800154 "com.android.apps.inputmethod.hindi", "com.android.apps.inputmethod.latin",
155 "com.android.apps.inputmethod.voice");
Yohei Yukawa9c372192018-03-20 22:54:56 -0700156 assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("hi"), LOCALE_HI,
157 "com.android.apps.inputmethod.hindi", "com.android.apps.inputmethod.latin");
Yohei Yukawad77adfe2014-09-11 23:50:21 +0900158
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900159 // locale: ja_JP
Yohei Yukawab21220e2014-11-01 21:04:30 +0900160 assertDefaultEnabledImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800161 "com.android.apps.inputmethod.japanese", "com.android.apps.inputmethod.voice");
Yohei Yukawa9c372192018-03-20 22:54:56 -0700162 assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP,
163 "com.android.apps.inputmethod.japanese");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900164
165 // locale: zh_CN
166 assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800167 "com.android.apps.inputmethod.pinyin", "com.android.apps.inputmethod.voice");
Yohei Yukawa9c372192018-03-20 22:54:56 -0700168 assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN,
169 "com.android.apps.inputmethod.pinyin");
Yohei Yukawab21220e2014-11-01 21:04:30 +0900170
171 // locale: zh_TW
172 // Note: In this case, no IME is suitable for the system locale. Hence we will pick up a
173 // fallback IME regardless of the "default" attribute.
174 assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800175 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
Yohei Yukawa9c372192018-03-20 22:54:56 -0700176 assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW,
177 "com.android.apps.inputmethod.latin");
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900178 }
179
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800180 @Test
Yohei Yukawa58980042014-02-27 17:10:00 +0900181 public void testParcelable() throws Exception {
Yohei Yukawab21220e2014-11-01 21:04:30 +0900182 final ArrayList<InputMethodInfo> originalList = getSamplePreinstalledImes("en-rUS");
Yohei Yukawa58980042014-02-27 17:10:00 +0900183 final List<InputMethodInfo> clonedList = cloneViaParcel(originalList);
184 assertNotNull(clonedList);
Yohei Yukawac18cd392014-03-03 13:08:34 +0900185 final List<InputMethodInfo> clonedClonedList = cloneViaParcel(clonedList);
186 assertNotNull(clonedClonedList);
Yohei Yukawa58980042014-02-27 17:10:00 +0900187 assertEquals(originalList, clonedList);
Yohei Yukawac18cd392014-03-03 13:08:34 +0900188 assertEquals(clonedList, clonedClonedList);
189 assertEquals(originalList.size(), clonedList.size());
190 assertEquals(clonedList.size(), clonedClonedList.size());
Yohei Yukawa58980042014-02-27 17:10:00 +0900191 for (int imeIndex = 0; imeIndex < originalList.size(); ++imeIndex) {
Yohei Yukawac18cd392014-03-03 13:08:34 +0900192 verifyEquality(originalList.get(imeIndex), clonedList.get(imeIndex));
193 verifyEquality(clonedList.get(imeIndex), clonedClonedList.get(imeIndex));
Yohei Yukawa58980042014-02-27 17:10:00 +0900194 }
195 }
196
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800197 @Test
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900198 public void testGetImplicitlyApplicableSubtypesLocked() throws Exception {
199 final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
200 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
201 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
202 final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
203 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
204 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawae985c242016-02-24 18:27:04 -0800205 final InputMethodSubtype nonAutoEnIN = createDummyInputMethodSubtype("en_IN",
206 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
207 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900208 final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA",
209 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
210 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
211 final InputMethodSubtype nonAutoFr = createDummyInputMethodSubtype("fr_CA",
212 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
213 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
214 final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
215 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
216 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
217 final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
218 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
219 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
220 final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
221 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
222 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
223 final InputMethodSubtype autoSubtype = createDummyInputMethodSubtype("auto",
224 SUBTYPE_MODE_KEYBOARD, !IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
225 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
226 final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja",
227 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
228 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800229 final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi",
230 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
231 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa238faad2016-03-11 10:39:51 -0800232 final InputMethodSubtype nonAutoSrCyrl = createDummyInputMethodSubtype("sr",
233 "sr-Cyrl", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
234 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
235 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
236 final InputMethodSubtype nonAutoSrLatn = createDummyInputMethodSubtype("sr_ZZ",
237 "sr-Latn", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
238 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
239 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800240 final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en",
241 SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
242 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800243 final InputMethodSubtype nonAutoHandwritingFr = createDummyInputMethodSubtype("fr",
244 SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
245 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawa238faad2016-03-11 10:39:51 -0800246 final InputMethodSubtype nonAutoHandwritingSrCyrl = createDummyInputMethodSubtype("sr",
247 "sr-Cyrl", SUBTYPE_MODE_HANDWRITING, !IS_AUX,
248 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
249 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
250 final InputMethodSubtype nonAutoHandwritingSrLatn = createDummyInputMethodSubtype("sr_ZZ",
251 "sr-Latn", SUBTYPE_MODE_HANDWRITING, !IS_AUX,
252 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
253 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900254 final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype =
255 createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
256 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
257 IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
258 final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2 =
259 createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
260 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
261 IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
262
263 // Make sure that an automatic subtype (overridesImplicitlyEnabledSubtype:true) is
264 // selected no matter what locale is specified.
265 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800266 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900267 subtypes.add(nonAutoEnUS);
268 subtypes.add(nonAutoEnGB);
269 subtypes.add(nonAutoJa);
270 subtypes.add(nonAutoFil);
271 subtypes.add(autoSubtype); // overridesImplicitlyEnabledSubtype == true
272 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
273 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800274 subtypes.add(nonAutoHandwritingEn);
275 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900276 final InputMethodInfo imi = createDummyInputMethodInfo(
277 "com.android.apps.inputmethod.latin",
278 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
279 subtypes);
280 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800281 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800282 getResourcesForLocales(LOCALE_EN_US), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900283 assertEquals(1, result.size());
284 verifyEquality(autoSubtype, result.get(0));
285 }
286
287 // Make sure that a subtype whose locale is exactly equal to the specified locale is
288 // selected as long as there is no no automatic subtype
289 // (overridesImplicitlyEnabledSubtype:true) in the given list.
290 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800291 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900292 subtypes.add(nonAutoEnUS); // locale == "en_US"
293 subtypes.add(nonAutoEnGB);
294 subtypes.add(nonAutoJa);
295 subtypes.add(nonAutoFil);
296 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
297 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800298 subtypes.add(nonAutoHandwritingEn);
299 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900300 final InputMethodInfo imi = createDummyInputMethodInfo(
301 "com.android.apps.inputmethod.latin",
302 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
303 subtypes);
304 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800305 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800306 getResourcesForLocales(LOCALE_EN_US), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800307 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900308 verifyEquality(nonAutoEnUS, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800309 verifyEquality(nonAutoHandwritingEn, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900310 }
311
312 // Make sure that a subtype whose locale is exactly equal to the specified locale is
313 // selected as long as there is no automatic subtype
314 // (overridesImplicitlyEnabledSubtype:true) in the given list.
315 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800316 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900317 subtypes.add(nonAutoEnUS);
318 subtypes.add(nonAutoEnGB); // locale == "en_GB"
319 subtypes.add(nonAutoJa);
320 subtypes.add(nonAutoFil);
321 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800322 subtypes.add(nonAutoHandwritingEn);
323 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900324 final InputMethodInfo imi = createDummyInputMethodInfo(
325 "com.android.apps.inputmethod.latin",
326 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
327 subtypes);
328 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800329 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800330 getResourcesForLocales(LOCALE_EN_GB), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800331 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900332 verifyEquality(nonAutoEnGB, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800333 verifyEquality(nonAutoHandwritingEn, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900334 }
335
336 // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and
337 // any subtype whose locale is exactly equal to the specified locale in the given list,
338 // try to find a subtype whose language is equal to the language part of the given locale.
339 // Here make sure that a subtype (locale: "fr_CA") can be found with locale: "fr".
340 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800341 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900342 subtypes.add(nonAutoFrCA); // locale == "fr_CA"
343 subtypes.add(nonAutoJa);
344 subtypes.add(nonAutoFil);
345 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
346 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800347 subtypes.add(nonAutoHandwritingEn);
348 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900349 final InputMethodInfo imi = createDummyInputMethodInfo(
350 "com.android.apps.inputmethod.latin",
351 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
352 subtypes);
353 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800354 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800355 getResourcesForLocales(LOCALE_FR), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800356 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900357 verifyEquality(nonAutoFrCA, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800358 verifyEquality(nonAutoHandwritingFr, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900359 }
360 // Then make sure that a subtype (locale: "fr") can be found with locale: "fr_CA".
361 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800362 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900363 subtypes.add(nonAutoFr); // locale == "fr"
364 subtypes.add(nonAutoJa);
365 subtypes.add(nonAutoFil);
366 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
367 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800368 subtypes.add(nonAutoHandwritingEn);
369 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900370 final InputMethodInfo imi = createDummyInputMethodInfo(
371 "com.android.apps.inputmethod.latin",
372 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
373 subtypes);
374 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800375 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800376 getResourcesForLocales(LOCALE_FR_CA), imi);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800377 assertEquals(2, result.size());
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900378 verifyEquality(nonAutoFrCA, result.get(0));
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800379 verifyEquality(nonAutoHandwritingFr, result.get(1));
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900380 }
381
382 // Make sure that subtypes which have "EnabledWhenDefaultIsNotAsciiCapable" in its
383 // extra value is selected if and only if all other selected IMEs are not AsciiCapable.
384 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800385 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900386 subtypes.add(nonAutoEnUS);
387 subtypes.add(nonAutoJa); // not ASCII capable
388 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
389 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800390 subtypes.add(nonAutoHandwritingEn);
391 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900392 final InputMethodInfo imi = createDummyInputMethodInfo(
393 "com.android.apps.inputmethod.latin",
394 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
395 subtypes);
396 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800397 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800398 getResourcesForLocales(LOCALE_JA_JP), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900399 assertEquals(3, result.size());
400 verifyEquality(nonAutoJa, result.get(0));
401 verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, result.get(1));
402 verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2, result.get(2));
403 }
404
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800405 // Make sure that if there is no subtype that matches the language requested, then we just
406 // use the first keyboard subtype.
407 {
408 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
409 subtypes.add(nonAutoHi);
410 subtypes.add(nonAutoEnUS);
411 subtypes.add(nonAutoHandwritingEn);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800412 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800413 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
414 final InputMethodInfo imi = createDummyInputMethodInfo(
415 "com.android.apps.inputmethod.latin",
416 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
417 subtypes);
418 final ArrayList<InputMethodSubtype> result =
419 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
420 getResourcesForLocales(LOCALE_JA_JP), imi);
421 assertEquals(1, result.size());
422 verifyEquality(nonAutoHi, result.get(0));
423 }
424 {
425 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
426 subtypes.add(nonAutoEnUS);
427 subtypes.add(nonAutoHi);
428 subtypes.add(nonAutoHandwritingEn);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800429 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800430 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
431 final InputMethodInfo imi = createDummyInputMethodInfo(
432 "com.android.apps.inputmethod.latin",
433 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
434 subtypes);
435 final ArrayList<InputMethodSubtype> result =
436 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
437 getResourcesForLocales(LOCALE_JA_JP), imi);
438 assertEquals(1, result.size());
439 verifyEquality(nonAutoEnUS, result.get(0));
440 }
441 {
442 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
443 subtypes.add(nonAutoHandwritingEn);
Yohei Yukawa80861ff2016-03-11 01:08:52 -0800444 subtypes.add(nonAutoHandwritingFr);
Yohei Yukawa42275bc2016-03-03 00:34:27 -0800445 subtypes.add(nonAutoEnUS);
446 subtypes.add(nonAutoHi);
447 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
448 final InputMethodInfo imi = createDummyInputMethodInfo(
449 "com.android.apps.inputmethod.latin",
450 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
451 subtypes);
452 final ArrayList<InputMethodSubtype> result =
453 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
454 getResourcesForLocales(LOCALE_JA_JP), imi);
455 assertEquals(1, result.size());
456 verifyEquality(nonAutoEnUS, result.get(0));
457 }
458
Yohei Yukawa238faad2016-03-11 10:39:51 -0800459 // Make sure that both language and script are taken into account to find the best matching
460 // subtype.
461 {
462 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
463 subtypes.add(nonAutoEnUS);
464 subtypes.add(nonAutoSrCyrl);
465 subtypes.add(nonAutoSrLatn);
466 subtypes.add(nonAutoHandwritingEn);
467 subtypes.add(nonAutoHandwritingFr);
468 subtypes.add(nonAutoHandwritingSrCyrl);
469 subtypes.add(nonAutoHandwritingSrLatn);
470 final InputMethodInfo imi = createDummyInputMethodInfo(
471 "com.android.apps.inputmethod.latin",
472 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
473 subtypes);
474 final ArrayList<InputMethodSubtype> result =
475 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
476 getResourcesForLocales(Locale.forLanguageTag("sr-Latn-RS")), imi);
477 assertEquals(2, result.size());
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800478 assertThat(nonAutoSrLatn, is(in(result)));
479 assertThat(nonAutoHandwritingSrLatn, is(in(result)));
Yohei Yukawa238faad2016-03-11 10:39:51 -0800480 }
481 {
482 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
483 subtypes.add(nonAutoEnUS);
484 subtypes.add(nonAutoSrCyrl);
485 subtypes.add(nonAutoSrLatn);
486 subtypes.add(nonAutoHandwritingEn);
487 subtypes.add(nonAutoHandwritingFr);
488 subtypes.add(nonAutoHandwritingSrCyrl);
489 subtypes.add(nonAutoHandwritingSrLatn);
490 final InputMethodInfo imi = createDummyInputMethodInfo(
491 "com.android.apps.inputmethod.latin",
492 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
493 subtypes);
494 final ArrayList<InputMethodSubtype> result =
495 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
496 getResourcesForLocales(Locale.forLanguageTag("sr-Cyrl-RS")), imi);
497 assertEquals(2, result.size());
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800498 assertThat(nonAutoSrCyrl, is(in(result)));
499 assertThat(nonAutoHandwritingSrCyrl, is(in(result)));
Yohei Yukawa238faad2016-03-11 10:39:51 -0800500 }
501
502 // Make sure that secondary locales are taken into account to find the best matching
503 // subtype.
504 {
505 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
506 subtypes.add(nonAutoEnUS);
507 subtypes.add(nonAutoEnGB);
508 subtypes.add(nonAutoSrCyrl);
509 subtypes.add(nonAutoSrLatn);
510 subtypes.add(nonAutoFr);
511 subtypes.add(nonAutoFrCA);
512 subtypes.add(nonAutoHandwritingEn);
513 subtypes.add(nonAutoHandwritingFr);
514 subtypes.add(nonAutoHandwritingSrCyrl);
515 subtypes.add(nonAutoHandwritingSrLatn);
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 =
521 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
522 getResourcesForLocales(
523 Locale.forLanguageTag("sr-Latn-RS-x-android"),
524 Locale.forLanguageTag("ja-JP"),
525 Locale.forLanguageTag("fr-FR"),
526 Locale.forLanguageTag("en-GB"),
527 Locale.forLanguageTag("en-US")),
528 imi);
529 assertEquals(6, result.size());
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800530 assertThat(nonAutoEnGB, is(in(result)));
531 assertThat(nonAutoFr, is(in(result)));
532 assertThat(nonAutoSrLatn, is(in(result)));
533 assertThat(nonAutoHandwritingEn, is(in(result)));
534 assertThat(nonAutoHandwritingFr, is(in(result)));
535 assertThat(nonAutoHandwritingSrLatn, is(in(result)));
Yohei Yukawa238faad2016-03-11 10:39:51 -0800536 }
537
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900538 // Make sure that 3-letter language code can be handled.
539 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800540 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900541 subtypes.add(nonAutoEnUS);
542 subtypes.add(nonAutoFil);
543 final InputMethodInfo imi = createDummyInputMethodInfo(
544 "com.android.apps.inputmethod.latin",
545 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
546 subtypes);
547 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800548 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800549 getResourcesForLocales(LOCALE_FIL_PH), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900550 assertEquals(1, result.size());
551 verifyEquality(nonAutoFil, result.get(0));
552 }
553
554 // Make sure that we never end up matching "fi" (finnish) with "fil" (filipino).
555 // Also make sure that the first subtype will be used as the last-resort candidate.
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(nonAutoJa);
559 subtypes.add(nonAutoEnUS);
560 subtypes.add(nonAutoFil);
561 final InputMethodInfo imi = createDummyInputMethodInfo(
562 "com.android.apps.inputmethod.latin",
563 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
564 subtypes);
565 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800566 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800567 getResourcesForLocales(LOCALE_FI), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900568 assertEquals(1, result.size());
569 verifyEquality(nonAutoJa, result.get(0));
570 }
571
572 // Make sure that "in" and "id" conversion is taken into account.
573 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800574 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900575 subtypes.add(nonAutoIn);
576 subtypes.add(nonAutoEnUS);
577 final InputMethodInfo imi = createDummyInputMethodInfo(
578 "com.android.apps.inputmethod.latin",
579 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
580 subtypes);
581 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800582 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800583 getResourcesForLocales(LOCALE_IN), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900584 assertEquals(1, result.size());
585 verifyEquality(nonAutoIn, result.get(0));
586 }
587 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800588 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900589 subtypes.add(nonAutoIn);
590 subtypes.add(nonAutoEnUS);
591 final InputMethodInfo imi = createDummyInputMethodInfo(
592 "com.android.apps.inputmethod.latin",
593 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
594 subtypes);
595 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800596 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800597 getResourcesForLocales(LOCALE_ID), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900598 assertEquals(1, result.size());
599 verifyEquality(nonAutoIn, result.get(0));
600 }
601 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800602 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900603 subtypes.add(nonAutoId);
604 subtypes.add(nonAutoEnUS);
605 final InputMethodInfo imi = createDummyInputMethodInfo(
606 "com.android.apps.inputmethod.latin",
607 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
608 subtypes);
609 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800610 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800611 getResourcesForLocales(LOCALE_IN), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900612 assertEquals(1, result.size());
613 verifyEquality(nonAutoId, result.get(0));
614 }
615 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800616 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900617 subtypes.add(nonAutoId);
618 subtypes.add(nonAutoEnUS);
619 final InputMethodInfo imi = createDummyInputMethodInfo(
620 "com.android.apps.inputmethod.latin",
621 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
622 subtypes);
623 final ArrayList<InputMethodSubtype> result =
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800624 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
Yohei Yukawafc843712016-02-24 00:27:34 -0800625 getResourcesForLocales(LOCALE_ID), imi);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900626 assertEquals(1, result.size());
627 verifyEquality(nonAutoId, result.get(0));
628 }
Yohei Yukawae985c242016-02-24 18:27:04 -0800629
630 // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and the system
631 // provides multiple locales, we try to enable multiple subtypes.
632 {
633 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
634 subtypes.add(nonAutoEnUS);
635 subtypes.add(nonAutoFrCA);
636 subtypes.add(nonAutoIn);
637 subtypes.add(nonAutoJa);
638 subtypes.add(nonAutoFil);
639 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
640 subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
641 final InputMethodInfo imi = createDummyInputMethodInfo(
642 "com.android.apps.inputmethod.latin",
643 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
644 subtypes);
645 final ArrayList<InputMethodSubtype> result =
646 InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
647 getResourcesForLocales(LOCALE_FR, LOCALE_EN_US, LOCALE_JA_JP), imi);
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800648 assertThat(nonAutoFrCA, is(in(result)));
649 assertThat(nonAutoEnUS, is(in(result)));
650 assertThat(nonAutoJa, is(in(result)));
651 assertThat(nonAutoIn, not(is(in(result))));
652 assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(is(in(result))));
653 assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(is(in(result))));
Yohei Yukawae985c242016-02-24 18:27:04 -0800654 }
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900655 }
656
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800657 @Test
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900658 public void testContainsSubtypeOf() throws Exception {
659 final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
660 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
661 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
662 final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
663 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
664 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
665 final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
666 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
667 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
668 final InputMethodSubtype nonAutoFilPH = createDummyInputMethodSubtype("fil_PH",
669 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
670 IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
671 final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
672 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
673 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
674 final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
675 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
676 IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
677
678 final boolean CHECK_COUNTRY = true;
679
680 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800681 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900682 subtypes.add(nonAutoEnUS);
683 final InputMethodInfo imi = createDummyInputMethodInfo(
684 "com.android.apps.inputmethod.latin",
685 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
686 subtypes);
687
688 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY,
689 SUBTYPE_MODE_KEYBOARD));
690 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, CHECK_COUNTRY,
691 SUBTYPE_MODE_KEYBOARD));
692 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
693 SUBTYPE_MODE_KEYBOARD));
694 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
695 SUBTYPE_MODE_KEYBOARD));
696 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
697 SUBTYPE_MODE_VOICE));
698 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
699 SUBTYPE_MODE_VOICE));
700 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
701 SUBTYPE_MODE_ANY));
702 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
703 SUBTYPE_MODE_ANY));
704
705 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, !CHECK_COUNTRY,
706 SUBTYPE_MODE_KEYBOARD));
707 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, CHECK_COUNTRY,
708 SUBTYPE_MODE_KEYBOARD));
709 }
710
711 // Make sure that 3-letter language code ("fil") 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(nonAutoFil);
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 assertTrue(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 assertFalse(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 3-letter language code ("fil_PH") can be handled.
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(nonAutoFilPH);
742 final InputMethodInfo imi = createDummyInputMethodInfo(
743 "com.android.apps.inputmethod.latin",
744 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
745 subtypes);
746 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
747 SUBTYPE_MODE_KEYBOARD));
748 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
749 SUBTYPE_MODE_KEYBOARD));
750 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
751 SUBTYPE_MODE_KEYBOARD));
752 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
753 SUBTYPE_MODE_KEYBOARD));
754
755 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
756 SUBTYPE_MODE_KEYBOARD));
757 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
758 SUBTYPE_MODE_KEYBOARD));
759 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
760 SUBTYPE_MODE_KEYBOARD));
761 assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
762 SUBTYPE_MODE_KEYBOARD));
763 }
764
765 // Make sure that a subtype whose locale is "in" can be queried with "id".
766 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800767 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900768 subtypes.add(nonAutoIn);
769 subtypes.add(nonAutoEnUS);
770 final InputMethodInfo imi = createDummyInputMethodInfo(
771 "com.android.apps.inputmethod.latin",
772 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
773 subtypes);
774 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
775 SUBTYPE_MODE_KEYBOARD));
776 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
777 SUBTYPE_MODE_KEYBOARD));
778 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
779 SUBTYPE_MODE_KEYBOARD));
780 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
781 SUBTYPE_MODE_KEYBOARD));
782 }
783
784 // Make sure that a subtype whose locale is "id" can be queried with "in".
785 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800786 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900787 subtypes.add(nonAutoId);
788 subtypes.add(nonAutoEnUS);
789 final InputMethodInfo imi = createDummyInputMethodInfo(
790 "com.android.apps.inputmethod.latin",
791 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
792 subtypes);
793 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
794 SUBTYPE_MODE_KEYBOARD));
Yohei Yukawaf487e0e2015-02-21 02:15:48 +0900795 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900796 SUBTYPE_MODE_KEYBOARD));
797 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
798 SUBTYPE_MODE_KEYBOARD));
Yohei Yukawaf487e0e2015-02-21 02:15:48 +0900799 assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900800 SUBTYPE_MODE_KEYBOARD));
801 }
802 }
803
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900804 private void assertDefaultEnabledImes(final ArrayList<InputMethodInfo> preinstalledImes,
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800805 final Locale systemLocale, String... expectedImeNames) {
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800806 final Context context = createTargetContextWithLocales(new LocaleList(systemLocale));
807 final String[] actualImeNames = getPackageNames(
Yohei Yukawaaf5cee82017-01-23 16:17:11 -0800808 InputMethodUtils.getDefaultEnabledImes(context, preinstalledImes));
Yohei Yukawab21220e2014-11-01 21:04:30 +0900809 assertEquals(expectedImeNames.length, actualImeNames.length);
810 for (int i = 0; i < expectedImeNames.length; ++i) {
811 assertEquals(expectedImeNames[i], actualImeNames[i]);
812 }
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900813 }
814
Yohei Yukawa9c372192018-03-20 22:54:56 -0700815 private void assertDefaultEnabledMinimumImes(final ArrayList<InputMethodInfo> preinstalledImes,
816 final Locale systemLocale, String... expectedImeNames) {
817 final Context context = createTargetContextWithLocales(new LocaleList(systemLocale));
818 final String[] actualImeNames = getPackageNames(
819 InputMethodUtils.getDefaultEnabledImes(context, preinstalledImes,
820 true /* onlyMinimum */));
821 assertEquals(expectedImeNames.length, actualImeNames.length);
822 for (int i = 0; i < expectedImeNames.length; ++i) {
823 assertEquals(expectedImeNames[i], actualImeNames[i]);
824 }
825 }
826
Yohei Yukawa58980042014-02-27 17:10:00 +0900827 private static List<InputMethodInfo> cloneViaParcel(final List<InputMethodInfo> list) {
828 Parcel p = null;
829 try {
830 p = Parcel.obtain();
831 p.writeTypedList(list);
832 p.setDataPosition(0);
833 return p.createTypedArrayList(InputMethodInfo.CREATOR);
834 } finally {
835 if (p != null) {
836 p.recycle();
837 }
838 }
839 }
840
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800841 private Context createTargetContextWithLocales(final LocaleList locales) {
842 final Configuration resourceConfiguration = new Configuration();
843 resourceConfiguration.setLocales(locales);
Yohei Yukawa8306fc42017-12-11 15:09:28 -0800844 return InstrumentationRegistry.getInstrumentation()
Yohei Yukawa5d64399c2016-02-08 23:21:37 -0800845 .getTargetContext()
846 .createConfigurationContext(resourceConfiguration);
Yohei Yukawabca817b2014-09-11 16:59:31 +0900847 }
848
Yohei Yukawafc843712016-02-24 00:27:34 -0800849 private Resources getResourcesForLocales(Locale... locales) {
850 return createTargetContextWithLocales(new LocaleList(locales)).getResources();
851 }
852
Yohei Yukawab21220e2014-11-01 21:04:30 +0900853 private String[] getPackageNames(final ArrayList<InputMethodInfo> imis) {
854 final String[] packageNames = new String[imis.size()];
855 for (int i = 0; i < imis.size(); ++i) {
856 packageNames[i] = imis.get(i).getPackageName();
Yohei Yukawabca817b2014-09-11 16:59:31 +0900857 }
858 return packageNames;
859 }
860
Yohei Yukawac18cd392014-03-03 13:08:34 +0900861 private static void verifyEquality(InputMethodInfo expected, InputMethodInfo actual) {
862 assertEquals(expected, actual);
863 assertEquals(expected.getSubtypeCount(), actual.getSubtypeCount());
864 for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) {
865 final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex);
866 final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex);
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900867 verifyEquality(expectedSubtype, actualSubtype);
Yohei Yukawac18cd392014-03-03 13:08:34 +0900868 }
869 }
870
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900871 private static void verifyEquality(InputMethodSubtype expected, InputMethodSubtype actual) {
872 assertEquals(expected, actual);
873 assertEquals(expected.hashCode(), actual.hashCode());
874 }
875
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900876 private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
877 CharSequence label, boolean isAuxIme, boolean isDefault,
878 List<InputMethodSubtype> subtypes) {
879 final ResolveInfo ri = new ResolveInfo();
880 final ServiceInfo si = new ServiceInfo();
881 final ApplicationInfo ai = new ApplicationInfo();
882 ai.packageName = packageName;
883 ai.enabled = true;
884 ai.flags |= ApplicationInfo.FLAG_SYSTEM;
885 si.applicationInfo = ai;
886 si.enabled = true;
887 si.packageName = packageName;
888 si.name = name;
889 si.exported = true;
890 si.nonLocalizedLabel = label;
891 ri.serviceInfo = si;
892 return new InputMethodInfo(ri, isAuxIme, "", subtypes, 1, isDefault);
893 }
894
895 private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
Yohei Yukawacfcbdda2014-09-10 17:53:51 +0900896 boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900897 boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) {
Yohei Yukawa238faad2016-03-11 10:39:51 -0800898 return createDummyInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary,
899 overridesImplicitlyEnabledSubtype, isAsciiCapable,
900 isEnabledWhenDefaultIsNotAsciiCapable);
901 }
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900902
Yohei Yukawa238faad2016-03-11 10:39:51 -0800903 private static InputMethodSubtype createDummyInputMethodSubtype(String locale,
904 String languageTag, String mode, boolean isAuxiliary,
905 boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable,
906 boolean isEnabledWhenDefaultIsNotAsciiCapable) {
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900907 final StringBuilder subtypeExtraValue = new StringBuilder();
908 if (isEnabledWhenDefaultIsNotAsciiCapable) {
909 subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
910 subtypeExtraValue.append(EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
911 }
912
913 // TODO: Remove following code. InputMethodSubtype#isAsciiCapable() has been publicly
914 // available since API level 19 (KitKat). We no longer need to rely on extra value.
915 if (isAsciiCapable) {
916 subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
917 subtypeExtraValue.append(EXTRA_VALUE_ASCII_CAPABLE);
918 }
919
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900920 return new InputMethodSubtypeBuilder()
921 .setSubtypeNameResId(0)
922 .setSubtypeIconResId(0)
923 .setSubtypeLocale(locale)
Yohei Yukawa238faad2016-03-11 10:39:51 -0800924 .setLanguageTag(languageTag)
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900925 .setSubtypeMode(mode)
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900926 .setSubtypeExtraValue(subtypeExtraValue.toString())
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900927 .setIsAuxiliary(isAuxiliary)
928 .setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype)
Yohei Yukawacfcbdda2014-09-10 17:53:51 +0900929 .setIsAsciiCapable(isAsciiCapable)
Yohei Yukawa443c2ba2014-09-10 14:10:30 +0900930 .build();
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900931 }
932
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900933 private static ArrayList<InputMethodInfo> getImesWithDefaultVoiceIme() {
934 ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
935 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800936 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900937 subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
938 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 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900941 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
942 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900943 preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultAutoVoiceIme",
944 "dummy.voice0", "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes));
945 }
946 preinstalledImes.addAll(getImesWithoutDefaultVoiceIme());
947 return preinstalledImes;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900948 }
949
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900950 private static ArrayList<InputMethodInfo> getImesWithoutDefaultVoiceIme() {
951 ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
952 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800953 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900954 subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
955 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
956 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900957 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900958 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
959 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900960 preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0",
961 "dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes));
962 }
963 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800964 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900965 subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
966 IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
967 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900968 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900969 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
970 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900971 preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1",
972 "dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes));
973 }
974 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800975 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900976 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +0900977 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
978 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900979 preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultVoiceIme2",
980 "dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes));
981 }
982 {
Yohei Yukawa622b44d2016-02-11 07:56:53 -0800983 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +0900984 subtypes.add(createDummyInputMethodSubtype("en_US", 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("DummyDefaultEnKeyboardIme",
988 "dummy.keyboard0", "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes));
989 }
990 return preinstalledImes;
Satoshi Kataokaf1367b72013-01-25 17:20:12 +0900991 }
992
Yohei Yukawab21220e2014-11-01 21:04:30 +0900993 private static boolean contains(final String[] textList, final String textToBeChecked) {
994 if (textList == null) {
995 return false;
996 }
997 for (final String text : textList) {
998 if (Objects.equals(textToBeChecked, text)) {
999 return true;
1000 }
1001 }
1002 return false;
1003 }
1004
1005 private static ArrayList<InputMethodInfo> getSamplePreinstalledImes(final String localeString) {
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001006 ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09001007
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001008 // a dummy Voice IME
1009 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001010 final boolean isDefaultIme = false;
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("", SUBTYPE_MODE_VOICE, 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.voice",
Yohei Yukawab21220e2014-11-01 21:04:30 +09001016 "com.android.inputmethod.voice", "DummyVoiceIme", IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001017 subtypes));
1018 }
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001019 // a dummy Hindi IME
1020 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001021 final boolean isDefaultIme = contains(new String[]{ "hi", "en-rIN" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001022 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001023 // TODO: This subtype should be marked as IS_ASCII_CAPABLE
1024 subtypes.add(createDummyInputMethodSubtype("en_IN", 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("hi", 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 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.hindi",
Yohei Yukawab21220e2014-11-01 21:04:30 +09001031 "com.android.inputmethod.hindi", "DummyHindiIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001032 subtypes));
1033 }
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09001034
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001035 // a dummy Pinyin IME
1036 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001037 final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001038 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001039 subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001040 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1041 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawab21220e2014-11-01 21:04:30 +09001042 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.pinyin",
1043 "com.android.apps.inputmethod.pinyin", "DummyPinyinIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001044 subtypes));
1045 }
Yohei Yukawa58980042014-02-27 17:10:00 +09001046
Yohei Yukawab21220e2014-11-01 21:04:30 +09001047 // a dummy Korean IME
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001048 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001049 final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001050 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001051 subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001052 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1053 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001054 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.korean",
Yohei Yukawab21220e2014-11-01 21:04:30 +09001055 "com.android.apps.inputmethod.korean", "DummyKoreanIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001056 subtypes));
1057 }
Yohei Yukawad77adfe2014-09-11 23:50:21 +09001058
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001059 // a dummy Latin IME
1060 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001061 final boolean isDefaultIme = contains(
1062 new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001063 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001064 subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001065 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1066 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001067 subtypes.add(createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001068 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1069 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001070 subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001071 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1072 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001073 subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001074 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
1075 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001076 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.latin",
Yohei Yukawab21220e2014-11-01 21:04:30 +09001077 "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, isDefaultIme,
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001078 subtypes));
1079 }
1080
1081 // a dummy Japanese IME
1082 {
Yohei Yukawab21220e2014-11-01 21:04:30 +09001083 final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString);
Yohei Yukawa622b44d2016-02-11 07:56:53 -08001084 final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001085 subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001086 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1087 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001088 subtypes.add(createDummyInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
Yohei Yukawae72d1c82015-02-20 20:55:21 +09001089 !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
1090 !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001091 preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.japanese",
1092 "com.android.apps.inputmethod.japanese", "DummyJapaneseIme", !IS_AUX,
Yohei Yukawab21220e2014-11-01 21:04:30 +09001093 isDefaultIme, subtypes));
Yohei Yukawa59cccf92014-09-12 23:21:54 +09001094 }
1095
1096 return preinstalledImes;
Yohei Yukawad77adfe2014-09-11 23:50:21 +09001097 }
Yohei Yukawa174843a2015-06-26 18:02:54 -07001098
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001099 @Test
Yohei Yukawa174843a2015-06-26 18:02:54 -07001100 public void testGetSuitableLocalesForSpellChecker() throws Exception {
1101 {
1102 final ArrayList<Locale> locales =
1103 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US);
1104 assertEquals(3, locales.size());
1105 assertEquals(LOCALE_EN_US, locales.get(0));
1106 assertEquals(LOCALE_EN_GB, locales.get(1));
1107 assertEquals(LOCALE_EN, locales.get(2));
1108 }
1109
1110 {
1111 final ArrayList<Locale> locales =
1112 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB);
1113 assertEquals(3, locales.size());
1114 assertEquals(LOCALE_EN_GB, locales.get(0));
1115 assertEquals(LOCALE_EN_US, locales.get(1));
1116 assertEquals(LOCALE_EN, locales.get(2));
1117 }
1118
1119 {
1120 final ArrayList<Locale> locales =
1121 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN);
1122 assertEquals(3, locales.size());
1123 assertEquals(LOCALE_EN, locales.get(0));
1124 assertEquals(LOCALE_EN_US, locales.get(1));
1125 assertEquals(LOCALE_EN_GB, locales.get(2));
1126 }
1127
1128 {
1129 final ArrayList<Locale> locales =
1130 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN);
1131 assertEquals(4, locales.size());
1132 assertEquals(LOCALE_EN_IN, locales.get(0));
1133 assertEquals(LOCALE_EN_US, locales.get(1));
1134 assertEquals(LOCALE_EN_GB, locales.get(2));
1135 assertEquals(LOCALE_EN, locales.get(3));
1136 }
1137
1138 {
1139 final ArrayList<Locale> locales =
1140 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP);
1141 assertEquals(5, locales.size());
1142 assertEquals(LOCALE_JA_JP, locales.get(0));
1143 assertEquals(LOCALE_JA, locales.get(1));
1144 assertEquals(LOCALE_EN_US, locales.get(2));
1145 assertEquals(LOCALE_EN_GB, locales.get(3));
1146 assertEquals(Locale.ENGLISH, locales.get(4));
1147 }
1148
1149 // Test 3-letter language code.
1150 {
1151 final ArrayList<Locale> locales =
1152 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH);
1153 assertEquals(5, locales.size());
1154 assertEquals(LOCALE_FIL_PH, locales.get(0));
1155 assertEquals(LOCALE_FIL, locales.get(1));
1156 assertEquals(LOCALE_EN_US, locales.get(2));
1157 assertEquals(LOCALE_EN_GB, locales.get(3));
1158 assertEquals(Locale.ENGLISH, locales.get(4));
1159 }
1160
1161 // Test variant.
1162 {
1163 final ArrayList<Locale> locales =
1164 InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH);
1165 assertEquals(6, locales.size());
1166 assertEquals(LOCALE_TH_TH_TH, locales.get(0));
1167 assertEquals(LOCALE_TH_TH, locales.get(1));
1168 assertEquals(LOCALE_TH, locales.get(2));
1169 assertEquals(LOCALE_EN_US, locales.get(3));
1170 assertEquals(LOCALE_EN_GB, locales.get(4));
1171 assertEquals(Locale.ENGLISH, locales.get(5));
1172 }
1173
1174 // Test Locale extension.
1175 {
1176 final Locale localeWithoutVariant = LOCALE_JA_JP;
1177 final Locale localeWithVariant = new Locale.Builder()
1178 .setLocale(LOCALE_JA_JP)
1179 .setExtension('x', "android")
1180 .build();
1181 assertFalse(localeWithoutVariant.equals(localeWithVariant));
1182
1183 final ArrayList<Locale> locales =
1184 InputMethodUtils.getSuitableLocalesForSpellChecker(localeWithVariant);
1185 assertEquals(5, locales.size());
1186 assertEquals(LOCALE_JA_JP, locales.get(0));
1187 assertEquals(LOCALE_JA, locales.get(1));
1188 assertEquals(LOCALE_EN_US, locales.get(2));
1189 assertEquals(LOCALE_EN_GB, locales.get(3));
1190 assertEquals(Locale.ENGLISH, locales.get(4));
1191 }
1192 }
Seigo Nonaka2028dda2015-07-06 17:41:24 +09001193
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001194 @Test
Seigo Nonaka2028dda2015-07-06 17:41:24 +09001195 public void testParseInputMethodsAndSubtypesString() {
1196 // Trivial cases.
1197 {
1198 assertTrue(InputMethodUtils.parseInputMethodsAndSubtypesString("").isEmpty());
1199 assertTrue(InputMethodUtils.parseInputMethodsAndSubtypesString(null).isEmpty());
1200 }
1201
1202 // No subtype cases.
1203 {
1204 ArrayMap<String, ArraySet<String>> r =
1205 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0");
1206 assertEquals(1, r.size());
1207 assertTrue(r.containsKey("ime0"));
1208 assertTrue(r.get("ime0").isEmpty());
1209 }
1210 {
1211 ArrayMap<String, ArraySet<String>> r =
1212 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0:ime1");
1213 assertEquals(2, r.size());
1214 assertTrue(r.containsKey("ime0"));
1215 assertTrue(r.get("ime0").isEmpty());
1216 assertTrue(r.containsKey("ime1"));
1217 assertTrue(r.get("ime1").isEmpty());
1218 }
1219
1220 // Input metho IDs and their subtypes.
1221 {
1222 ArrayMap<String, ArraySet<String>> r =
1223 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0");
1224 assertEquals(1, r.size());
1225 assertTrue(r.containsKey("ime0"));
1226 ArraySet<String> subtypes = r.get("ime0");
1227 assertEquals(1, subtypes.size());
1228 assertTrue(subtypes.contains("subtype0"));
1229 }
1230 {
1231 ArrayMap<String, ArraySet<String>> r =
1232 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0;subtype0");
1233 assertEquals(1, r.size());
1234 assertTrue(r.containsKey("ime0"));
1235 ArraySet<String> subtypes = r.get("ime0");
1236 assertEquals(1, subtypes.size());
1237 assertTrue(subtypes.contains("subtype0"));
1238 }
1239 {
1240 ArrayMap<String, ArraySet<String>> r =
1241 InputMethodUtils.parseInputMethodsAndSubtypesString("ime0;subtype0;subtype1");
1242 assertEquals(1, r.size());
1243 assertTrue(r.containsKey("ime0"));
1244 ArraySet<String> subtypes = r.get("ime0");
1245 assertEquals(2, subtypes.size());
1246 assertTrue(subtypes.contains("subtype0"));
1247 assertTrue(subtypes.contains("subtype1"));
1248 }
1249 {
1250 ArrayMap<String, ArraySet<String>> r =
1251 InputMethodUtils.parseInputMethodsAndSubtypesString(
1252 "ime0;subtype0:ime1;subtype1");
1253 assertEquals(2, r.size());
1254 assertTrue(r.containsKey("ime0"));
1255 assertTrue(r.containsKey("ime1"));
1256 ArraySet<String> subtypes0 = r.get("ime0");
1257 assertEquals(1, subtypes0.size());
1258 assertTrue(subtypes0.contains("subtype0"));
1259
1260 ArraySet<String> subtypes1 = r.get("ime1");
1261 assertEquals(1, subtypes1.size());
1262 assertTrue(subtypes1.contains("subtype1"));
1263 }
1264 {
1265 ArrayMap<String, ArraySet<String>> r =
1266 InputMethodUtils.parseInputMethodsAndSubtypesString(
1267 "ime0;subtype0;subtype1:ime1;subtype2");
1268 assertEquals(2, r.size());
1269 assertTrue(r.containsKey("ime0"));
1270 assertTrue(r.containsKey("ime1"));
1271 ArraySet<String> subtypes0 = r.get("ime0");
1272 assertEquals(2, subtypes0.size());
1273 assertTrue(subtypes0.contains("subtype0"));
1274 assertTrue(subtypes0.contains("subtype1"));
1275
1276 ArraySet<String> subtypes1 = r.get("ime1");
1277 assertEquals(1, subtypes1.size());
1278 assertTrue(subtypes1.contains("subtype2"));
1279 }
1280 {
1281 ArrayMap<String, ArraySet<String>> r =
1282 InputMethodUtils.parseInputMethodsAndSubtypesString(
1283 "ime0;subtype0;subtype1:ime1;subtype1;subtype2");
1284 assertEquals(2, r.size());
1285 assertTrue(r.containsKey("ime0"));
1286 assertTrue(r.containsKey("ime1"));
1287 ArraySet<String> subtypes0 = r.get("ime0");
1288 assertEquals(2, subtypes0.size());
1289 assertTrue(subtypes0.contains("subtype0"));
1290 assertTrue(subtypes0.contains("subtype1"));
1291
1292 ArraySet<String> subtypes1 = r.get("ime1");
1293 assertEquals(2, subtypes1.size());
1294 assertTrue(subtypes0.contains("subtype1"));
1295 assertTrue(subtypes1.contains("subtype2"));
1296 }
1297 {
1298 ArrayMap<String, ArraySet<String>> r =
1299 InputMethodUtils.parseInputMethodsAndSubtypesString(
1300 "ime0;subtype0;subtype1:ime1;subtype1;subtype2:ime2");
1301 assertEquals(3, r.size());
1302 assertTrue(r.containsKey("ime0"));
1303 assertTrue(r.containsKey("ime1"));
1304 assertTrue(r.containsKey("ime2"));
1305 ArraySet<String> subtypes0 = r.get("ime0");
1306 assertEquals(2, subtypes0.size());
1307 assertTrue(subtypes0.contains("subtype0"));
1308 assertTrue(subtypes0.contains("subtype1"));
1309
1310 ArraySet<String> subtypes1 = r.get("ime1");
1311 assertEquals(2, subtypes1.size());
1312 assertTrue(subtypes0.contains("subtype1"));
1313 assertTrue(subtypes1.contains("subtype2"));
1314
1315 ArraySet<String> subtypes2 = r.get("ime2");
1316 assertTrue(subtypes2.isEmpty());
1317 }
1318 }
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001319
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001320 @Test
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001321 public void testbuildInputMethodsAndSubtypesString() {
1322 {
1323 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1324 assertEquals("", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
1325 }
1326 {
1327 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001328 map.put("ime0", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001329 assertEquals("ime0", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
1330 }
1331 {
1332 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1333 ArraySet<String> subtypes1 = new ArraySet<>();
1334 subtypes1.add("subtype0");
1335 map.put("ime0", subtypes1);
1336 assertEquals("ime0;subtype0", InputMethodUtils.buildInputMethodsAndSubtypesString(map));
1337 }
1338 {
1339 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1340 ArraySet<String> subtypes1 = new ArraySet<>();
1341 subtypes1.add("subtype0");
1342 subtypes1.add("subtype1");
1343 map.put("ime0", subtypes1);
1344
1345 // We do not expect what order will be used to concatenate items in
1346 // InputMethodUtils.buildInputMethodsAndSubtypesString() hence enumerate all possible
1347 // permutations here.
1348 ArraySet<String> validSequences = new ArraySet<>();
1349 validSequences.add("ime0;subtype0;subtype1");
1350 validSequences.add("ime0;subtype1;subtype0");
1351 assertTrue(validSequences.contains(
1352 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1353 }
1354 {
1355 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001356 map.put("ime0", new ArraySet<>());
1357 map.put("ime1", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001358
1359 ArraySet<String> validSequences = new ArraySet<>();
1360 validSequences.add("ime0:ime1");
1361 validSequences.add("ime1:ime0");
1362 assertTrue(validSequences.contains(
1363 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1364 }
1365 {
1366 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1367 ArraySet<String> subtypes1 = new ArraySet<>();
1368 subtypes1.add("subtype0");
1369 map.put("ime0", subtypes1);
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001370 map.put("ime1", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001371
1372 ArraySet<String> validSequences = new ArraySet<>();
1373 validSequences.add("ime0;subtype0:ime1");
1374 validSequences.add("ime1;ime0;subtype0");
1375 assertTrue(validSequences.contains(
1376 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1377 }
1378 {
1379 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1380 ArraySet<String> subtypes1 = new ArraySet<>();
1381 subtypes1.add("subtype0");
1382 subtypes1.add("subtype1");
1383 map.put("ime0", subtypes1);
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001384 map.put("ime1", new ArraySet<>());
Seigo Nonaka2a099bc2015-08-14 19:29:45 -07001385
1386 ArraySet<String> validSequences = new ArraySet<>();
1387 validSequences.add("ime0;subtype0;subtype1:ime1");
1388 validSequences.add("ime0;subtype1;subtype0:ime1");
1389 validSequences.add("ime1:ime0;subtype0;subtype1");
1390 validSequences.add("ime1:ime0;subtype1;subtype0");
1391 assertTrue(validSequences.contains(
1392 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1393 }
1394 {
1395 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1396 ArraySet<String> subtypes1 = new ArraySet<>();
1397 subtypes1.add("subtype0");
1398 map.put("ime0", subtypes1);
1399
1400 ArraySet<String> subtypes2 = new ArraySet<>();
1401 subtypes2.add("subtype1");
1402 map.put("ime1", subtypes2);
1403
1404 ArraySet<String> validSequences = new ArraySet<>();
1405 validSequences.add("ime0;subtype0:ime1;subtype1");
1406 validSequences.add("ime1;subtype1:ime0;subtype0");
1407 assertTrue(validSequences.contains(
1408 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1409 }
1410 {
1411 ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
1412 ArraySet<String> subtypes1 = new ArraySet<>();
1413 subtypes1.add("subtype0");
1414 subtypes1.add("subtype1");
1415 map.put("ime0", subtypes1);
1416
1417 ArraySet<String> subtypes2 = new ArraySet<>();
1418 subtypes2.add("subtype2");
1419 subtypes2.add("subtype3");
1420 map.put("ime1", subtypes2);
1421
1422 ArraySet<String> validSequences = new ArraySet<>();
1423 validSequences.add("ime0;subtype0;subtype1:ime1;subtype2;subtype3");
1424 validSequences.add("ime0;subtype1;subtype0:ime1;subtype2;subtype3");
1425 validSequences.add("ime0;subtype0;subtype1:ime1;subtype3;subtype2");
1426 validSequences.add("ime0;subtype1;subtype0:ime1;subtype3;subtype2");
1427 validSequences.add("ime1;subtype2;subtype3:ime0;subtype0;subtype1");
1428 validSequences.add("ime2;subtype3;subtype2:ime0;subtype0;subtype1");
1429 validSequences.add("ime3;subtype2;subtype3:ime0;subtype1;subtype0");
1430 validSequences.add("ime4;subtype3;subtype2:ime0;subtype1;subtype0");
1431 assertTrue(validSequences.contains(
1432 InputMethodUtils.buildInputMethodsAndSubtypesString(map)));
1433 }
1434 }
Yohei Yukawa226c4bb2015-12-03 15:21:15 -08001435
Yohei Yukawa8306fc42017-12-11 15:09:28 -08001436 @Test
Yohei Yukawa226c4bb2015-12-03 15:21:15 -08001437 public void testConstructLocaleFromString() throws Exception {
1438 assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en"));
1439 assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US"));
1440 assertEquals(new Locale("en", "US", "POSIX"),
1441 InputMethodUtils.constructLocaleFromString("en_US_POSIX"));
1442
1443 // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
1444 // support three letter language codes, and used "tl" (Tagalog) as the language string for
1445 // "fil" (Filipino).
1446 assertEquals(new Locale("fil"), InputMethodUtils.constructLocaleFromString("tl"));
1447 assertEquals(new Locale("fil", "PH"), InputMethodUtils.constructLocaleFromString("tl_PH"));
1448 assertEquals(new Locale("fil", "PH", "POSIX"),
1449 InputMethodUtils.constructLocaleFromString("tl_PH_POSIX"));
1450
1451 // So far rejecting an invalid/unexpected locale string is out of the scope of this method.
1452 assertEquals(new Locale("a"), InputMethodUtils.constructLocaleFromString("a"));
1453 assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c"));
1454 assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US"));
1455 }
Yohei Yukawacf68d522017-12-12 09:33:26 -08001456
1457 @Test
1458 public void testIsSoftInputModeStateVisibleAllowed() {
1459 // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always
1460 // allowed, regardless of the focused view state.
1461 assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1462 Build.VERSION_CODES.O_MR1, 0));
1463 assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1464 Build.VERSION_CODES.O_MR1, CONTROL_WINDOW_VIEW_HAS_FOCUS));
1465 assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1466 Build.VERSION_CODES.O_MR1,
1467 CONTROL_WINDOW_VIEW_HAS_FOCUS | CONTROL_WINDOW_IS_TEXT_EDITOR));
1468
1469 // On P+ devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are allowed only
1470 // when there is a focused View and its View#onCheckIsTextEditor() returns true.
1471 assertFalse(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1472 Build.VERSION_CODES.P, 0));
1473 assertFalse(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1474 Build.VERSION_CODES.P, CONTROL_WINDOW_VIEW_HAS_FOCUS));
1475 assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
1476 Build.VERSION_CODES.P,
1477 CONTROL_WINDOW_VIEW_HAS_FOCUS | CONTROL_WINDOW_IS_TEXT_EDITOR));
1478
1479 }
1480
Satoshi Kataokaf1367b72013-01-25 17:20:12 +09001481}