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