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