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 17 package com.android.providers.contacts; 18 19 import android.provider.ContactsContract.FullNameStyle; 20 import android.test.AndroidTestCase; 21 import android.test.suitebuilder.annotation.SmallTest; 22 import android.util.Log; 23 24 import java.text.Collator; 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.HashSet; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.Locale; 31 32 @SmallTest 33 public 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 = "\u0406"; // І 45 private static final String UKRAINIAN_NAME_2 = "\u0407"; // Ї 46 private static final String UKRAINIAN_NAME_3 = "\u0490"; // Ґ 47 private static final String CHINESE_LATIN_MIX_NAME_1 = "D\u675C\u9D51"; // D杜鵑 48 private static final String CHINESE_LATIN_MIX_NAME_2 = "MARY \u675C\u9D51"; // MARY 杜鵑 49 private static final String[] CHINESE_NAME_KEY = { 50 "\u9D51",// 鵑 51 "\u675C\u9D51", // 杜鵑 52 "JUAN", "DUJUAN", "J", "DJ"}; 53 private static final String[] CHINESE_LATIN_MIX_NAME_1_KEY = { 54 "\u9D51", // 鵑 55 "\u675C\u9D51", // 杜鵑 56 "D \u675C\u9D51", // D 杜鵑 57 "JUAN", "DUJUAN", "J", "DJ", "D DUJUAN", "DDJ"}; 58 private static final String[] CHINESE_LATIN_MIX_NAME_2_KEY = { 59 "\u9D51", // 鵑 60 "\u675C\u9D51", // 杜鵑 61 "MARY \u675C\u9D51", // MARY 杜鵑 62 "JUAN", "DUJUAN", "MARY DUJUAN", "J", "DJ", "MDJ"}; 63 private static final String[] LATIN_NAME_KEY = {"John Smith", "Smith", "JS", "S"}; 64 private static final String[] LATIN_NAME_KEY_2 = { 65 "John Paul Jones", "Paul Jones", "Jones", "JPJ", "PJ", "J"}; 66 private static final String[] LABELS_EN_US = { 67 "\u2026", // … 68 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 69 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 70 "#", ""}; 71 private static final String[] LABELS_JA_JP = { 72 "…", "\u3042", "\u304B", "\u3055", "\u305F", "\u306A", "\u306F", 73 "\u307E", "\u3084", "\u3089", "\u308F", "\u4ED6", 74 "…", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 75 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 76 "#", ""}; 77 private static final String[] LABELS_ZH_TW = { 78 "…", "1\u5283", "2\u5283", "3\u5283", "4\u5283", "5\u5283", "6\u5283", 79 "7\u5283", "8\u5283", "9\u5283", "10\u5283", "11\u5283", "12\u5283", 80 "13\u5283", "14\u5283", "15\u5283", "16\u5283", "17\u5283", "18\u5283", 81 "19\u5283", "20\u5283", "21\u5283", "22\u5283", "23\u5283", "24\u5283", 82 "25\u5283", "26\u5283", "27\u5283", "28\u5283", "29\u5283", "30\u5283", 83 "31\u5283", "32\u5283", "33\u5283", 84 "35\u5283", "36\u5283", "39\u5283", "48\u5283", 85 "…", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 86 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 87 "#", ""}; 88 private static final String[] LABELS_KO = { 89 "…", "\u3131", "\u3134", "\u3137", "\u3139", "\u3141", "\u3142", 90 "\u3145", "\u3147", "\u3148", "\u314A", "\u314B", "\u314C", "\u314D", 91 "\u314E", "…", 92 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 93 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 94 "#", ""}; 95 private static final String[] LABELS_AR = { 96 "\u2026", "\u0627", "\u0628", "\u062a", "\u062b", "\u062c", "\u062d", 97 "\u062e", "\u062f", "\u0630", "\u0631", "\u0632", "\u0633", "\u0634", 98 "\u0635", "\u0636", "\u0637", "\u0638", "\u0639", "\u063a", "\u0641", 99 "\u0642", "\u0643", "\u0644", "\u0645", "\u0646", "\u0647", "\u0648", 100 "\u064a", 101 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 102 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 103 "#", ""}; 104 105 private static final String JAPANESE_MISC = "\u4ed6"; // 他 106 107 private static final Locale LOCALE_ARABIC = new Locale("ar"); 108 private static final Locale LOCALE_SERBIAN = new Locale("sr"); 109 private static final Locale LOCALE_UKRAINIAN = new Locale("uk"); 110 private static final Locale LOCALE_SPANISH = new Locale("es"); 111 private static final Locale LOCALE_GREEK = new Locale("el"); 112 113 private ContactLocaleUtils mTargetUtils; 114 setLocales(Locale... locales)115 private void setLocales(Locale... locales) { 116 mTargetUtils = ContactLocaleUtils.newInstanceForTest(locales); 117 } 118 getLabel(String name)119 private String getLabel(String name) { 120 int bucketIndex = mTargetUtils.getBucketIndex(name); 121 return mTargetUtils.getBucketLabel(bucketIndex); 122 } 123 getNameLookupKeys(String name, int nameStyle)124 private Iterator<String> getNameLookupKeys(String name, int nameStyle) { 125 return mTargetUtils.getNameLookupKeys(name, nameStyle); 126 } 127 getLabels()128 private ArrayList<String> getLabels() { 129 return mTargetUtils.getLabels(); 130 } 131 testEnglishContactLocaleUtils()132 public void testEnglishContactLocaleUtils() throws Exception { 133 setLocales(Locale.ENGLISH); 134 assertEquals("#", getLabel(PHONE_NUMBER_1)); 135 assertEquals("#", getLabel(PHONE_NUMBER_2)); 136 assertEquals("J", getLabel(LATIN_NAME)); 137 assertEquals("\u2026", getLabel(CHINESE_NAME)); 138 assertEquals("D", getLabel(CHINESE_LATIN_MIX_NAME_1)); 139 assertEquals("B", getLabel("Bob Smith")); 140 141 assertEquals("\u0646", getLabel(ARABIC_NAME)); 142 assertEquals("\u0408", getLabel(SERBIAN_NAME)); 143 // Updated in CLDR 27/ICU 55: 144 // http://cldr.unicode.org/index/downloads/cldr-27#TOC-Changes-to-Collation 145 assertEquals("\u0406", getLabel(UKRAINIAN_NAME)); 146 147 assertNull(getNameLookupKeys(LATIN_NAME, FullNameStyle.UNDEFINED)); 148 verifyLabels(getLabels(), LABELS_EN_US); 149 } 150 testJapaneseContactLocaleUtils()151 public void testJapaneseContactLocaleUtils() throws Exception { 152 setLocales(Locale.JAPAN); 153 assertEquals("#", getLabel(PHONE_NUMBER_1)); 154 assertEquals("#", getLabel(PHONE_NUMBER_2)); 155 assertEquals(JAPANESE_MISC, getLabel(KANJI_NAME)); 156 assertEquals("J", getLabel(LATIN_NAME)); 157 assertEquals(JAPANESE_MISC, getLabel(CHINESE_NAME)); 158 assertEquals("D", getLabel(CHINESE_LATIN_MIX_NAME_1)); 159 160 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CJK)); 161 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CHINESE)); 162 163 assertEquals("B", getLabel("Bob Smith")); 164 verifyLabels(getLabels(), LABELS_JA_JP); 165 } 166 testChineseContactLocaleUtils()167 public void testChineseContactLocaleUtils() throws Exception { 168 setLocales(Locale.SIMPLIFIED_CHINESE); 169 assertEquals("#", getLabel(PHONE_NUMBER_1)); 170 assertEquals("#", getLabel(PHONE_NUMBER_2)); 171 assertEquals("J", getLabel(LATIN_NAME)); 172 assertEquals("D", getLabel(CHINESE_NAME)); 173 assertEquals("D", getLabel(CHINESE_LATIN_MIX_NAME_1)); 174 assertEquals("B", getLabel("Bob Smith")); 175 verifyLabels(getLabels(), LABELS_EN_US); 176 177 setLocales(Locale.TRADITIONAL_CHINESE); 178 assertEquals("#", getLabel(PHONE_NUMBER_1)); 179 assertEquals("#", getLabel(PHONE_NUMBER_2)); 180 assertEquals("J", getLabel(LATIN_NAME)); 181 assertEquals("7\u5283", getLabel(CHINESE_NAME)); 182 assertEquals("D", getLabel(CHINESE_LATIN_MIX_NAME_1)); 183 184 setLocales(Locale.SIMPLIFIED_CHINESE); 185 Iterator<String> keys = getNameLookupKeys(CHINESE_NAME, 186 FullNameStyle.CHINESE); 187 verifyKeys(keys, CHINESE_NAME_KEY); 188 189 keys = getNameLookupKeys(CHINESE_LATIN_MIX_NAME_1, FullNameStyle.CHINESE); 190 verifyKeys(keys, CHINESE_LATIN_MIX_NAME_1_KEY); 191 192 keys = getNameLookupKeys(CHINESE_LATIN_MIX_NAME_2, FullNameStyle.CHINESE); 193 verifyKeys(keys, CHINESE_LATIN_MIX_NAME_2_KEY); 194 195 setLocales(Locale.TRADITIONAL_CHINESE); 196 assertEquals("B", getLabel("Bob Smith")); 197 verifyLabels(getLabels(), LABELS_ZH_TW); 198 } 199 testPinyinEnabledSecondaryLocale()200 public void testPinyinEnabledSecondaryLocale() throws Exception { 201 setLocales(Locale.ENGLISH, Locale.SIMPLIFIED_CHINESE); 202 assertEquals("D", getLabel(CHINESE_NAME)); 203 204 Iterator<String> keys = getNameLookupKeys(CHINESE_NAME, 205 FullNameStyle.CHINESE); 206 verifyKeys(keys, CHINESE_NAME_KEY); 207 } 208 testPinyinDisabledSecondaryLocale()209 public void testPinyinDisabledSecondaryLocale() throws Exception { 210 setLocales(Locale.ENGLISH, Locale.JAPAN); 211 assertEquals(JAPANESE_MISC, getLabel(CHINESE_NAME)); 212 213 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CHINESE)); 214 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CJK)); 215 } 216 testChineseChinese()217 public void testChineseChinese() throws Exception { 218 setLocales(Locale.SIMPLIFIED_CHINESE, Locale.TRADITIONAL_CHINESE); 219 assertEquals("D", getLabel(CHINESE_NAME)); // Prefer pinyin 220 221 setLocales(Locale.TRADITIONAL_CHINESE, Locale.SIMPLIFIED_CHINESE); 222 assertEquals("7\u5283", getLabel(CHINESE_NAME)); // 7劃 -- Prefer # of strokes 223 } 224 testJapaneseChinese()225 public void testJapaneseChinese() throws Exception { 226 setLocales(Locale.JAPAN, Locale.TRADITIONAL_CHINESE); 227 assertEquals(JAPANESE_MISC, getLabel(CHINESE_NAME)); // Prefer Japanese 228 229 setLocales(Locale.JAPAN, Locale.SIMPLIFIED_CHINESE); 230 assertEquals(JAPANESE_MISC, getLabel(CHINESE_NAME)); // Prefer Japanese 231 } 232 testChineseStyleNameWithDifferentLocale()233 public void testChineseStyleNameWithDifferentLocale() throws Exception { 234 setLocales(Locale.ENGLISH); 235 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CHINESE)); 236 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CJK)); 237 238 setLocales(Locale.SIMPLIFIED_CHINESE); 239 Iterator<String> keys = getNameLookupKeys(CHINESE_NAME, 240 FullNameStyle.CJK); 241 verifyKeys(keys, CHINESE_NAME_KEY); 242 keys = getNameLookupKeys(LATIN_NAME, FullNameStyle.WESTERN); 243 verifyKeys(keys, LATIN_NAME_KEY); 244 keys = getNameLookupKeys(LATIN_NAME_2, FullNameStyle.WESTERN); 245 verifyKeys(keys, LATIN_NAME_KEY_2); 246 247 setLocales(Locale.TRADITIONAL_CHINESE); 248 assertNull(getNameLookupKeys(CHINESE_NAME, FullNameStyle.CJK)); 249 } 250 testKoreanContactLocaleUtils()251 public void testKoreanContactLocaleUtils() throws Exception { 252 setLocales(Locale.KOREA); 253 assertEquals("\u3131", getLabel("\u1100")); 254 assertEquals("\u3131", getLabel("\u3131")); 255 assertEquals("\u3131", getLabel("\u1101")); 256 assertEquals("\u314e", getLabel("\u1161")); 257 assertEquals("B", getLabel("Bob Smith")); 258 verifyLabels(getLabels(), LABELS_KO); 259 } 260 testArabicContactLocaleUtils()261 public void testArabicContactLocaleUtils() throws Exception { 262 setLocales(LOCALE_ARABIC); 263 assertEquals("\u0646", getLabel(ARABIC_NAME)); 264 assertEquals("B", getLabel("Bob Smith")); 265 verifyLabels(getLabels(), LABELS_AR); 266 } 267 testSerbianContactLocaleUtils()268 public void testSerbianContactLocaleUtils() throws Exception { 269 setLocales(LOCALE_SERBIAN); 270 assertEquals("\u0408", getLabel(SERBIAN_NAME)); 271 assertEquals("B", getLabel("Bob Smith")); 272 } 273 testUkrainianContactLocaleUtils()274 public void testUkrainianContactLocaleUtils() throws Exception { 275 setLocales(LOCALE_UKRAINIAN); 276 assertEquals("\u0406", getLabel(UKRAINIAN_NAME)); 277 assertEquals("\u0407", getLabel(UKRAINIAN_NAME_2)); 278 assertEquals("\u0490", getLabel(UKRAINIAN_NAME_3)); 279 assertEquals("B", getLabel("Bob Smith")); 280 } 281 testGermanContactLocaleUtils()282 public void testGermanContactLocaleUtils() throws Exception { 283 setLocales(Locale.GERMANY); 284 assertEquals("S", getLabel("Sacher")); 285 286 // ICU 51 has labels Sch and St. These were removed in ICU 52 287 assertEquals("S", getLabel("Schiller")); 288 assertEquals("S", getLabel("Steiff")); 289 verifyLabels(getLabels(), LABELS_EN_US); 290 } 291 testOtherLocales()292 public void testOtherLocales() throws Exception { 293 setLocales(Locale.ENGLISH); 294 295 assertEquals("N", getLabel("n")); 296 assertEquals("N", getLabel("ñ")); 297 298 setLocales(LOCALE_SPANISH); 299 300 assertEquals("N", getLabel("n")); 301 assertEquals("Ñ", getLabel("ñ")); 302 303 setLocales(Locale.ENGLISH, LOCALE_SPANISH); 304 305 assertEquals("N", getLabel("n")); 306 assertEquals("N", getLabel("ñ")); // TODO This should ideally return Ñ. 307 308 } 309 verifyKeys(final Iterator<String> resultKeys, final String[] expectedKeys)310 private void verifyKeys(final Iterator<String> resultKeys, final String[] expectedKeys) 311 throws Exception { 312 HashSet<String> allKeys = new HashSet<String>(); 313 while (resultKeys.hasNext()) { 314 allKeys.add(resultKeys.next()); 315 } 316 assertEquals(new HashSet<String>(Arrays.asList(expectedKeys)), allKeys); 317 } 318 319 // Verify that the initial set of resultLabels matches the expectedLabels. 320 // Ignore the (large) number of secondary locale labels that make up the 321 // tail labels in the result set right before the final "#" and "" buckets. verifyLabels(final ArrayList<String> resultLabels, final String[] expectedLabels)322 private void verifyLabels(final ArrayList<String> resultLabels, 323 final String[] expectedLabels) throws Exception { 324 final List<String> expectedLabelList = Arrays.asList(expectedLabels); 325 final int numLabels = expectedLabelList.size() - 2; 326 assertEquals(expectedLabelList.subList(0, numLabels), 327 resultLabels.subList(0, numLabels)); 328 } 329 } 330