InputMethodSubtypeSwitchingControllerTest.java revision 529001f06761205bcaae1570d81556be397f56fb
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
17package android.os;
18
19import android.content.pm.ApplicationInfo;
20import android.content.pm.ResolveInfo;
21import android.content.pm.ServiceInfo;
22import android.test.InstrumentationTestCase;
23import android.test.suitebuilder.annotation.SmallTest;
24import android.view.inputmethod.InputMethodInfo;
25import android.view.inputmethod.InputMethodSubtype;
26import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
27
28import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl;
29import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
30import com.android.internal.inputmethod.InputMethodUtils;
31
32import java.util.ArrayList;
33import java.util.Arrays;
34import java.util.List;
35
36public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTestCase {
37    private static final String DUMMY_PACKAGE_NAME = "dymmy package name";
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<InputMethodSubtype>();
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        if (subtypes == null) {
80            items.add(new ImeSubtypeListItem(imeName, null /* variableName */, imi,
81                    NOT_A_SUBTYPE_ID, null, SYSTEM_LOCALE));
82        } else {
83            for (int i = 0; i < subtypes.size(); ++i) {
84                final String subtypeLocale = subtypeLocales.get(i);
85                items.add(new ImeSubtypeListItem(imeName, subtypeLocale, imi, i, subtypeLocale,
86                        SYSTEM_LOCALE));
87            }
88        }
89    }
90
91    private static List<ImeSubtypeListItem> createEnabledImeSubtypes() {
92        final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>();
93        addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme", Arrays.asList("en_US", "fr"),
94                true /* supportsSwitchingToNextInputMethod*/);
95        addDummyImeSubtypeListItems(items, "switchUnawareLatinIme", "switchUnawareLatinIme",
96                Arrays.asList("en_UK", "hi"),
97                false /* supportsSwitchingToNextInputMethod*/);
98        addDummyImeSubtypeListItems(items, "subtypeUnawareIme", "subtypeUnawareIme", null,
99                false /* supportsSwitchingToNextInputMethod*/);
100        addDummyImeSubtypeListItems(items, "JapaneseIme", "JapaneseIme", Arrays.asList("ja_JP"),
101                true /* supportsSwitchingToNextInputMethod*/);
102        addDummyImeSubtypeListItems(items, "switchUnawareJapaneseIme", "switchUnawareJapaneseIme",
103                Arrays.asList("ja_JP"), false /* supportsSwitchingToNextInputMethod*/);
104        return items;
105    }
106
107    private static List<ImeSubtypeListItem> createDisabledImeSubtypes() {
108        final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>();
109        addDummyImeSubtypeListItems(items,
110                "UnknownIme", "UnknownIme",
111                Arrays.asList("en_US", "hi"),
112                true /* supportsSwitchingToNextInputMethod*/);
113        addDummyImeSubtypeListItems(items,
114                "UnknownSwitchingUnawareIme", "UnknownSwitchingUnawareIme",
115                Arrays.asList("en_US"),
116                false /* supportsSwitchingToNextInputMethod*/);
117        addDummyImeSubtypeListItems(items, "UnknownSubtypeUnawareIme",
118                "UnknownSubtypeUnawareIme", null,
119                false /* supportsSwitchingToNextInputMethod*/);
120        return items;
121    }
122
123    private void assertNextInputMethod(final ControllerImpl controller,
124            final boolean onlyCurrentIme,
125            final ImeSubtypeListItem currentItem, final ImeSubtypeListItem nextItem) {
126        InputMethodSubtype subtype = null;
127        if (currentItem.mSubtypeName != null) {
128            subtype = createDummySubtype(currentItem.mSubtypeName.toString());
129        }
130        final ImeSubtypeListItem nextIme = controller.getNextInputMethod(onlyCurrentIme,
131                currentItem.mImi, subtype);
132        assertEquals(nextItem, nextIme);
133    }
134
135    private void assertRotationOrder(final ControllerImpl controller,
136            final boolean onlyCurrentIme,
137            final ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) {
138        final int N = expectedRotationOrderOfImeSubtypeList.length;
139        for (int i = 0; i < N; i++) {
140            final int currentIndex = i;
141            final int nextIndex = (currentIndex + 1) % N;
142            final ImeSubtypeListItem currentItem =
143                    expectedRotationOrderOfImeSubtypeList[currentIndex];
144            final ImeSubtypeListItem nextItem = expectedRotationOrderOfImeSubtypeList[nextIndex];
145            assertNextInputMethod(controller, onlyCurrentIme, currentItem, nextItem);
146        }
147    }
148
149    private void onUserAction(final ControllerImpl controller,
150            final ImeSubtypeListItem subtypeListItem) {
151        InputMethodSubtype subtype = null;
152        if (subtypeListItem.mSubtypeName != null) {
153            subtype = createDummySubtype(subtypeListItem.mSubtypeName.toString());
154        }
155        controller.onUserActionLocked(subtypeListItem.mImi, subtype);
156    }
157
158    @SmallTest
159    public void testControllerImpl() throws Exception {
160        final List<ImeSubtypeListItem> disabledItems = createDisabledImeSubtypes();
161        final ImeSubtypeListItem disabledIme_en_US = disabledItems.get(0);
162        final ImeSubtypeListItem disabledIme_hi = disabledItems.get(1);
163        final ImeSubtypeListItem disabledSwitchingUnawareIme = disabledItems.get(2);
164        final ImeSubtypeListItem disabledSubtypeUnawareIme = disabledItems.get(3);
165
166        final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes();
167        final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0);
168        final ImeSubtypeListItem latinIme_fr = enabledItems.get(1);
169        final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2);
170        final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3);
171        final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4);
172        final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5);
173        final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6);
174
175        final ControllerImpl controller = new ControllerImpl(enabledItems);
176
177        // switching-aware loop
178        assertRotationOrder(controller, false /* onlyCurrentIme */,
179                latinIme_en_US, latinIme_fr, japaneseIme_ja_JP);
180
181        // switching-unaware loop
182        assertRotationOrder(controller, false /* onlyCurrentIme */,
183                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
184                switchUnawareJapaneseIme_ja_JP);
185
186        // test onlyCurrentIme == true
187        assertRotationOrder(controller, true /* onlyCurrentIme */,
188                latinIme_en_US, latinIme_fr);
189        assertRotationOrder(controller, true /* onlyCurrentIme */,
190                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi);
191        assertNextInputMethod(controller, true /* onlyCurrentIme */,
192                subtypeUnawareIme, null);
193        assertNextInputMethod(controller, true /* onlyCurrentIme */,
194                japaneseIme_ja_JP, null);
195        assertNextInputMethod(controller, true /* onlyCurrentIme */,
196                switchUnawareJapaneseIme_ja_JP, null);
197
198        // Make sure that disabled IMEs are not accepted.
199        assertNextInputMethod(controller, false /* onlyCurrentIme */,
200                disabledIme_en_US, null);
201        assertNextInputMethod(controller, false /* onlyCurrentIme */,
202                disabledIme_hi, null);
203        assertNextInputMethod(controller, false /* onlyCurrentIme */,
204                disabledSwitchingUnawareIme, null);
205        assertNextInputMethod(controller, false /* onlyCurrentIme */,
206                disabledSubtypeUnawareIme, null);
207        assertNextInputMethod(controller, true /* onlyCurrentIme */,
208                disabledIme_en_US, null);
209        assertNextInputMethod(controller, true /* onlyCurrentIme */,
210                disabledIme_hi, null);
211        assertNextInputMethod(controller, true /* onlyCurrentIme */,
212                disabledSwitchingUnawareIme, null);
213        assertNextInputMethod(controller, true /* onlyCurrentIme */,
214                disabledSubtypeUnawareIme, null);
215    }
216
217    // This test is disabled until DynamicRotationList is enabled.
218    @SmallTest
219    public void DISABLED_testControllerImplWithUserAction() throws Exception {
220        final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes();
221        final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0);
222        final ImeSubtypeListItem latinIme_fr = enabledItems.get(1);
223        final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2);
224        final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3);
225        final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4);
226        final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5);
227        final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6);
228
229        final ControllerImpl controller = new ControllerImpl(enabledItems);
230
231        // === switching-aware loop ===
232        assertRotationOrder(controller, false /* onlyCurrentIme */,
233                latinIme_en_US, latinIme_fr, japaneseIme_ja_JP);
234        // Then notify that a user did something for latinIme_fr.
235        onUserAction(controller, latinIme_fr);
236        assertRotationOrder(controller, false /* onlyCurrentIme */,
237                latinIme_fr, latinIme_en_US, japaneseIme_ja_JP);
238        // Then notify that a user did something for latinIme_fr again.
239        onUserAction(controller, latinIme_fr);
240        assertRotationOrder(controller, false /* onlyCurrentIme */,
241                latinIme_fr, latinIme_en_US, japaneseIme_ja_JP);
242        // Then notify that a user did something for japaneseIme_ja_JP.
243        onUserAction(controller, latinIme_fr);
244        assertRotationOrder(controller, false /* onlyCurrentIme */,
245                japaneseIme_ja_JP, latinIme_fr, latinIme_en_US);
246        // Check onlyCurrentIme == true.
247        assertNextInputMethod(controller, true /* onlyCurrentIme */,
248                japaneseIme_ja_JP, null);
249        assertRotationOrder(controller, true /* onlyCurrentIme */,
250                latinIme_fr, latinIme_en_US);
251        assertRotationOrder(controller, true /* onlyCurrentIme */,
252                latinIme_en_US, latinIme_fr);
253
254        // === switching-unaware loop ===
255        assertRotationOrder(controller, false /* onlyCurrentIme */,
256                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
257                switchUnawareJapaneseIme_ja_JP);
258        // User action should be ignored for switching unaware IMEs.
259        onUserAction(controller, switchingUnawarelatinIme_hi);
260        assertRotationOrder(controller, false /* onlyCurrentIme */,
261                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
262                switchUnawareJapaneseIme_ja_JP);
263        // User action should be ignored for switching unaware IMEs.
264        onUserAction(controller, switchUnawareJapaneseIme_ja_JP);
265        assertRotationOrder(controller, false /* onlyCurrentIme */,
266                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme,
267                switchUnawareJapaneseIme_ja_JP);
268        // Check onlyCurrentIme == true.
269        assertRotationOrder(controller, true /* onlyCurrentIme */,
270                switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi);
271        assertNextInputMethod(controller, true /* onlyCurrentIme */,
272                subtypeUnawareIme, null);
273        assertNextInputMethod(controller, true /* onlyCurrentIme */,
274                switchUnawareJapaneseIme_ja_JP, null);
275    }
276}
277