InputMethodTest.java revision 443c2bafd824779a75cd4b922b6839a8df9795e9
1/*
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
17package android.os;
18
19import com.android.internal.inputmethod.InputMethodUtils;
20
21import android.content.Context;
22import android.content.pm.ApplicationInfo;
23import android.content.pm.ResolveInfo;
24import android.content.pm.ServiceInfo;
25import android.test.InstrumentationTestCase;
26import android.test.suitebuilder.annotation.SmallTest;
27import android.view.inputmethod.InputMethodInfo;
28import android.view.inputmethod.InputMethodSubtype;
29import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
30
31import java.util.ArrayList;
32import java.util.List;
33
34public class InputMethodTest extends InstrumentationTestCase {
35    private static final boolean IS_AUX = true;
36    private static final boolean IS_DEFAULT = true;
37    private static final boolean IS_AUTO = true;
38    private static final ArrayList<InputMethodSubtype> NO_SUBTYPE = null;
39
40    @SmallTest
41    public void testDefaultEnabledImesWithDefaultVoiceIme() throws Exception {
42        final Context context = getInstrumentation().getTargetContext();
43        final ArrayList<InputMethodInfo> imis = new ArrayList<InputMethodInfo>();
44        imis.add(createDefaultAutoDummyVoiceIme());
45        imis.add(createNonDefaultAutoDummyVoiceIme0());
46        imis.add(createNonDefaultAutoDummyVoiceIme1());
47        imis.add(createNonDefaultDummyVoiceIme2());
48        imis.add(createDefaultDummyEnUSKeyboardIme());
49        imis.add(createNonDefaultDummyJaJPKeyboardIme());
50        imis.add(createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes());
51        final ArrayList<InputMethodInfo> enabledImis = InputMethodUtils.getDefaultEnabledImes(
52                context, true, imis);
53        assertEquals(2, enabledImis.size());
54        for (int i = 0; i < enabledImis.size(); ++i) {
55            final InputMethodInfo imi = enabledImis.get(0);
56            // "DummyDefaultAutoVoiceIme" and "DummyDefaultEnKeyboardIme"
57            if (imi.getPackageName().equals("DummyDefaultAutoVoiceIme")
58                    || imi.getPackageName().equals("DummyDefaultEnKeyboardIme")) {
59                continue;
60            } else {
61                fail("Invalid enabled subtype.");
62            }
63        }
64    }
65
66    @SmallTest
67    public void testDefaultEnabledImesWithOutDefaultVoiceIme() throws Exception {
68        final Context context = getInstrumentation().getTargetContext();
69        final ArrayList<InputMethodInfo> imis = new ArrayList<InputMethodInfo>();
70        imis.add(createNonDefaultAutoDummyVoiceIme0());
71        imis.add(createNonDefaultAutoDummyVoiceIme1());
72        imis.add(createNonDefaultDummyVoiceIme2());
73        imis.add(createDefaultDummyEnUSKeyboardIme());
74        imis.add(createNonDefaultDummyJaJPKeyboardIme());
75        imis.add(createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes());
76        final ArrayList<InputMethodInfo> enabledImis = InputMethodUtils.getDefaultEnabledImes(
77                context, true, imis);
78        assertEquals(3, enabledImis.size());
79        for (int i = 0; i < enabledImis.size(); ++i) {
80            final InputMethodInfo imi = enabledImis.get(0);
81            // "DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1" and
82            // "DummyDefaultEnKeyboardIme"
83            if (imi.getPackageName().equals("DummyNonDefaultAutoVoiceIme0")
84                    || imi.getPackageName().equals("DummyNonDefaultAutoVoiceIme1")
85                    || imi.getPackageName().equals("DummyDefaultEnKeyboardIme")) {
86                continue;
87            } else {
88                fail("Invalid enabled subtype.");
89            }
90        }
91    }
92
93    @SmallTest
94    public void testParcelable() throws Exception {
95        final ArrayList<InputMethodInfo> originalList = new ArrayList<InputMethodInfo>();
96        originalList.add(createNonDefaultAutoDummyVoiceIme0());
97        originalList.add(createNonDefaultAutoDummyVoiceIme1());
98        originalList.add(createNonDefaultDummyVoiceIme2());
99        originalList.add(createDefaultDummyEnUSKeyboardIme());
100        originalList.add(createNonDefaultDummyJaJPKeyboardIme());
101        originalList.add(createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes());
102
103        final List<InputMethodInfo> clonedList = cloneViaParcel(originalList);
104        assertNotNull(clonedList);
105        final List<InputMethodInfo> clonedClonedList = cloneViaParcel(clonedList);
106        assertNotNull(clonedClonedList);
107        assertEquals(originalList, clonedList);
108        assertEquals(clonedList, clonedClonedList);
109        assertEquals(originalList.size(), clonedList.size());
110        assertEquals(clonedList.size(), clonedClonedList.size());
111        for (int imeIndex = 0; imeIndex < originalList.size(); ++imeIndex) {
112            verifyEquality(originalList.get(imeIndex), clonedList.get(imeIndex));
113            verifyEquality(clonedList.get(imeIndex), clonedClonedList.get(imeIndex));
114        }
115    }
116
117    private static List<InputMethodInfo> cloneViaParcel(final List<InputMethodInfo> list) {
118        Parcel p = null;
119        try {
120            p = Parcel.obtain();
121            p.writeTypedList(list);
122            p.setDataPosition(0);
123            return p.createTypedArrayList(InputMethodInfo.CREATOR);
124        } finally {
125            if (p != null) {
126                p.recycle();
127            }
128        }
129    }
130
131    private static void verifyEquality(InputMethodInfo expected, InputMethodInfo actual) {
132        assertEquals(expected, actual);
133        assertEquals(expected.getSubtypeCount(), actual.getSubtypeCount());
134        for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) {
135            final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex);
136            final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex);
137            assertEquals(expectedSubtype, actualSubtype);
138            assertEquals(expectedSubtype.hashCode(), actualSubtype.hashCode());
139        }
140    }
141
142    private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
143            CharSequence label, boolean isAuxIme, boolean isDefault,
144            List<InputMethodSubtype> subtypes) {
145        final ResolveInfo ri = new ResolveInfo();
146        final ServiceInfo si = new ServiceInfo();
147        final ApplicationInfo ai = new ApplicationInfo();
148        ai.packageName = packageName;
149        ai.enabled = true;
150        ai.flags |= ApplicationInfo.FLAG_SYSTEM;
151        si.applicationInfo = ai;
152        si.enabled = true;
153        si.packageName = packageName;
154        si.name = name;
155        si.exported = true;
156        si.nonLocalizedLabel = label;
157        ri.serviceInfo = si;
158        return new InputMethodInfo(ri, isAuxIme, "", subtypes, 1, isDefault);
159    }
160
161    private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
162            boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
163        return new InputMethodSubtypeBuilder()
164                .setSubtypeNameResId(0)
165                .setSubtypeIconResId(0)
166                .setSubtypeLocale(locale)
167                .setSubtypeMode(mode)
168                .setSubtypeExtraValue("")
169                .setIsAuxiliary(isAuxiliary)
170                .setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype)
171                .build();
172    }
173
174    private static InputMethodInfo createDefaultAutoDummyVoiceIme() {
175        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
176        subtypes.add(createDummyInputMethodSubtype("auto", "voice", IS_AUX, IS_AUTO));
177        subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO));
178        return createDummyInputMethodInfo("DummyDefaultAutoVoiceIme", "dummy.voice0",
179                "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes);
180    }
181
182    private static InputMethodInfo createNonDefaultAutoDummyVoiceIme0() {
183        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
184        subtypes.add(createDummyInputMethodSubtype("auto", "voice", IS_AUX, IS_AUTO));
185        subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO));
186        return createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0", "dummy.voice1",
187                "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes);
188    }
189
190    private static InputMethodInfo createNonDefaultAutoDummyVoiceIme1() {
191        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
192        subtypes.add(createDummyInputMethodSubtype("auto", "voice", IS_AUX, IS_AUTO));
193        subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO));
194        return createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1", "dummy.voice2",
195                "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes);
196    }
197
198    private static InputMethodInfo createNonDefaultDummyVoiceIme2() {
199        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
200        subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO));
201        return createDummyInputMethodInfo("DummyNonDefaultVoiceIme2", "dummy.voice3",
202                "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes);
203    }
204
205    private static InputMethodInfo createDefaultDummyEnUSKeyboardIme() {
206        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
207        subtypes.add(createDummyInputMethodSubtype("en_US", "keyboard", !IS_AUX, !IS_AUTO));
208        return createDummyInputMethodInfo("DummyDefaultEnKeyboardIme", "dummy.keyboard0",
209                "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes);
210    }
211
212    private static InputMethodInfo createNonDefaultDummyJaJPKeyboardIme() {
213        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
214        subtypes.add(createDummyInputMethodSubtype("ja_JP", "keyboard", !IS_AUX, !IS_AUTO));
215        return createDummyInputMethodInfo("DummyNonDefaultJaJPKeyboardIme", "dummy.keyboard1",
216                "DummyKeyboard1", !IS_AUX, !IS_DEFAULT, subtypes);
217    }
218
219    // Although IMEs that have no subtype are considered to be deprecated, the Android framework
220    // must still be able to handle such IMEs as well as IMEs that have at least one subtype.
221    private static InputMethodInfo createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes() {
222        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
223        return createDummyInputMethodInfo("DummyNonDefaultJaJPKeyboardImeWithoutSubtypes",
224                "dummy.keyboard2", "DummyKeyboard2", !IS_AUX, !IS_DEFAULT, NO_SUBTYPE);
225    }
226}
227