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