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.server.inputmethod; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 23 import android.content.ComponentName; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.ResolveInfo; 26 import android.content.pm.ServiceInfo; 27 import android.view.inputmethod.InputMethodInfo; 28 import android.view.inputmethod.InputMethodSubtype; 29 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; 30 31 import androidx.test.filters.SmallTest; 32 import androidx.test.runner.AndroidJUnit4; 33 34 import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl; 35 import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; 36 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.List; 43 44 @SmallTest 45 @RunWith(AndroidJUnit4.class) 46 public class InputMethodSubtypeSwitchingControllerTest { 47 private static final String DUMMY_PACKAGE_NAME = "dummy package name"; 48 private static final String DUMMY_IME_LABEL = "dummy ime label"; 49 private static final String DUMMY_SETTING_ACTIVITY_NAME = ""; 50 private static final boolean DUMMY_IS_AUX_IME = false; 51 private static final boolean DUMMY_FORCE_DEFAULT = false; 52 private static final boolean DUMMY_IS_VR_IME = false; 53 private static final int DUMMY_IS_DEFAULT_RES_ID = 0; 54 private static final String SYSTEM_LOCALE = "en_US"; 55 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID; 56 createDummySubtype(final String locale)57 private static InputMethodSubtype createDummySubtype(final String locale) { 58 final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder(); 59 return builder.setSubtypeNameResId(0) 60 .setSubtypeIconResId(0) 61 .setSubtypeLocale(locale) 62 .setIsAsciiCapable(true) 63 .build(); 64 } 65 addDummyImeSubtypeListItems(List<ImeSubtypeListItem> items, String imeName, String imeLabel, List<String> subtypeLocales, boolean supportsSwitchingToNextInputMethod)66 private static void addDummyImeSubtypeListItems(List<ImeSubtypeListItem> items, 67 String imeName, String imeLabel, List<String> subtypeLocales, 68 boolean supportsSwitchingToNextInputMethod) { 69 final ResolveInfo ri = new ResolveInfo(); 70 final ServiceInfo si = new ServiceInfo(); 71 final ApplicationInfo ai = new ApplicationInfo(); 72 ai.packageName = DUMMY_PACKAGE_NAME; 73 ai.enabled = true; 74 si.applicationInfo = ai; 75 si.enabled = true; 76 si.packageName = DUMMY_PACKAGE_NAME; 77 si.name = imeName; 78 si.exported = true; 79 si.nonLocalizedLabel = imeLabel; 80 ri.serviceInfo = si; 81 List<InputMethodSubtype> subtypes = null; 82 if (subtypeLocales != null) { 83 subtypes = new ArrayList<InputMethodSubtype>(); 84 for (String subtypeLocale : subtypeLocales) { 85 subtypes.add(createDummySubtype(subtypeLocale)); 86 } 87 } 88 final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME, 89 DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID, 90 DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod, DUMMY_IS_VR_IME); 91 if (subtypes == null) { 92 items.add(new ImeSubtypeListItem(imeName, null /* variableName */, imi, 93 NOT_A_SUBTYPE_ID, null, SYSTEM_LOCALE)); 94 } else { 95 for (int i = 0; i < subtypes.size(); ++i) { 96 final String subtypeLocale = subtypeLocales.get(i); 97 items.add(new ImeSubtypeListItem(imeName, subtypeLocale, imi, i, subtypeLocale, 98 SYSTEM_LOCALE)); 99 } 100 } 101 } 102 createDummyItem(ComponentName imeComponentName, String imeName, String subtypeName, String subtypeLocale, int subtypeIndex, String systemLocale)103 private static ImeSubtypeListItem createDummyItem(ComponentName imeComponentName, 104 String imeName, String subtypeName, String subtypeLocale, int subtypeIndex, 105 String systemLocale) { 106 final ResolveInfo ri = new ResolveInfo(); 107 final ServiceInfo si = new ServiceInfo(); 108 final ApplicationInfo ai = new ApplicationInfo(); 109 ai.packageName = imeComponentName.getPackageName(); 110 ai.enabled = true; 111 si.applicationInfo = ai; 112 si.enabled = true; 113 si.packageName = imeComponentName.getPackageName(); 114 si.name = imeComponentName.getClassName(); 115 si.exported = true; 116 si.nonLocalizedLabel = DUMMY_IME_LABEL; 117 ri.serviceInfo = si; 118 ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); 119 subtypes.add(new InputMethodSubtypeBuilder() 120 .setSubtypeNameResId(0) 121 .setSubtypeIconResId(0) 122 .setSubtypeLocale(subtypeLocale) 123 .setIsAsciiCapable(true) 124 .build()); 125 final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME, 126 DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID, 127 DUMMY_FORCE_DEFAULT, true /* supportsSwitchingToNextInputMethod */, 128 DUMMY_IS_VR_IME); 129 return new ImeSubtypeListItem(imeName, subtypeName, imi, subtypeIndex, subtypeLocale, 130 systemLocale); 131 } 132 createEnabledImeSubtypes()133 private static List<ImeSubtypeListItem> createEnabledImeSubtypes() { 134 final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>(); 135 addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme", Arrays.asList("en_US", "fr"), 136 true /* supportsSwitchingToNextInputMethod*/); 137 addDummyImeSubtypeListItems(items, "switchUnawareLatinIme", "switchUnawareLatinIme", 138 Arrays.asList("en_UK", "hi"), 139 false /* supportsSwitchingToNextInputMethod*/); 140 addDummyImeSubtypeListItems(items, "subtypeUnawareIme", "subtypeUnawareIme", null, 141 false /* supportsSwitchingToNextInputMethod*/); 142 addDummyImeSubtypeListItems(items, "JapaneseIme", "JapaneseIme", Arrays.asList("ja_JP"), 143 true /* supportsSwitchingToNextInputMethod*/); 144 addDummyImeSubtypeListItems(items, "switchUnawareJapaneseIme", "switchUnawareJapaneseIme", 145 Arrays.asList("ja_JP"), false /* supportsSwitchingToNextInputMethod*/); 146 return items; 147 } 148 createDisabledImeSubtypes()149 private static List<ImeSubtypeListItem> createDisabledImeSubtypes() { 150 final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>(); 151 addDummyImeSubtypeListItems(items, 152 "UnknownIme", "UnknownIme", 153 Arrays.asList("en_US", "hi"), 154 true /* supportsSwitchingToNextInputMethod*/); 155 addDummyImeSubtypeListItems(items, 156 "UnknownSwitchingUnawareIme", "UnknownSwitchingUnawareIme", 157 Arrays.asList("en_US"), 158 false /* supportsSwitchingToNextInputMethod*/); 159 addDummyImeSubtypeListItems(items, "UnknownSubtypeUnawareIme", 160 "UnknownSubtypeUnawareIme", null, 161 false /* supportsSwitchingToNextInputMethod*/); 162 return items; 163 } 164 assertNextInputMethod(final ControllerImpl controller, final boolean onlyCurrentIme, final ImeSubtypeListItem currentItem, final ImeSubtypeListItem nextItem)165 private void assertNextInputMethod(final ControllerImpl controller, 166 final boolean onlyCurrentIme, 167 final ImeSubtypeListItem currentItem, final ImeSubtypeListItem nextItem) { 168 InputMethodSubtype subtype = null; 169 if (currentItem.mSubtypeName != null) { 170 subtype = createDummySubtype(currentItem.mSubtypeName.toString()); 171 } 172 final ImeSubtypeListItem nextIme = controller.getNextInputMethod(onlyCurrentIme, 173 currentItem.mImi, subtype); 174 assertEquals(nextItem, nextIme); 175 } 176 assertRotationOrder(final ControllerImpl controller, final boolean onlyCurrentIme, final ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList)177 private void assertRotationOrder(final ControllerImpl controller, 178 final boolean onlyCurrentIme, 179 final ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) { 180 final int N = expectedRotationOrderOfImeSubtypeList.length; 181 for (int i = 0; i < N; i++) { 182 final int currentIndex = i; 183 final int nextIndex = (currentIndex + 1) % N; 184 final ImeSubtypeListItem currentItem = 185 expectedRotationOrderOfImeSubtypeList[currentIndex]; 186 final ImeSubtypeListItem nextItem = expectedRotationOrderOfImeSubtypeList[nextIndex]; 187 assertNextInputMethod(controller, onlyCurrentIme, currentItem, nextItem); 188 } 189 } 190 onUserAction(final ControllerImpl controller, final ImeSubtypeListItem subtypeListItem)191 private void onUserAction(final ControllerImpl controller, 192 final ImeSubtypeListItem subtypeListItem) { 193 InputMethodSubtype subtype = null; 194 if (subtypeListItem.mSubtypeName != null) { 195 subtype = createDummySubtype(subtypeListItem.mSubtypeName.toString()); 196 } 197 controller.onUserActionLocked(subtypeListItem.mImi, subtype); 198 } 199 200 @Test testControllerImpl()201 public void testControllerImpl() throws Exception { 202 final List<ImeSubtypeListItem> disabledItems = createDisabledImeSubtypes(); 203 final ImeSubtypeListItem disabledIme_en_US = disabledItems.get(0); 204 final ImeSubtypeListItem disabledIme_hi = disabledItems.get(1); 205 final ImeSubtypeListItem disabledSwitchingUnawareIme = disabledItems.get(2); 206 final ImeSubtypeListItem disabledSubtypeUnawareIme = disabledItems.get(3); 207 208 final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes(); 209 final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0); 210 final ImeSubtypeListItem latinIme_fr = enabledItems.get(1); 211 final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2); 212 final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3); 213 final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4); 214 final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5); 215 final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6); 216 217 final ControllerImpl controller = ControllerImpl.createFrom( 218 null /* currentInstance */, enabledItems); 219 220 // switching-aware loop 221 assertRotationOrder(controller, false /* onlyCurrentIme */, 222 latinIme_en_US, latinIme_fr, japaneseIme_ja_JP); 223 224 // switching-unaware loop 225 assertRotationOrder(controller, false /* onlyCurrentIme */, 226 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, 227 switchUnawareJapaneseIme_ja_JP); 228 229 // test onlyCurrentIme == true 230 assertRotationOrder(controller, true /* onlyCurrentIme */, 231 latinIme_en_US, latinIme_fr); 232 assertRotationOrder(controller, true /* onlyCurrentIme */, 233 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi); 234 assertNextInputMethod(controller, true /* onlyCurrentIme */, 235 subtypeUnawareIme, null); 236 assertNextInputMethod(controller, true /* onlyCurrentIme */, 237 japaneseIme_ja_JP, null); 238 assertNextInputMethod(controller, true /* onlyCurrentIme */, 239 switchUnawareJapaneseIme_ja_JP, null); 240 241 // Make sure that disabled IMEs are not accepted. 242 assertNextInputMethod(controller, false /* onlyCurrentIme */, 243 disabledIme_en_US, null); 244 assertNextInputMethod(controller, false /* onlyCurrentIme */, 245 disabledIme_hi, null); 246 assertNextInputMethod(controller, false /* onlyCurrentIme */, 247 disabledSwitchingUnawareIme, null); 248 assertNextInputMethod(controller, false /* onlyCurrentIme */, 249 disabledSubtypeUnawareIme, null); 250 assertNextInputMethod(controller, true /* onlyCurrentIme */, 251 disabledIme_en_US, null); 252 assertNextInputMethod(controller, true /* onlyCurrentIme */, 253 disabledIme_hi, null); 254 assertNextInputMethod(controller, true /* onlyCurrentIme */, 255 disabledSwitchingUnawareIme, null); 256 assertNextInputMethod(controller, true /* onlyCurrentIme */, 257 disabledSubtypeUnawareIme, null); 258 } 259 260 @Test testControllerImplWithUserAction()261 public void testControllerImplWithUserAction() throws Exception { 262 final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes(); 263 final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0); 264 final ImeSubtypeListItem latinIme_fr = enabledItems.get(1); 265 final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2); 266 final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3); 267 final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4); 268 final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5); 269 final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6); 270 271 final ControllerImpl controller = ControllerImpl.createFrom( 272 null /* currentInstance */, enabledItems); 273 274 // === switching-aware loop === 275 assertRotationOrder(controller, false /* onlyCurrentIme */, 276 latinIme_en_US, latinIme_fr, japaneseIme_ja_JP); 277 // Then notify that a user did something for latinIme_fr. 278 onUserAction(controller, latinIme_fr); 279 assertRotationOrder(controller, false /* onlyCurrentIme */, 280 latinIme_fr, latinIme_en_US, japaneseIme_ja_JP); 281 // Then notify that a user did something for latinIme_fr again. 282 onUserAction(controller, latinIme_fr); 283 assertRotationOrder(controller, false /* onlyCurrentIme */, 284 latinIme_fr, latinIme_en_US, japaneseIme_ja_JP); 285 // Then notify that a user did something for japaneseIme_ja_JP. 286 onUserAction(controller, latinIme_fr); 287 assertRotationOrder(controller, false /* onlyCurrentIme */, 288 japaneseIme_ja_JP, latinIme_fr, latinIme_en_US); 289 // Check onlyCurrentIme == true. 290 assertNextInputMethod(controller, true /* onlyCurrentIme */, 291 japaneseIme_ja_JP, null); 292 assertRotationOrder(controller, true /* onlyCurrentIme */, 293 latinIme_fr, latinIme_en_US); 294 assertRotationOrder(controller, true /* onlyCurrentIme */, 295 latinIme_en_US, latinIme_fr); 296 297 // === switching-unaware loop === 298 assertRotationOrder(controller, false /* onlyCurrentIme */, 299 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, 300 switchUnawareJapaneseIme_ja_JP); 301 // User action should be ignored for switching unaware IMEs. 302 onUserAction(controller, switchingUnawarelatinIme_hi); 303 assertRotationOrder(controller, false /* onlyCurrentIme */, 304 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, 305 switchUnawareJapaneseIme_ja_JP); 306 // User action should be ignored for switching unaware IMEs. 307 onUserAction(controller, switchUnawareJapaneseIme_ja_JP); 308 assertRotationOrder(controller, false /* onlyCurrentIme */, 309 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, 310 switchUnawareJapaneseIme_ja_JP); 311 // Check onlyCurrentIme == true. 312 assertRotationOrder(controller, true /* onlyCurrentIme */, 313 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi); 314 assertNextInputMethod(controller, true /* onlyCurrentIme */, 315 subtypeUnawareIme, null); 316 assertNextInputMethod(controller, true /* onlyCurrentIme */, 317 switchUnawareJapaneseIme_ja_JP, null); 318 319 // Rotation order should be preserved when created with the same subtype list. 320 final List<ImeSubtypeListItem> sameEnabledItems = createEnabledImeSubtypes(); 321 final ControllerImpl newController = ControllerImpl.createFrom(controller, 322 sameEnabledItems); 323 assertRotationOrder(newController, false /* onlyCurrentIme */, 324 japaneseIme_ja_JP, latinIme_fr, latinIme_en_US); 325 assertRotationOrder(newController, false /* onlyCurrentIme */, 326 switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, 327 switchUnawareJapaneseIme_ja_JP); 328 329 // Rotation order should be initialized when created with a different subtype list. 330 final List<ImeSubtypeListItem> differentEnabledItems = Arrays.asList( 331 latinIme_en_US, latinIme_fr, switchingUnawarelatinIme_en_UK, 332 switchUnawareJapaneseIme_ja_JP); 333 final ControllerImpl anotherController = ControllerImpl.createFrom(controller, 334 differentEnabledItems); 335 assertRotationOrder(anotherController, false /* onlyCurrentIme */, 336 latinIme_en_US, latinIme_fr); 337 assertRotationOrder(anotherController, false /* onlyCurrentIme */, 338 switchingUnawarelatinIme_en_UK, switchUnawareJapaneseIme_ja_JP); 339 } 340 341 @Test testImeSubtypeListItem()342 public void testImeSubtypeListItem() throws Exception { 343 final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>(); 344 addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme", 345 Arrays.asList("en_US", "fr", "en", "en_uk", "enn", "e", "EN_US"), 346 true /* supportsSwitchingToNextInputMethod*/); 347 final ImeSubtypeListItem item_en_US = items.get(0); 348 final ImeSubtypeListItem item_fr = items.get(1); 349 final ImeSubtypeListItem item_en = items.get(2); 350 final ImeSubtypeListItem item_enn = items.get(3); 351 final ImeSubtypeListItem item_e = items.get(4); 352 final ImeSubtypeListItem item_EN_US = items.get(5); 353 354 assertTrue(item_en_US.mIsSystemLocale); 355 assertFalse(item_fr.mIsSystemLocale); 356 assertFalse(item_en.mIsSystemLocale); 357 assertFalse(item_en.mIsSystemLocale); 358 assertFalse(item_enn.mIsSystemLocale); 359 assertFalse(item_e.mIsSystemLocale); 360 assertFalse(item_EN_US.mIsSystemLocale); 361 362 assertTrue(item_en_US.mIsSystemLanguage); 363 assertFalse(item_fr.mIsSystemLanguage); 364 assertTrue(item_en.mIsSystemLanguage); 365 assertFalse(item_enn.mIsSystemLocale); 366 assertFalse(item_e.mIsSystemLocale); 367 assertFalse(item_EN_US.mIsSystemLocale); 368 } 369 370 @Test testImeSubtypeListComparator()371 public void testImeSubtypeListComparator() throws Exception { 372 final ComponentName imeX1 = new ComponentName("com.example.imeX", "Ime1"); 373 final ComponentName imeX2 = new ComponentName("com.example.imeX", "Ime2"); 374 final ComponentName imeY1 = new ComponentName("com.example.imeY", "Ime1"); 375 final ComponentName imeZ1 = new ComponentName("com.example.imeZ", "Ime1"); 376 { 377 final List<ImeSubtypeListItem> items = Arrays.asList( 378 // Subtypes of two IMEs that have the same display name "X". 379 // Subtypes that has the same locale of the system's. 380 createDummyItem(imeX1, "X", "E", "en_US", 0, "en_US"), 381 createDummyItem(imeX2, "X", "E", "en_US", 0, "en_US"), 382 createDummyItem(imeX1, "X", "Z", "en_US", 3, "en_US"), 383 createDummyItem(imeX2, "X", "Z", "en_US", 3, "en_US"), 384 createDummyItem(imeX1, "X", "", "en_US", 6, "en_US"), 385 createDummyItem(imeX2, "X", "", "en_US", 6, "en_US"), 386 // Subtypes that has the same language of the system's. 387 createDummyItem(imeX1, "X", "E", "en", 1, "en_US"), 388 createDummyItem(imeX2, "X", "E", "en", 1, "en_US"), 389 createDummyItem(imeX1, "X", "Z", "en", 4, "en_US"), 390 createDummyItem(imeX2, "X", "Z", "en", 4, "en_US"), 391 createDummyItem(imeX1, "X", "", "en", 7, "en_US"), 392 createDummyItem(imeX2, "X", "", "en", 7, "en_US"), 393 // Subtypes that has different language than the system's. 394 createDummyItem(imeX1, "X", "A", "hi_IN", 27, "en_US"), 395 createDummyItem(imeX2, "X", "A", "hi_IN", 27, "en_US"), 396 createDummyItem(imeX1, "X", "E", "ja", 2, "en_US"), 397 createDummyItem(imeX2, "X", "E", "ja", 2, "en_US"), 398 createDummyItem(imeX1, "X", "Z", "ja", 5, "en_US"), 399 createDummyItem(imeX2, "X", "Z", "ja", 5, "en_US"), 400 createDummyItem(imeX1, "X", "", "ja", 8, "en_US"), 401 createDummyItem(imeX2, "X", "", "ja", 8, "en_US"), 402 403 // Subtypes of IME "Y". 404 // Subtypes that has the same locale of the system's. 405 createDummyItem(imeY1, "Y", "E", "en_US", 9, "en_US"), 406 createDummyItem(imeY1, "Y", "Z", "en_US", 12, "en_US"), 407 createDummyItem(imeY1, "Y", "", "en_US", 15, "en_US"), 408 // Subtypes that has the same language of the system's. 409 createDummyItem(imeY1, "Y", "E", "en", 10, "en_US"), 410 createDummyItem(imeY1, "Y", "Z", "en", 13, "en_US"), 411 createDummyItem(imeY1, "Y", "", "en", 16, "en_US"), 412 // Subtypes that has different language than the system's. 413 createDummyItem(imeY1, "Y", "A", "hi_IN", 28, "en_US"), 414 createDummyItem(imeY1, "Y", "E", "ja", 11, "en_US"), 415 createDummyItem(imeY1, "Y", "Z", "ja", 14, "en_US"), 416 createDummyItem(imeY1, "Y", "", "ja", 17, "en_US"), 417 418 // Subtypes of IME Z. 419 // Subtypes that has the same locale of the system's. 420 createDummyItem(imeZ1, "", "E", "en_US", 18, "en_US"), 421 createDummyItem(imeZ1, "", "Z", "en_US", 21, "en_US"), 422 createDummyItem(imeZ1, "", "", "en_US", 24, "en_US"), 423 // Subtypes that has the same language of the system's. 424 createDummyItem(imeZ1, "", "E", "en", 19, "en_US"), 425 createDummyItem(imeZ1, "", "Z", "en", 22, "en_US"), 426 createDummyItem(imeZ1, "", "", "en", 25, "en_US"), 427 // Subtypes that has different language than the system's. 428 createDummyItem(imeZ1, "", "A", "hi_IN", 29, "en_US"), 429 createDummyItem(imeZ1, "", "E", "ja", 20, "en_US"), 430 createDummyItem(imeZ1, "", "Z", "ja", 23, "en_US"), 431 createDummyItem(imeZ1, "", "", "ja", 26, "en_US")); 432 433 // Ensure {@link java.lang.Comparable#compareTo} contracts are satisfied. 434 for (int i = 0; i < items.size(); ++i) { 435 final ImeSubtypeListItem item1 = items.get(i); 436 // Ensures sgn(x.compareTo(y)) == -sgn(y.compareTo(x)). 437 assertTrue(item1 + " has the same order of itself", item1.compareTo(item1) == 0); 438 // Ensures (x.compareTo(y) > 0 && y.compareTo(z) > 0) implies x.compareTo(z) > 0. 439 for (int j = i + 1; j < items.size(); ++j) { 440 final ImeSubtypeListItem item2 = items.get(j); 441 // Ensures sgn(x.compareTo(y)) == -sgn(y.compareTo(x)). 442 assertTrue(item1 + " is less than " + item2, item1.compareTo(item2) < 0); 443 assertTrue(item2 + " is greater than " + item1, item2.compareTo(item1) > 0); 444 } 445 } 446 } 447 448 { 449 // Following two items have the same priority. 450 final ImeSubtypeListItem nonSystemLocale1 = 451 createDummyItem(imeX1, "X", "A", "ja_JP", 0, "en_US"); 452 final ImeSubtypeListItem nonSystemLocale2 = 453 createDummyItem(imeX1, "X", "A", "hi_IN", 1, "en_US"); 454 assertTrue(nonSystemLocale1.compareTo(nonSystemLocale2) == 0); 455 assertTrue(nonSystemLocale2.compareTo(nonSystemLocale1) == 0); 456 // But those aren't equal to each other. 457 assertFalse(nonSystemLocale1.equals(nonSystemLocale2)); 458 assertFalse(nonSystemLocale2.equals(nonSystemLocale1)); 459 } 460 461 { 462 // Check if ComponentName is also taken into account when comparing two items. 463 final ImeSubtypeListItem ime1 = createDummyItem(imeX1, "X", "A", "ja_JP", 0, "en_US"); 464 final ImeSubtypeListItem ime2 = createDummyItem(imeX2, "X", "A", "ja_JP", 0, "en_US"); 465 assertTrue(ime1.compareTo(ime2) < 0); 466 assertTrue(ime2.compareTo(ime1) > 0); 467 // But those aren't equal to each other. 468 assertFalse(ime1.equals(ime2)); 469 assertFalse(ime2.equals(ime1)); 470 } 471 } 472 } 473