OSDN Git Service

Fix ImeSubtypeListItem#compareTo()
[android-x86/frameworks-base.git] / core / tests / coretests / src / com / android / internal / inputmethod / InputMethodSubtypeSwitchingControllerTest.java
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.internal.inputmethod;
18
19 import android.content.pm.ApplicationInfo;
20 import android.content.pm.ResolveInfo;
21 import android.content.pm.ServiceInfo;
22 import android.test.InstrumentationTestCase;
23 import android.test.suitebuilder.annotation.SmallTest;
24 import android.view.inputmethod.InputMethodInfo;
25 import android.view.inputmethod.InputMethodSubtype;
26 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
27
28 import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl;
29 import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
30
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.List;
34
35 public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTestCase {
36     private static final String DUMMY_PACKAGE_NAME = "dummy package name";
37     private static final String DUMMY_IME_LABEL = "dummy ime label";
38     private static final String DUMMY_SETTING_ACTIVITY_NAME = "";
39     private static final boolean DUMMY_IS_AUX_IME = false;
40     private static final boolean DUMMY_FORCE_DEFAULT = false;
41     private static final int DUMMY_IS_DEFAULT_RES_ID = 0;
42     private static final String SYSTEM_LOCALE = "en_US";
43     private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
44
45     private static InputMethodSubtype createDummySubtype(final String locale) {
46         final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder();
47         return builder.setSubtypeNameResId(0)
48                 .setSubtypeIconResId(0)
49                 .setSubtypeLocale(locale)
50                 .setIsAsciiCapable(true)
51                 .build();
52     }
53
54     private static void addDummyImeSubtypeListItems(List<ImeSubtypeListItem> items,
55             String imeName, String imeLabel, List<String> subtypeLocales,
56             boolean supportsSwitchingToNextInputMethod) {
57         final ResolveInfo ri = new ResolveInfo();
58         final ServiceInfo si = new ServiceInfo();
59         final ApplicationInfo ai = new ApplicationInfo();
60         ai.packageName = DUMMY_PACKAGE_NAME;
61         ai.enabled = true;
62         si.applicationInfo = ai;
63         si.enabled = true;
64         si.packageName = DUMMY_PACKAGE_NAME;
65         si.name = imeName;
66         si.exported = true;
67         si.nonLocalizedLabel = imeLabel;
68         ri.serviceInfo = si;
69         List<InputMethodSubtype> subtypes = null;
70         if (subtypeLocales != null) {
71             subtypes = new ArrayList<>();
72             for (String subtypeLocale : subtypeLocales) {
73                 subtypes.add(createDummySubtype(subtypeLocale));
74             }
75         }
76         final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
77                 DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
78                 DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod,
79                 false /* supportsDismissingWindow */);
80         if (subtypes == null) {
81             items.add(new ImeSubtypeListItem(imeName, null /* variableName */, imi,
82                     NOT_A_SUBTYPE_ID, null, SYSTEM_LOCALE));
83         } else {
84             for (int i = 0; i < subtypes.size(); ++i) {
85                 final String subtypeLocale = subtypeLocales.get(i);
86                 items.add(new ImeSubtypeListItem(imeName, subtypeLocale, imi, i, subtypeLocale,
87                         SYSTEM_LOCALE));
88             }
89         }
90     }
91
92     private static ImeSubtypeListItem createDummyItem(String imeName,
93             String subtypeName, String subtypeLocale, int subtypeIndex, String systemLocale) {
94         final ResolveInfo ri = new ResolveInfo();
95         final ServiceInfo si = new ServiceInfo();
96         final ApplicationInfo ai = new ApplicationInfo();
97         ai.packageName = DUMMY_PACKAGE_NAME;
98         ai.enabled = true;
99         si.applicationInfo = ai;
100         si.enabled = true;
101         si.packageName = DUMMY_PACKAGE_NAME;
102         si.name = imeName;
103         si.exported = true;
104         si.nonLocalizedLabel = DUMMY_IME_LABEL;
105         ri.serviceInfo = si;
106         ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
107         subtypes.add(new InputMethodSubtypeBuilder()
108                 .setSubtypeNameResId(0)
109                 .setSubtypeIconResId(0)
110                 .setSubtypeLocale(subtypeLocale)
111                 .setIsAsciiCapable(true)
112                 .build());
113         final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
114                 DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
115                 DUMMY_FORCE_DEFAULT, true /* supportsSwitchingToNextInputMethod */,
116                 false /* supportsDismissingWindow */);
117         return new ImeSubtypeListItem(imeName, subtypeName, imi, subtypeIndex, subtypeLocale,
118                 systemLocale);
119     }
120
121     private static List<ImeSubtypeListItem> createEnabledImeSubtypes() {
122         final List<ImeSubtypeListItem> items = new ArrayList<>();
123         addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme", Arrays.asList("en_US", "fr"),
124                 true /* supportsSwitchingToNextInputMethod*/);
125         addDummyImeSubtypeListItems(items, "switchUnawareLatinIme", "switchUnawareLatinIme",
126                 Arrays.asList("en_UK", "hi"),
127                 false /* supportsSwitchingToNextInputMethod*/);
128         addDummyImeSubtypeListItems(items, "subtypeUnawareIme", "subtypeUnawareIme", null,
129                 false /* supportsSwitchingToNextInputMethod*/);
130         addDummyImeSubtypeListItems(items, "JapaneseIme", "JapaneseIme", Arrays.asList("ja_JP"),
131                 true /* supportsSwitchingToNextInputMethod*/);
132         addDummyImeSubtypeListItems(items, "switchUnawareJapaneseIme", "switchUnawareJapaneseIme",
133                 Arrays.asList("ja_JP"), false /* supportsSwitchingToNextInputMethod*/);
134         return items;
135     }
136
137     private static List<ImeSubtypeListItem> createDisabledImeSubtypes() {
138         final List<ImeSubtypeListItem> items = new ArrayList<>();
139         addDummyImeSubtypeListItems(items,
140                 "UnknownIme", "UnknownIme",
141                 Arrays.asList("en_US", "hi"),
142                 true /* supportsSwitchingToNextInputMethod*/);
143         addDummyImeSubtypeListItems(items,
144                 "UnknownSwitchingUnawareIme", "UnknownSwitchingUnawareIme",
145                 Arrays.asList("en_US"),
146                 false /* supportsSwitchingToNextInputMethod*/);
147         addDummyImeSubtypeListItems(items, "UnknownSubtypeUnawareIme",
148                 "UnknownSubtypeUnawareIme", null,
149                 false /* supportsSwitchingToNextInputMethod*/);
150         return items;
151     }
152
153     private void assertNextInputMethod(final ControllerImpl controller,
154             final boolean onlyCurrentIme, final ImeSubtypeListItem currentItem,
155             final ImeSubtypeListItem nextItem, final ImeSubtypeListItem prevItem) {
156         InputMethodSubtype subtype = null;
157         if (currentItem.mSubtypeName != null) {
158             subtype = createDummySubtype(currentItem.mSubtypeName.toString());
159         }
160         final ImeSubtypeListItem nextIme = controller.getNextInputMethod(onlyCurrentIme,
161                 currentItem.mImi, subtype, true /* forward */);
162         assertEquals(nextItem, nextIme);
163         final ImeSubtypeListItem prevIme = controller.getNextInputMethod(onlyCurrentIme,
164                 currentItem.mImi, subtype, false /* forward */);
165         assertEquals(prevItem, prevIme);
166     }
167
168     private void assertRotationOrder(final ControllerImpl controller,
169             final boolean onlyCurrentIme,
170             final ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) {
171         final int N = expectedRotationOrderOfImeSubtypeList.length;
172         for (int i = 0; i < N; i++) {
173             final int currentIndex = i;
174             final int prevIndex = (currentIndex + N - 1) % N;
175             final int nextIndex = (currentIndex + 1) % N;
176             final ImeSubtypeListItem currentItem =
177                     expectedRotationOrderOfImeSubtypeList[currentIndex];
178             final ImeSubtypeListItem nextItem = expectedRotationOrderOfImeSubtypeList[nextIndex];
179             final ImeSubtypeListItem prevItem = expectedRotationOrderOfImeSubtypeList[prevIndex];
180             assertNextInputMethod(controller, onlyCurrentIme, currentItem, nextItem, prevItem);
181         }
182     }
183
184     private void onUserAction(final ControllerImpl controller,
185             final ImeSubtypeListItem subtypeListItem) {
186         InputMethodSubtype subtype = null;
187         if (subtypeListItem.mSubtypeName != null) {
188             subtype = createDummySubtype(subtypeListItem.mSubtypeName.toString());
189         }
190         controller.onUserActionLocked(subtypeListItem.mImi, subtype);
191     }
192
193     @SmallTest
194     public void testControllerImpl() throws Exception {
195         final List<ImeSubtypeListItem> disabledItems = createDisabledImeSubtypes();
196         final ImeSubtypeListItem disabledIme_en_US = disabledItems.get(0);
197         final ImeSubtypeListItem disabledIme_hi = disabledItems.get(1);
198         final ImeSubtypeListItem disabledSwitchingUnawareIme = disabledItems.get(2);
199         final ImeSubtypeListItem disabledSubtypeUnawareIme = disabledItems.get(3);
200
201         final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes();
202         final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0);
203         final ImeSubtypeListItem latinIme_fr = enabledItems.get(1);
204         final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2);
205         final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3);
206         final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4);
207         final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5);
208         final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6);
209
210         final ControllerImpl controller = ControllerImpl.createFrom(
211                 null /* currentInstance */, enabledItems);
212
213         // switching-aware loop
214         assertRotationOrder(controller, false /* onlyCurrentIme */,
215                 latinIme_en_US, latinIme_fr, japaneseIme_ja_JP);
216
217         // switching-unaware loop
218         assertRotationOrder(controller, false /* onlyCurrentIme */,
219                 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
220                 switchUnawareJapaneseIme_ja_JP);
221
222         // test onlyCurrentIme == true
223         assertRotationOrder(controller, true /* onlyCurrentIme */,
224                 latinIme_en_US, latinIme_fr);
225         assertRotationOrder(controller, true /* onlyCurrentIme */,
226                 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi);
227         assertNextInputMethod(controller, true /* onlyCurrentIme */,
228                 subtypeUnawareIme, null, null);
229         assertNextInputMethod(controller, true /* onlyCurrentIme */,
230                 japaneseIme_ja_JP, null, null);
231         assertNextInputMethod(controller, true /* onlyCurrentIme */,
232                 switchUnawareJapaneseIme_ja_JP, null, null);
233
234         // Make sure that disabled IMEs are not accepted.
235         assertNextInputMethod(controller, false /* onlyCurrentIme */,
236                 disabledIme_en_US, null, null);
237         assertNextInputMethod(controller, false /* onlyCurrentIme */,
238                 disabledIme_hi, null, null);
239         assertNextInputMethod(controller, false /* onlyCurrentIme */,
240                 disabledSwitchingUnawareIme, null, null);
241         assertNextInputMethod(controller, false /* onlyCurrentIme */,
242                 disabledSubtypeUnawareIme, null, null);
243         assertNextInputMethod(controller, true /* onlyCurrentIme */,
244                 disabledIme_en_US, null, null);
245         assertNextInputMethod(controller, true /* onlyCurrentIme */,
246                 disabledIme_hi, null, null);
247         assertNextInputMethod(controller, true /* onlyCurrentIme */,
248                 disabledSwitchingUnawareIme, null, null);
249         assertNextInputMethod(controller, true /* onlyCurrentIme */,
250                 disabledSubtypeUnawareIme, null, null);
251     }
252
253     @SmallTest
254     public void testControllerImplWithUserAction() throws Exception {
255         final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes();
256         final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0);
257         final ImeSubtypeListItem latinIme_fr = enabledItems.get(1);
258         final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2);
259         final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3);
260         final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4);
261         final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5);
262         final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6);
263
264         final ControllerImpl controller = ControllerImpl.createFrom(
265                 null /* currentInstance */, enabledItems);
266
267         // === switching-aware loop ===
268         assertRotationOrder(controller, false /* onlyCurrentIme */,
269                 latinIme_en_US, latinIme_fr, japaneseIme_ja_JP);
270         // Then notify that a user did something for latinIme_fr.
271         onUserAction(controller, latinIme_fr);
272         assertRotationOrder(controller, false /* onlyCurrentIme */,
273                 latinIme_fr, latinIme_en_US, japaneseIme_ja_JP);
274         // Then notify that a user did something for latinIme_fr again.
275         onUserAction(controller, latinIme_fr);
276         assertRotationOrder(controller, false /* onlyCurrentIme */,
277                 latinIme_fr, latinIme_en_US, japaneseIme_ja_JP);
278         // Then notify that a user did something for japaneseIme_ja_JP.
279         onUserAction(controller, latinIme_fr);
280         assertRotationOrder(controller, false /* onlyCurrentIme */,
281                 japaneseIme_ja_JP, latinIme_fr, latinIme_en_US);
282         // Check onlyCurrentIme == true.
283         assertNextInputMethod(controller, true /* onlyCurrentIme */,
284                 japaneseIme_ja_JP, null, null);
285         assertRotationOrder(controller, true /* onlyCurrentIme */,
286                 latinIme_fr, latinIme_en_US);
287         assertRotationOrder(controller, true /* onlyCurrentIme */,
288                 latinIme_en_US, latinIme_fr);
289
290         // === switching-unaware loop ===
291         assertRotationOrder(controller, false /* onlyCurrentIme */,
292                 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
293                 switchUnawareJapaneseIme_ja_JP);
294         // User action should be ignored for switching unaware IMEs.
295         onUserAction(controller, switchingUnawarelatinIme_hi);
296         assertRotationOrder(controller, false /* onlyCurrentIme */,
297                 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
298                 switchUnawareJapaneseIme_ja_JP);
299         // User action should be ignored for switching unaware IMEs.
300         onUserAction(controller, switchUnawareJapaneseIme_ja_JP);
301         assertRotationOrder(controller, false /* onlyCurrentIme */,
302                 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
303                 switchUnawareJapaneseIme_ja_JP);
304         // Check onlyCurrentIme == true.
305         assertRotationOrder(controller, true /* onlyCurrentIme */,
306                 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi);
307         assertNextInputMethod(controller, true /* onlyCurrentIme */,
308                 subtypeUnawareIme, null, null);
309         assertNextInputMethod(controller, true /* onlyCurrentIme */,
310                 switchUnawareJapaneseIme_ja_JP, null, null);
311
312         // Rotation order should be preserved when created with the same subtype list.
313         final List<ImeSubtypeListItem> sameEnabledItems = createEnabledImeSubtypes();
314         final ControllerImpl newController = ControllerImpl.createFrom(controller,
315                 sameEnabledItems);
316         assertRotationOrder(newController, false /* onlyCurrentIme */,
317                 japaneseIme_ja_JP, latinIme_fr, latinIme_en_US);
318         assertRotationOrder(newController, false /* onlyCurrentIme */,
319                 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
320                 switchUnawareJapaneseIme_ja_JP);
321
322         // Rotation order should be initialized when created with a different subtype list.
323         final List<ImeSubtypeListItem> differentEnabledItems = Arrays.asList(
324                 latinIme_en_US, latinIme_fr, switchingUnawarelatinIme_en_UK,
325                 switchUnawareJapaneseIme_ja_JP);
326         final ControllerImpl anotherController = ControllerImpl.createFrom(controller,
327                 differentEnabledItems);
328         assertRotationOrder(anotherController, false /* onlyCurrentIme */,
329                 latinIme_en_US, latinIme_fr);
330         assertRotationOrder(anotherController, false /* onlyCurrentIme */,
331                 switchingUnawarelatinIme_en_UK, switchUnawareJapaneseIme_ja_JP);
332     }
333
334     @SmallTest
335     public void testImeSubtypeListItem() throws Exception {
336         final List<ImeSubtypeListItem> items = new ArrayList<>();
337         addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme",
338                 Arrays.asList("en_US", "fr", "en", "en_uk", "enn", "e", "EN_US"),
339                 true /* supportsSwitchingToNextInputMethod*/);
340         final ImeSubtypeListItem item_en_US = items.get(0);
341         final ImeSubtypeListItem item_fr = items.get(1);
342         final ImeSubtypeListItem item_en = items.get(2);
343         final ImeSubtypeListItem item_enn = items.get(3);
344         final ImeSubtypeListItem item_e = items.get(4);
345         final ImeSubtypeListItem item_EN_US = items.get(5);
346
347         assertTrue(item_en_US.mIsSystemLocale);
348         assertFalse(item_fr.mIsSystemLocale);
349         assertFalse(item_en.mIsSystemLocale);
350         assertFalse(item_en.mIsSystemLocale);
351         assertFalse(item_enn.mIsSystemLocale);
352         assertFalse(item_e.mIsSystemLocale);
353         assertFalse(item_EN_US.mIsSystemLocale);
354
355         assertTrue(item_en_US.mIsSystemLanguage);
356         assertFalse(item_fr.mIsSystemLanguage);
357         assertTrue(item_en.mIsSystemLanguage);
358         assertFalse(item_enn.mIsSystemLocale);
359         assertFalse(item_e.mIsSystemLocale);
360         assertFalse(item_EN_US.mIsSystemLocale);
361     }
362
363     @SmallTest
364     public void testImeSubtypeListComparator() throws Exception {
365         {
366             final List<ImeSubtypeListItem> items = Arrays.asList(
367                     createDummyItem("X", "A", "en_US", 0, "en_US"),
368                     createDummyItem("X", "A", "en", 1, "en_US"),
369                     createDummyItem("X", "A", "ja", 2, "en_US"),
370                     createDummyItem("X", "Z", "en_US", 3, "en_US"),
371                     createDummyItem("X", "Z", "en", 4, "en_US"),
372                     createDummyItem("X", "Z", "ja", 5, "en_US"),
373                     createDummyItem("X", "", "en_US", 6, "en_US"),
374                     createDummyItem("X", "", "en", 7, "en_US"),
375                     createDummyItem("X", "", "ja", 8, "en_US"),
376                     createDummyItem("Y", "A", "en_US", 9, "en_US"),
377                     createDummyItem("Y", "A", "en", 10, "en_US"),
378                     createDummyItem("Y", "A", "ja", 11, "en_US"),
379                     createDummyItem("Y", "Z", "en_US", 12, "en_US"),
380                     createDummyItem("Y", "Z", "en", 13, "en_US"),
381                     createDummyItem("Y", "Z", "ja", 14, "en_US"),
382                     createDummyItem("Y", "", "en_US", 15, "en_US"),
383                     createDummyItem("Y", "", "en", 16, "en_US"),
384                     createDummyItem("Y", "", "ja", 17, "en_US"),
385                     createDummyItem("", "A", "en_US", 18, "en_US"),
386                     createDummyItem("", "A", "en", 19, "en_US"),
387                     createDummyItem("", "A", "ja", 20, "en_US"),
388                     createDummyItem("", "Z", "en_US", 21, "en_US"),
389                     createDummyItem("", "Z", "en", 22, "en_US"),
390                     createDummyItem("", "Z", "ja", 23, "en_US"),
391                     createDummyItem("", "", "en_US", 24, "en_US"),
392                     createDummyItem("", "", "en", 25, "en_US"),
393                     createDummyItem("", "", "ja", 26, "en_US"));
394
395             for (int i = 0; i < items.size(); ++i) {
396                 assertEquals(0, items.get(i).compareTo(items.get(i)));
397                 for (int j = i + 1; j < items.size(); ++j) {
398                     assertTrue(items.get(i).compareTo(items.get(j)) < 0);
399                     assertTrue(items.get(j).compareTo(items.get(i)) > 0);
400                 }
401             }
402         }
403
404         {
405             // Following two items have the same priority.
406             final ImeSubtypeListItem nonSystemLocale1 =
407                     createDummyItem("X", "A", "ja_JP", 0, "en_us");
408             final ImeSubtypeListItem nonSystemLocale2 =
409                     createDummyItem("X", "A", "hi_IN", 1, "en_us");
410             assertEquals(0, nonSystemLocale1.compareTo(nonSystemLocale2));
411             assertEquals(0, nonSystemLocale2.compareTo(nonSystemLocale1));
412         }
413     }
414 }