1/* 2 * Copyright (C) 2010 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 com.android.providers.contacts; 18 19import android.provider.ContactsContract.FullNameStyle; 20import android.test.AndroidTestCase; 21import android.test.suitebuilder.annotation.SmallTest; 22import android.util.Log; 23 24import java.text.Collator; 25import java.util.ArrayList; 26import java.util.Arrays; 27import java.util.HashSet; 28import java.util.Iterator; 29import java.util.List; 30import java.util.Locale; 31 32@SmallTest 33public class ContactLocaleUtilsTest extends AndroidTestCase { 34 private static final String TAG = "ContactLocaleUtilsTest"; 35 36 private static final String PHONE_NUMBER_1 = "+1 (650) 555-1212"; 37 private static final String PHONE_NUMBER_2 = "650-555-1212"; 38 private static final String LATIN_NAME = "John Smith"; 39 private static final String LATIN_NAME_2 = "John Paul Jones"; 40 private static final String KANJI_NAME = "\u65e5"; 41 private static final String ARABIC_NAME = "\u0646\u0648\u0631"; /* Noor */ 42 private static final String CHINESE_NAME = "\u675C\u9D51"; 43 private static final String SERBIAN_NAME = "\u0408\u0435\u043B\u0435\u043D\u0430"; 44 private static final String UKRAINIAN_NAME = "\u0407"; 45 private static final String UKRAINIAN_NAME_2 = "\u0490"; 46 private static final String CHINESE_LATIN_MIX_NAME_1 = "D\u675C\u9D51"; 47 private static final String CHINESE_LATIN_MIX_NAME_2 = "MARY \u675C\u9D51"; 48 private static final String[] CHINESE_NAME_KEY = {"\u9D51", "\u675C\u9D51", "JUAN", "DUJUAN", 49 "J", "DJ"}; 50 private static final String[] CHINESE_LATIN_MIX_NAME_1_KEY = {"\u9D51", "\u675C\u9D51", 51 "D \u675C\u9D51", "JUAN", "DUJUAN", "J", "DJ", "D DUJUAN", "DDJ"}; 52 private static final String[] CHINESE_LATIN_MIX_NAME_2_KEY = {"\u9D51", "\u675C\u9D51", 53 "MARY \u675C\u9D51", "JUAN", "DUJUAN", "MARY DUJUAN", "J", "DJ", "MDJ"}; 54 private static final String[] LATIN_NAME_KEY = {"John Smith", "Smith", "JS", "S"}; 55 private static final String[] LATIN_NAME_KEY_2 = { 56 "John Paul Jones", "Paul Jones", "Jones", "JPJ", "PJ", "J"}; 57 private static final String[] LABELS_EN_US = { 58 "", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 59 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 60 "#", ""}; 61 private static final String[] LABELS_JA_JP = { 62 "", "\u3042", "\u304B", "\u3055", "\u305F", "\u306A", "\u306F", 63 "\u307E", "\u3084", "\u3089", "\u308F", "\u4ED6", 64 "", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 65 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 66 "#", ""}; 67 private static final String[] LABELS_ZH_TW = { 68 "", "1\u5283", "2\u5283", "3\u5283", "4\u5283", "5\u5283", "6\u5283", 69 "7\u5283", "8\u5283", "9\u5283", "10\u5283", "11\u5283", "12\u5283", 70 "13\u5283", "14\u5283", "15\u5283", "16\u5283", "17\u5283", "18\u5283", 71 "19\u5283", "20\u5283", "21\u5283", "22\u5283", "23\u5283", "24\u5283", 72 "25\u5283", "26\u5283", "27\u5283", "28\u5283", "29\u5283", "30\u5283", 73 "31\u5283", "32\u5283", "33\u5283", 74 "35\u5283", "36\u5283", "39\u5283", "48\u5283", 75 "", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 76 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 77 "#", ""}; 78 private static final String[] LABELS_KO = { 79 "", "\u3131", "\u3134", "\u3137", "\u3139", "\u3141", "\u3142", 80 "\u3145", "\u3147", "\u3148", "\u314A", "\u314B", "\u314C", "\u314D", 81 "\u314E", 82 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 83 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 84 "#", ""}; 85 private static final String[] LABELS_AR = { 86 "", "\u0627", "\u0628", "\u062a", "\u062b", "\u062c", "\u062d", 87 "\u062e", "\u062f", "\u0630", "\u0631", "\u0632", "\u0633", "\u0634", 88 "\u0635", "\u0636", "\u0637", "\u0638", "\u0639", "\u063a", "\u0641", 89 "\u0642", "\u0643", "\u0644", "\u0645", "\u0646", "\u0647", "\u0648", 90 "\u064a", 91 "", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 92 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 93 "#", ""}; 94 95 private static final String JAPANESE_MISC = "\u4ed6"; 96 97 private static final Locale LOCALE_ARABIC = new Locale("ar"); 98 private static final Locale LOCALE_SERBIAN = new Locale("sr"); 99 private static final Locale LOCALE_UKRAINIAN = new Locale("uk"); 100 private boolean hasSimplifiedChineseCollator; 101 private boolean hasTraditionalChineseCollator; 102 private boolean hasJapaneseCollator; 103 private boolean hasKoreanCollator; 104 private boolean hasArabicCollator; 105 private boolean hasGermanCollator; 106 private boolean hasSerbianCollator; 107 private boolean hasUkrainianCollator; 108 109 @Override 110 protected void setUp() throws Exception { 111 super.setUp(); 112 final Locale locale[] = Collator.getAvailableLocales(); 113 for (int i = 0; i < locale.length; i++) { 114 if (LocaleSet.isLocaleSimplifiedChinese(locale[i])) { 115 hasSimplifiedChineseCollator = true; 116 } else if (LocaleSet.isLocaleTraditionalChinese(locale[i])) { 117 hasTraditionalChineseCollator = true; 118 } else if (locale[i].equals(Locale.JAPAN)) { 119 hasJapaneseCollator = true; 120 } else if (locale[i].equals(Locale.KOREA)) { 121 hasKoreanCollator = true; 122 } else if (locale[i].equals(LOCALE_ARABIC)) { 123 hasArabicCollator = true; 124 } else if (locale[i].equals(Locale.GERMANY)) { 125 hasGermanCollator = true; 126 } else if (locale[i].equals(LOCALE_SERBIAN)) { 127 hasSerbianCollator = true; 128 } else if (locale[i].equals(LOCALE_UKRAINIAN)) { 129 hasUkrainianCollator = true; 130 } 131 } 132 } 133 134 private String getLabel(String name) { 135 ContactLocaleUtils utils = ContactLocaleUtils.getInstance(); 136 int bucketIndex = utils.getBucketIndex(name); 137 return utils.getBucketLabel(bucketIndex); 138 } 139 140 private Iterator<String> getNameLookupKeys(String name, int nameStyle) { 141 ContactLocaleUtils utils = ContactLocaleUtils.getInstance(); 142 return utils.getNameLookupKeys(name, nameStyle); 143 } 144 145 private ArrayList<String> getLabels() { 146 ContactLocaleUtils utils = ContactLocaleUtils.getInstance(); 147 return utils.getLabels(); 148 } 149 150 public void testEnglishContactLocaleUtils() throws Exception { 151 ContactLocaleUtils.setLocale(Locale.ENGLISH); 152 assertEquals("#", getLabel(PHONE_NUMBER_1)); 153 assertEquals("#", getLabel(PHONE_NUMBER_2)); 154 assertEquals("J", getLabel(LATIN_NAME)); 155 assertEquals("", getLabel(CHINESE_NAME)); 156 assertEquals("D", getLabel(CHINESE_LATIN_MIX_NAME_1)); 157 assertEquals("B", getLabel("Bob Smith")); 158 159 if (hasArabicCollator) { 160 assertEquals("\u0646", getLabel(ARABIC_NAME)); 161 } 162 if (hasSerbianCollator) { 163 assertEquals("\u0408", getLabel(SERBIAN_NAME)); 164 } 165 if (hasUkrainianCollator) { 166 assertEquals("\u0407", getLabel(UKRAINIAN_NAME)); 167 } 168 169 assertNull(getNameLookupKeys(LATIN_NAME, FullNameStyle.UNDEFINED)); 170 verifyLabels(getLabels(), LABELS_EN_US); 171 } 172 173 public void testJapaneseContactLocaleUtils() throws Exception { 174 if (!hasJapaneseCollator) { 175 Log.w(TAG, "Japanese collator not found; skipping test"); 176 return; 177 } 178 179 ContactLocaleUtils.setLocale(Locale.JAPAN); 180 assertEquals("#", getLabel(PHONE_NUMBER_1)); 181 assertEquals("#", getLabel(PHONE_NUMBER_2)); 182 assertEquals(JAPANESE_MISC, getLabel(KANJI_NAME)); 183 assertEquals("J", getLabel(LATIN_NAME)); 184 assertEquals(JAPANESE_MISC, getLabel(CHINESE_NAME)); 185 assertEquals("D", getLabel(CHINESE_LATIN_MIX_NAME_1)); 186 187 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CJK)); 188 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CHINESE)); 189 190 assertEquals("B", getLabel("Bob Smith")); 191 verifyLabels(getLabels(), LABELS_JA_JP); 192 } 193 194 public void testChineseContactLocaleUtils() throws Exception { 195 if (!hasSimplifiedChineseCollator) { 196 Log.w(TAG, "Simplified Chinese collator not found; skipping test"); 197 return; 198 } 199 200 ContactLocaleUtils.setLocale(Locale.SIMPLIFIED_CHINESE); 201 assertEquals("#", getLabel(PHONE_NUMBER_1)); 202 assertEquals("#", getLabel(PHONE_NUMBER_2)); 203 assertEquals("J", getLabel(LATIN_NAME)); 204 assertEquals("D", getLabel(CHINESE_NAME)); 205 assertEquals("D", getLabel(CHINESE_LATIN_MIX_NAME_1)); 206 assertEquals("B", getLabel("Bob Smith")); 207 verifyLabels(getLabels(), LABELS_EN_US); 208 209 if (hasTraditionalChineseCollator) { 210 ContactLocaleUtils.setLocale(Locale.TRADITIONAL_CHINESE); 211 assertEquals("#", getLabel(PHONE_NUMBER_1)); 212 assertEquals("#", getLabel(PHONE_NUMBER_2)); 213 assertEquals("J", getLabel(LATIN_NAME)); 214 assertEquals("7\u5283", getLabel(CHINESE_NAME)); 215 assertEquals("D", getLabel(CHINESE_LATIN_MIX_NAME_1)); 216 } else { 217 Log.w(TAG, "Traditional Chinese collator not found"); 218 } 219 220 ContactLocaleUtils.setLocale(Locale.SIMPLIFIED_CHINESE); 221 Iterator<String> keys = getNameLookupKeys(CHINESE_NAME, 222 FullNameStyle.CHINESE); 223 verifyKeys(keys, CHINESE_NAME_KEY); 224 225 keys = getNameLookupKeys(CHINESE_LATIN_MIX_NAME_1, FullNameStyle.CHINESE); 226 verifyKeys(keys, CHINESE_LATIN_MIX_NAME_1_KEY); 227 228 keys = getNameLookupKeys(CHINESE_LATIN_MIX_NAME_2, FullNameStyle.CHINESE); 229 verifyKeys(keys, CHINESE_LATIN_MIX_NAME_2_KEY); 230 231 if (hasTraditionalChineseCollator) { 232 ContactLocaleUtils.setLocale(Locale.TRADITIONAL_CHINESE); 233 assertEquals("B", getLabel("Bob Smith")); 234 verifyLabels(getLabels(), LABELS_ZH_TW); 235 } 236 } 237 238 public void testPinyinEnabledSecondaryLocale() throws Exception { 239 if (!hasSimplifiedChineseCollator) { 240 Log.w(TAG, "Simplified Chinese collator not found; skipping test"); 241 return; 242 } 243 244 ContactLocaleUtils.setLocales( 245 new LocaleSet(Locale.ENGLISH, Locale.SIMPLIFIED_CHINESE)); 246 assertEquals("D", getLabel(CHINESE_NAME)); 247 248 Iterator<String> keys = getNameLookupKeys(CHINESE_NAME, 249 FullNameStyle.CHINESE); 250 verifyKeys(keys, CHINESE_NAME_KEY); 251 } 252 253 public void testPinyinDisabledSecondaryLocale() throws Exception { 254 if (!hasSimplifiedChineseCollator) { 255 Log.w(TAG, "Simplified Chinese collator not found; skipping test"); 256 return; 257 } 258 259 ContactLocaleUtils.setLocales( 260 new LocaleSet(Locale.ENGLISH, Locale.JAPAN)); 261 assertEquals("", getLabel(CHINESE_NAME)); 262 263 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CHINESE)); 264 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CJK)); 265 } 266 267 public void testChineseStyleNameWithDifferentLocale() throws Exception { 268 if (!hasSimplifiedChineseCollator) { 269 Log.w(TAG, "Simplified Chinese collator not found; skipping test"); 270 return; 271 } 272 273 ContactLocaleUtils.setLocale(Locale.ENGLISH); 274 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CHINESE)); 275 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CJK)); 276 277 ContactLocaleUtils.setLocale(Locale.SIMPLIFIED_CHINESE); 278 Iterator<String> keys = getNameLookupKeys(CHINESE_NAME, 279 FullNameStyle.CJK); 280 verifyKeys(keys, CHINESE_NAME_KEY); 281 keys = getNameLookupKeys(LATIN_NAME, FullNameStyle.WESTERN); 282 verifyKeys(keys, LATIN_NAME_KEY); 283 keys = getNameLookupKeys(LATIN_NAME_2, FullNameStyle.WESTERN); 284 verifyKeys(keys, LATIN_NAME_KEY_2); 285 286 if (hasTraditionalChineseCollator) { 287 ContactLocaleUtils.setLocale(Locale.TRADITIONAL_CHINESE); 288 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CJK)); 289 } 290 } 291 292 public void testKoreanContactLocaleUtils() throws Exception { 293 if (!hasKoreanCollator) { 294 Log.w(TAG, "Korean collator not found; skipping test"); 295 return; 296 } 297 298 ContactLocaleUtils.setLocale(Locale.KOREA); 299 assertEquals("\u3131", getLabel("\u1100")); 300 assertEquals("\u3131", getLabel("\u3131")); 301 assertEquals("\u3131", getLabel("\u1101")); 302 assertEquals("\u314e", getLabel("\u1161")); 303 assertEquals("B", getLabel("Bob Smith")); 304 verifyLabels(getLabels(), LABELS_KO); 305 } 306 307 public void testArabicContactLocaleUtils() throws Exception { 308 if (!hasArabicCollator) { 309 Log.w(TAG, "Arabic collator not found; skipping test"); 310 return; 311 } 312 313 ContactLocaleUtils.setLocale(LOCALE_ARABIC); 314 assertEquals("\u0646", getLabel(ARABIC_NAME)); 315 assertEquals("B", getLabel("Bob Smith")); 316 verifyLabels(getLabels(), LABELS_AR); 317 } 318 319 public void testSerbianContactLocaleUtils() throws Exception { 320 if (!hasSerbianCollator) { 321 Log.w(TAG, "Serbian collator not found; skipping test"); 322 return; 323 } 324 325 ContactLocaleUtils.setLocale(LOCALE_SERBIAN); 326 assertEquals("\u0408", getLabel(SERBIAN_NAME)); 327 assertEquals("B", getLabel("Bob Smith")); 328 } 329 330 public void testUkrainianContactLocaleUtils() throws Exception { 331 if (!hasUkrainianCollator) { 332 Log.w(TAG, "Ukrainian collator not found; skipping test"); 333 return; 334 } 335 336 ContactLocaleUtils.setLocale(LOCALE_UKRAINIAN); 337 assertEquals("\u0407", getLabel(UKRAINIAN_NAME)); 338 // ICU 52 has a bug whereby this letter has a bucket created only if 339 // Ukrainian is the primary language. Once this is fixed also test this 340 // label when in English locale. 341 assertEquals("\u0490", getLabel(UKRAINIAN_NAME_2)); 342 assertEquals("B", getLabel("Bob Smith")); 343 } 344 345 public void testGermanContactLocaleUtils() throws Exception { 346 if (!hasGermanCollator) { 347 return; 348 } 349 350 ContactLocaleUtils.setLocale(Locale.GERMANY); 351 assertEquals("S", getLabel("Sacher")); 352 353 // ICU 51 has labels Sch and St. These were removed in ICU 52 354 assertEquals("S", getLabel("Schiller")); 355 assertEquals("S", getLabel("Steiff")); 356 verifyLabels(getLabels(), LABELS_EN_US); 357 } 358 359 private void verifyKeys(final Iterator<String> resultKeys, final String[] expectedKeys) 360 throws Exception { 361 HashSet<String> allKeys = new HashSet<String>(); 362 while (resultKeys.hasNext()) { 363 allKeys.add(resultKeys.next()); 364 } 365 assertEquals(new HashSet<String>(Arrays.asList(expectedKeys)), allKeys); 366 } 367 368 // Verify that the initial set of resultLabels matches the expectedLabels. 369 // Ignore the (large) number of secondary locale labels that make up the 370 // tail labels in the result set right before the final "#" and "" buckets. 371 private void verifyLabels(final ArrayList<String> resultLabels, 372 final String[] expectedLabels) throws Exception { 373 final List<String> expectedLabelList = Arrays.asList(expectedLabels); 374 final int numLabels = expectedLabelList.size() - 2; 375 assertEquals(expectedLabelList.subList(0, numLabels), 376 resultLabels.subList(0, numLabels)); 377 } 378} 379