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