1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 /* 5 ******************************************************************************* 6 * Copyright (C) 2004-2014, International Business Machines Corporation and 7 * others. All Rights Reserved. 8 ******************************************************************************* 9 */ 10 package ohos.global.icu.util; 11 12 import java.util.ArrayList; 13 import java.util.Arrays; 14 import java.util.BitSet; 15 import java.util.Date; 16 import java.util.HashMap; 17 import java.util.List; 18 import java.util.Map; 19 import java.util.MissingResourceException; 20 import java.util.ResourceBundle; 21 import java.util.Set; 22 23 import ohos.global.icu.impl.Utility; 24 import ohos.global.icu.text.BreakIterator; 25 import ohos.global.icu.text.Collator; 26 import ohos.global.icu.text.DateFormat; 27 import ohos.global.icu.text.NumberFormat; 28 import ohos.global.icu.text.SimpleDateFormat; 29 30 /** 31 * This convenience class provides a mechanism for bundling together different 32 * globalization preferences. It includes: 33 * <ul> 34 * <li>A list of locales/languages in preference order</li> 35 * <li>A territory</li> 36 * <li>A currency</li> 37 * <li>A timezone</li> 38 * <li>A calendar</li> 39 * <li>A collator (for language-sensitive sorting, searching, and matching).</li> 40 * <li>Explicit overrides for date/time formats, etc.</li> 41 * </ul> 42 * The class will heuristically compute implicit, heuristic values for the above 43 * based on available data if explicit values are not supplied. These implicit 44 * values can be presented to users for confirmation, or replacement if the 45 * values are incorrect. 46 * <p> 47 * To reset any explicit field so that it will get heuristic values, pass in 48 * null. For example, myPreferences.setLocale(null); 49 * <p> 50 * All of the heuristics can be customized by subclasses, by overriding 51 * getTerritory(), guessCollator(), etc. 52 * <p> 53 * The class also supplies display names for languages, scripts, territories, 54 * currencies, timezones, etc. These are computed according to the 55 * locale/language preference list. Thus, if the preference is Breton; French; 56 * English, then the display name for a language will be returned in Breton if 57 * available, otherwise in French if available, otherwise in English. 58 * <p> 59 * The codes used to reference territory, currency, etc. are as defined elsewhere 60 * in ICU, and are taken from CLDR (which reflects RFC 3066bis usage, ISO 4217, 61 * and the TZ Timezone database identifiers). 62 * <p> 63 * <b>This is at a prototype stage, and has not incorporated all the design 64 * changes that we would like yet; further feedback is welcome.</b></p> 65 * Note: 66 * <ul> 67 * <li>to get the display name for the first day of the week, use the calendar + 68 * display names.</li> 69 * <li>to get the work days, ask the calendar (when that is available).</li> 70 * <li>to get papersize / measurement system/bidi-orientation, ask the locale 71 * (when that is available there)</li> 72 * <li>to get the field order in a date, and whether a time is 24hour or not, 73 * ask the DateFormat (when that is available there)</li> 74 * <li>it will support HOST locale when it becomes available (it is a special 75 * locale that will ask the services to use the host platform's values).</li> 76 * </ul> 77 * 78 * @hide exposed on OHOS 79 * @hide draft / provisional / internal are hidden on OHOS 80 */ 81 82 //TODO: 83 // - Add Holidays 84 // - Add convenience to get/take Locale as well as ULocale. 85 // - Add Lenient datetime formatting when that is available. 86 // - Should this be serializable? 87 // - Other utilities? 88 89 public class GlobalizationPreferences implements Freezable<GlobalizationPreferences> { 90 91 /** 92 * Default constructor 93 * @hide draft / provisional / internal are hidden on OHOS 94 */ GlobalizationPreferences()95 public GlobalizationPreferences(){} 96 /** 97 * Number Format type 98 * @hide draft / provisional / internal are hidden on OHOS 99 */ 100 public static final int 101 NF_NUMBER = 0, // NumberFormat.NUMBERSTYLE 102 NF_CURRENCY = 1, // NumberFormat.CURRENCYSTYLE 103 NF_PERCENT = 2, // NumberFormat.PERCENTSTYLE 104 NF_SCIENTIFIC = 3, // NumberFormat.SCIENTIFICSTYLE 105 NF_INTEGER = 4; // NumberFormat.INTEGERSTYLE 106 107 private static final int NF_LIMIT = NF_INTEGER + 1; 108 109 /** 110 * Date Format type 111 * @hide draft / provisional / internal are hidden on OHOS 112 */ 113 public static final int 114 DF_FULL = DateFormat.FULL, // 0 115 DF_LONG = DateFormat.LONG, // 1 116 DF_MEDIUM = DateFormat.MEDIUM, // 2 117 DF_SHORT = DateFormat.SHORT, // 3 118 DF_NONE = 4; 119 120 private static final int DF_LIMIT = DF_NONE + 1; 121 122 /** 123 * For selecting a choice of display names 124 * @hide draft / provisional / internal are hidden on OHOS 125 */ 126 public static final int 127 ID_LOCALE = 0, 128 ID_LANGUAGE = 1, 129 ID_SCRIPT = 2, 130 ID_TERRITORY = 3, 131 ID_VARIANT = 4, 132 ID_KEYWORD = 5, 133 ID_KEYWORD_VALUE = 6, 134 ID_CURRENCY = 7, 135 ID_CURRENCY_SYMBOL = 8, 136 ID_TIMEZONE = 9; 137 138 //private static final int ID_LIMIT = ID_TIMEZONE + 1; 139 140 /** 141 * Break iterator type 142 * @hide draft / provisional / internal are hidden on OHOS 143 */ 144 public static final int 145 BI_CHARACTER = BreakIterator.KIND_CHARACTER, // 0 146 BI_WORD = BreakIterator.KIND_WORD, // 1 147 BI_LINE = BreakIterator.KIND_LINE, // 2 148 BI_SENTENCE = BreakIterator.KIND_SENTENCE, // 3 149 BI_TITLE = BreakIterator.KIND_TITLE; // 4 150 151 private static final int BI_LIMIT = BI_TITLE + 1; 152 153 /** 154 * Sets the language/locale priority list. If other information is 155 * not (yet) available, this is used to to produce a default value 156 * for the appropriate territory, currency, timezone, etc. The 157 * user should be given the opportunity to correct those defaults 158 * in case they are incorrect. 159 * 160 * @param inputLocales list of locales in priority order, eg {"be", "fr"} 161 * for Breton first, then French if that fails. 162 * @return this, for chaining 163 * @hide draft / provisional / internal are hidden on OHOS 164 */ setLocales(List<ULocale> inputLocales)165 public GlobalizationPreferences setLocales(List<ULocale> inputLocales) { 166 if (isFrozen()) { 167 throw new UnsupportedOperationException("Attempt to modify immutable object"); 168 } 169 locales = processLocales(inputLocales); 170 return this; 171 } 172 173 /** 174 * Get a copy of the language/locale priority list 175 * 176 * @return a copy of the language/locale priority list. 177 * @hide draft / provisional / internal are hidden on OHOS 178 */ getLocales()179 public List<ULocale> getLocales() { 180 List<ULocale> result; 181 if (locales == null) { 182 result = guessLocales(); 183 } else { 184 result = new ArrayList<>(); 185 result.addAll(locales); 186 } 187 return result; 188 } 189 190 /** 191 * Convenience function for getting the locales in priority order 192 * @param index The index (0..n) of the desired item. 193 * @return desired item. null if index is out of range 194 * @hide draft / provisional / internal are hidden on OHOS 195 */ getLocale(int index)196 public ULocale getLocale(int index) { 197 List<ULocale> lcls = locales; 198 if (lcls == null) { 199 lcls = guessLocales(); 200 } 201 if (index >= 0 && index < lcls.size()) { 202 return lcls.get(index); 203 } 204 return null; 205 } 206 207 /** 208 * Convenience routine for setting the language/locale priority 209 * list from an array. 210 * 211 * @see #setLocales(List locales) 212 * @param uLocales list of locales in an array 213 * @return this, for chaining 214 * @hide draft / provisional / internal are hidden on OHOS 215 */ setLocales(ULocale[] uLocales)216 public GlobalizationPreferences setLocales(ULocale[] uLocales) { 217 if (isFrozen()) { 218 throw new UnsupportedOperationException("Attempt to modify immutable object"); 219 } 220 return setLocales(Arrays.asList(uLocales)); 221 } 222 223 /** 224 * Convenience routine for setting the language/locale priority 225 * list from a single locale/language. 226 * 227 * @see #setLocales(List locales) 228 * @param uLocale single locale 229 * @return this, for chaining 230 * @hide draft / provisional / internal are hidden on OHOS 231 */ setLocale(ULocale uLocale)232 public GlobalizationPreferences setLocale(ULocale uLocale) { 233 if (isFrozen()) { 234 throw new UnsupportedOperationException("Attempt to modify immutable object"); 235 } 236 return setLocales(new ULocale[]{uLocale}); 237 } 238 239 /** 240 * Convenience routine for setting the locale priority list from 241 * an Accept-Language string. 242 * @see #setLocales(List locales) 243 * @param acceptLanguageString Accept-Language list, as defined by 244 * Section 14.4 of the RFC 2616 (HTTP 1.1) 245 * @return this, for chaining 246 * @hide draft / provisional / internal are hidden on OHOS 247 */ setLocales(String acceptLanguageString)248 public GlobalizationPreferences setLocales(String acceptLanguageString) { 249 if (isFrozen()) { 250 throw new UnsupportedOperationException("Attempt to modify immutable object"); 251 } 252 Set<ULocale> acceptSet = LocalePriorityList.add(acceptLanguageString).build().getULocales(); 253 // processLocales() wants a List even though it only iterates front-to-back. 254 locales = processLocales(new ArrayList<>(acceptSet)); 255 return this; 256 } 257 258 /** 259 * Convenience function to get a ResourceBundle instance using 260 * the specified base name based on the language/locale priority list 261 * stored in this object. 262 * 263 * @param baseName the base name of the resource bundle, a fully qualified 264 * class name 265 * @return a resource bundle for the given base name and locale based on the 266 * language/locale priority list stored in this object 267 * @hide draft / provisional / internal are hidden on OHOS 268 */ getResourceBundle(String baseName)269 public ResourceBundle getResourceBundle(String baseName) { 270 return getResourceBundle(baseName, null); 271 } 272 273 /** 274 * Convenience function to get a ResourceBundle instance using 275 * the specified base name and class loader based on the language/locale 276 * priority list stored in this object. 277 * 278 * @param baseName the base name of the resource bundle, a fully qualified 279 * class name 280 * @param loader the class object from which to load the resource bundle 281 * @return a resource bundle for the given base name and locale based on the 282 * language/locale priority list stored in this object 283 * @hide draft / provisional / internal are hidden on OHOS 284 */ getResourceBundle(String baseName, ClassLoader loader)285 public ResourceBundle getResourceBundle(String baseName, ClassLoader loader) { 286 UResourceBundle urb = null; 287 UResourceBundle candidate = null; 288 String actualLocaleName = null; 289 List<ULocale> fallbacks = getLocales(); 290 for (int i = 0; i < fallbacks.size(); i++) { 291 String localeName = (fallbacks.get(i)).toString(); 292 if (actualLocaleName != null && localeName.equals(actualLocaleName)) { 293 // Actual locale name in the previous round may exactly matches 294 // with the next fallback locale 295 urb = candidate; 296 break; 297 } 298 try { 299 if (loader == null) { 300 candidate = UResourceBundle.getBundleInstance(baseName, localeName); 301 } 302 else { 303 candidate = UResourceBundle.getBundleInstance(baseName, localeName, loader); 304 } 305 if (candidate != null) { 306 actualLocaleName = candidate.getULocale().getName(); 307 if (actualLocaleName.equals(localeName)) { 308 urb = candidate; 309 break; 310 } 311 if (urb == null) { 312 // Preserve the available bundle as the last resort 313 urb = candidate; 314 } 315 } 316 } catch (MissingResourceException mre) { 317 actualLocaleName = null; 318 continue; 319 } 320 } 321 if (urb == null) { 322 throw new MissingResourceException("Can't find bundle for base name " 323 + baseName, baseName, ""); 324 } 325 return urb; 326 } 327 328 /** 329 * Sets the territory, which is a valid territory according to for 330 * RFC 3066 (or successor). If not otherwise set, default 331 * currency and timezone values will be set from this. The user 332 * should be given the opportunity to correct those defaults in 333 * case they are incorrect. 334 * 335 * @param territory code 336 * @return this, for chaining 337 * @hide draft / provisional / internal are hidden on OHOS 338 */ setTerritory(String territory)339 public GlobalizationPreferences setTerritory(String territory) { 340 if (isFrozen()) { 341 throw new UnsupportedOperationException("Attempt to modify immutable object"); 342 } 343 this.territory = territory; // immutable, so don't need to clone 344 return this; 345 } 346 347 /** 348 * Gets the territory setting. If it wasn't explicitly set, it is 349 * computed from the general locale setting. 350 * 351 * @return territory code, explicit or implicit. 352 * @hide draft / provisional / internal are hidden on OHOS 353 */ getTerritory()354 public String getTerritory() { 355 if (territory == null) { 356 return guessTerritory(); 357 } 358 return territory; // immutable, so don't need to clone 359 } 360 361 /** 362 * Sets the currency code. If this has not been set, uses default for territory. 363 * 364 * @param currency Valid ISO 4217 currency code. 365 * @return this, for chaining 366 * @hide draft / provisional / internal are hidden on OHOS 367 */ setCurrency(Currency currency)368 public GlobalizationPreferences setCurrency(Currency currency) { 369 if (isFrozen()) { 370 throw new UnsupportedOperationException("Attempt to modify immutable object"); 371 } 372 this.currency = currency; // immutable, so don't need to clone 373 return this; 374 } 375 376 /** 377 * Get a copy of the currency computed according to the settings. 378 * 379 * @return currency code, explicit or implicit. 380 * @hide draft / provisional / internal are hidden on OHOS 381 */ getCurrency()382 public Currency getCurrency() { 383 if (currency == null) { 384 return guessCurrency(); 385 } 386 return currency; // immutable, so don't have to clone 387 } 388 389 /** 390 * Sets the calendar. If this has not been set, uses default for territory. 391 * 392 * @param calendar arbitrary calendar 393 * @return this, for chaining 394 * @hide draft / provisional / internal are hidden on OHOS 395 */ setCalendar(Calendar calendar)396 public GlobalizationPreferences setCalendar(Calendar calendar) { 397 if (isFrozen()) { 398 throw new UnsupportedOperationException("Attempt to modify immutable object"); 399 } 400 this.calendar = (Calendar) calendar.clone(); // clone for safety 401 return this; 402 } 403 404 /** 405 * Get a copy of the calendar according to the settings. 406 * 407 * @return calendar explicit or implicit. 408 * @hide draft / provisional / internal are hidden on OHOS 409 */ getCalendar()410 public Calendar getCalendar() { 411 if (calendar == null) { 412 return guessCalendar(); 413 } 414 Calendar temp = (Calendar) calendar.clone(); // clone for safety 415 temp.setTimeZone(getTimeZone()); 416 temp.setTimeInMillis(System.currentTimeMillis()); 417 return temp; 418 } 419 420 /** 421 * Sets the timezone ID. If this has not been set, uses default for territory. 422 * 423 * @param timezone a valid TZID (see UTS#35). 424 * @return this, for chaining 425 * @hide draft / provisional / internal are hidden on OHOS 426 */ setTimeZone(TimeZone timezone)427 public GlobalizationPreferences setTimeZone(TimeZone timezone) { 428 if (isFrozen()) { 429 throw new UnsupportedOperationException("Attempt to modify immutable object"); 430 } 431 this.timezone = (TimeZone) timezone.clone(); // clone for safety; 432 return this; 433 } 434 435 /** 436 * Get the timezone. It was either explicitly set, or is 437 * heuristically computed from other settings. 438 * 439 * @return timezone, either implicitly or explicitly set 440 * @hide draft / provisional / internal are hidden on OHOS 441 */ getTimeZone()442 public TimeZone getTimeZone() { 443 if (timezone == null) { 444 return guessTimeZone(); 445 } 446 return timezone.cloneAsThawed(); // clone for safety 447 } 448 449 /** 450 * Get a copy of the collator according to the settings. 451 * 452 * @return collator explicit or implicit. 453 * @hide draft / provisional / internal are hidden on OHOS 454 */ getCollator()455 public Collator getCollator() { 456 if (collator == null) { 457 return guessCollator(); 458 } 459 try { 460 return (Collator) collator.clone(); // clone for safety 461 } catch (CloneNotSupportedException e) { 462 throw new ICUCloneNotSupportedException("Error in cloning collator", e); 463 } 464 } 465 466 /** 467 * Explicitly set the collator for this object. 468 * @param collator The collator object to be passed. 469 * @return this, for chaining 470 * @hide draft / provisional / internal are hidden on OHOS 471 */ setCollator(Collator collator)472 public GlobalizationPreferences setCollator(Collator collator) { 473 if (isFrozen()) { 474 throw new UnsupportedOperationException("Attempt to modify immutable object"); 475 } 476 try { 477 this.collator = (Collator) collator.clone(); // clone for safety 478 } catch (CloneNotSupportedException e) { 479 throw new ICUCloneNotSupportedException("Error in cloning collator", e); 480 } 481 return this; 482 } 483 484 /** 485 * Get a copy of the break iterator for the specified type according to the 486 * settings. 487 * 488 * @param type break type - BI_CHARACTER or BI_WORD, BI_LINE, BI_SENTENCE, BI_TITLE 489 * @return break iterator explicit or implicit 490 * @hide draft / provisional / internal are hidden on OHOS 491 */ getBreakIterator(int type)492 public BreakIterator getBreakIterator(int type) { 493 if (type < BI_CHARACTER || type >= BI_LIMIT) { 494 throw new IllegalArgumentException("Illegal break iterator type"); 495 } 496 if (breakIterators == null || breakIterators[type] == null) { 497 return guessBreakIterator(type); 498 } 499 return (BreakIterator) breakIterators[type].clone(); // clone for safety 500 } 501 502 /** 503 * Explicitly set the break iterator for this object. 504 * 505 * @param type break type - BI_CHARACTER or BI_WORD, BI_LINE, BI_SENTENCE, BI_TITLE 506 * @param iterator a break iterator 507 * @return this, for chaining 508 * @hide draft / provisional / internal are hidden on OHOS 509 */ setBreakIterator(int type, BreakIterator iterator)510 public GlobalizationPreferences setBreakIterator(int type, BreakIterator iterator) { 511 if (type < BI_CHARACTER || type >= BI_LIMIT) { 512 throw new IllegalArgumentException("Illegal break iterator type"); 513 } 514 if (isFrozen()) { 515 throw new UnsupportedOperationException("Attempt to modify immutable object"); 516 } 517 if (breakIterators == null) 518 breakIterators = new BreakIterator[BI_LIMIT]; 519 breakIterators[type] = (BreakIterator) iterator.clone(); // clone for safety 520 return this; 521 } 522 523 /** 524 * Get the display name for an ID: language, script, territory, currency, timezone... 525 * Uses the language priority list to do so. 526 * 527 * @param id language code, script code, ... 528 * @param type specifies the type of the ID: ID_LANGUAGE, etc. 529 * @return the display name 530 * @hide draft / provisional / internal are hidden on OHOS 531 */ getDisplayName(String id, int type)532 public String getDisplayName(String id, int type) { 533 String result = id; 534 for (ULocale locale : getLocales()) { 535 if (!isAvailableLocale(locale, TYPE_GENERIC)) { 536 continue; 537 } 538 switch (type) { 539 case ID_LOCALE: 540 result = ULocale.getDisplayName(id, locale); 541 break; 542 case ID_LANGUAGE: 543 result = ULocale.getDisplayLanguage(id, locale); 544 break; 545 case ID_SCRIPT: 546 result = ULocale.getDisplayScript("und-" + id, locale); 547 break; 548 case ID_TERRITORY: 549 result = ULocale.getDisplayCountry("und-" + id, locale); 550 break; 551 case ID_VARIANT: 552 // TODO fix variant parsing 553 result = ULocale.getDisplayVariant("und-QQ-" + id, locale); 554 break; 555 case ID_KEYWORD: 556 result = ULocale.getDisplayKeyword(id, locale); 557 break; 558 case ID_KEYWORD_VALUE: 559 String[] parts = new String[2]; 560 Utility.split(id,'=',parts); 561 result = ULocale.getDisplayKeywordValue("und@"+id, parts[0], locale); 562 // TODO fix to tell when successful 563 if (result.equals(parts[1])) { 564 continue; 565 } 566 break; 567 case ID_CURRENCY_SYMBOL: 568 case ID_CURRENCY: 569 Currency temp = new Currency(id); 570 result =temp.getName(locale, type==ID_CURRENCY 571 ? Currency.LONG_NAME 572 : Currency.SYMBOL_NAME, null /* isChoiceFormat */); 573 // TODO: have method that doesn't take parameter. Add 574 // function to determine whether string is choice 575 // format. 576 // TODO: have method that doesn't require us 577 // to create a currency 578 break; 579 case ID_TIMEZONE: 580 SimpleDateFormat dtf = new SimpleDateFormat("vvvv",locale); 581 dtf.setTimeZone(TimeZone.getFrozenTimeZone(id)); 582 result = dtf.format(new Date()); 583 // TODO, have method that doesn't require us to create a timezone 584 // fix other hacks 585 // hack for couldn't match 586 587 boolean isBadStr = false; 588 // Matcher badTimeZone = Pattern.compile("[A-Z]{2}|.*\\s\\([A-Z]{2}\\)").matcher(""); 589 // badtzstr = badTimeZone.reset(result).matches(); 590 String teststr = result; 591 int sidx = result.indexOf('('); 592 int eidx = result.indexOf(')'); 593 if (sidx != -1 && eidx != -1 && (eidx - sidx) == 3) { 594 teststr = result.substring(sidx+1, eidx); 595 } 596 if (teststr.length() == 2) { 597 isBadStr = true; 598 for (int i = 0; i < 2; i++) { 599 char c = teststr.charAt(i); 600 if (c < 'A' || 'Z' < c) { 601 isBadStr = false; 602 break; 603 } 604 } 605 } 606 if (isBadStr) { 607 continue; 608 } 609 break; 610 default: 611 throw new IllegalArgumentException("Unknown type: " + type); 612 } 613 614 // TODO need better way of seeing if we fell back to root!! 615 // This will not work at all for lots of stuff 616 if (!id.equals(result)) { 617 return result; 618 } 619 } 620 return result; 621 } 622 623 /** 624 * Set an explicit date format. Overrides the locale priority list for 625 * a particular combination of dateStyle and timeStyle. DF_NONE should 626 * be used if for the style, where only the date or time format individually 627 * is being set. 628 * 629 * @param dateStyle DF_FULL, DF_LONG, DF_MEDIUM, DF_SHORT or DF_NONE 630 * @param timeStyle DF_FULL, DF_LONG, DF_MEDIUM, DF_SHORT or DF_NONE 631 * @param format The date format 632 * @return this, for chaining 633 * @hide draft / provisional / internal are hidden on OHOS 634 */ setDateFormat(int dateStyle, int timeStyle, DateFormat format)635 public GlobalizationPreferences setDateFormat(int dateStyle, int timeStyle, DateFormat format) { 636 if (isFrozen()) { 637 throw new UnsupportedOperationException("Attempt to modify immutable object"); 638 } 639 if (dateFormats == null) { 640 dateFormats = new DateFormat[DF_LIMIT][DF_LIMIT]; 641 } 642 dateFormats[dateStyle][timeStyle] = (DateFormat) format.clone(); // for safety 643 return this; 644 } 645 646 /** 647 * Gets a date format according to the current settings. If there 648 * is an explicit (non-null) date/time format set, a copy of that 649 * is returned. Otherwise, the language priority list is used. 650 * DF_NONE should be used for the style, where only the date or 651 * time format individually is being gotten. 652 * 653 * @param dateStyle DF_FULL, DF_LONG, DF_MEDIUM, DF_SHORT or DF_NONE 654 * @param timeStyle DF_FULL, DF_LONG, DF_MEDIUM, DF_SHORT or DF_NONE 655 * @return a DateFormat, according to the above description 656 * @hide draft / provisional / internal are hidden on OHOS 657 */ getDateFormat(int dateStyle, int timeStyle)658 public DateFormat getDateFormat(int dateStyle, int timeStyle) { 659 if (dateStyle == DF_NONE && timeStyle == DF_NONE 660 || dateStyle < 0 || dateStyle >= DF_LIMIT 661 || timeStyle < 0 || timeStyle >= DF_LIMIT) { 662 throw new IllegalArgumentException("Illegal date format style arguments"); 663 } 664 DateFormat result = null; 665 if (dateFormats != null) { 666 result = dateFormats[dateStyle][timeStyle]; 667 } 668 if (result != null) { 669 result = (DateFormat) result.clone(); // clone for safety 670 // Not sure overriding configuration is what we really want... 671 result.setTimeZone(getTimeZone()); 672 } else { 673 result = guessDateFormat(dateStyle, timeStyle); 674 } 675 return result; 676 } 677 678 /** 679 * Gets a number format according to the current settings. If 680 * there is an explicit (non-null) number format set, a copy of 681 * that is returned. Otherwise, the language priority list is 682 * used. 683 * 684 * @param style NF_NUMBER, NF_CURRENCY, NF_PERCENT, NF_SCIENTIFIC, NF_INTEGER 685 * @hide draft / provisional / internal are hidden on OHOS 686 */ getNumberFormat(int style)687 public NumberFormat getNumberFormat(int style) { 688 if (style < 0 || style >= NF_LIMIT) { 689 throw new IllegalArgumentException("Illegal number format type"); 690 } 691 NumberFormat result = null; 692 if (numberFormats != null) { 693 result = numberFormats[style]; 694 } 695 if (result != null) { 696 result = (NumberFormat) result.clone(); // clone for safety (later optimize) 697 } else { 698 result = guessNumberFormat(style); 699 } 700 return result; 701 } 702 703 /** 704 * Sets a number format explicitly. Overrides the general locale settings. 705 * 706 * @param style NF_NUMBER, NF_CURRENCY, NF_PERCENT, NF_SCIENTIFIC, NF_INTEGER 707 * @param format The number format 708 * @return this, for chaining 709 * @hide draft / provisional / internal are hidden on OHOS 710 */ setNumberFormat(int style, NumberFormat format)711 public GlobalizationPreferences setNumberFormat(int style, NumberFormat format) { 712 if (isFrozen()) { 713 throw new UnsupportedOperationException("Attempt to modify immutable object"); 714 } 715 if (numberFormats == null) { 716 numberFormats = new NumberFormat[NF_LIMIT]; 717 } 718 numberFormats[style] = (NumberFormat) format.clone(); // for safety 719 return this; 720 } 721 722 /** 723 * Restore the object to the initial state. 724 * 725 * @return this, for chaining 726 * @hide draft / provisional / internal are hidden on OHOS 727 */ reset()728 public GlobalizationPreferences reset() { 729 if (isFrozen()) { 730 throw new UnsupportedOperationException("Attempt to modify immutable object"); 731 } 732 locales = null; 733 territory = null; 734 calendar = null; 735 collator = null; 736 breakIterators = null; 737 timezone = null; 738 currency = null; 739 dateFormats = null; 740 numberFormats = null; 741 implicitLocales = null; 742 return this; 743 } 744 745 /** 746 * Process a language/locale priority list specified via <code>setLocales</code>. 747 * The input locale list may be expanded or re-ordered to represent the prioritized 748 * language/locale order actually used by this object by the algorithm explained 749 * below. 750 * <br> 751 * <br> 752 * <b>Step 1</b>: Move later occurrence of more specific locale before earlier 753 * occurrence of less specific locale. 754 * <br> 755 * Before: en, fr_FR, en_US, en_GB 756 * <br> 757 * After: en_US, en_GB, en, fr_FR 758 * <br> 759 * <br> 760 * <b>Step 2</b>: Append a fallback locale to each locale. 761 * <br> 762 * Before: en_US, en_GB, en, fr_FR 763 * <br> 764 * After: en_US, en, en_GB, en, en, fr_FR, fr 765 * <br> 766 * <br> 767 * <b>Step 3</b>: Remove earlier occurrence of duplicated locale entries. 768 * <br> 769 * Before: en_US, en, en_GB, en, en, fr_FR, fr 770 * <br> 771 * After: en_US, en_GB, en, fr_FR, fr 772 * <br> 773 * <br> 774 * The final locale list is used to produce a default value for the appropriate territory, 775 * currency, timezone, etc. The list also represents the lookup order used in 776 * <code>getResourceBundle</code> for this object. A subclass may override this method 777 * to customize the algorithm used for populating the locale list. 778 * 779 * @param inputLocales The list of input locales 780 * @hide draft / provisional / internal are hidden on OHOS 781 */ processLocales(List<ULocale> inputLocales)782 protected List<ULocale> processLocales(List<ULocale> inputLocales) { 783 // Note: Some of the callers, and non-ICU call sites, could be simpler/more efficient 784 // if this method took a Collection or even an Iterable. 785 // Maybe we can change it since this is still @draft and probably not widely overridden. 786 List<ULocale> result = new ArrayList<>(); 787 /* 788 * Step 1: Relocate later occurrence of more specific locale 789 * before earlier occurrence of less specific locale. 790 * 791 * Example: 792 * Before - en_US, fr_FR, zh, en_US_Boston, zh_TW, zh_Hant, fr_CA 793 * After - en_US_Boston, en_US, fr_FR, zh_TW, zh_Hant, zh, fr_CA 794 */ 795 for (ULocale uloc : inputLocales) { 796 String language = uloc.getLanguage(); 797 String script = uloc.getScript(); 798 String country = uloc.getCountry(); 799 String variant = uloc.getVariant(); 800 801 boolean bInserted = false; 802 for (int j = 0; j < result.size(); j++) { 803 // Check if this locale is more specific 804 // than existing locale entries already inserted 805 // in the destination list 806 ULocale u = result.get(j); 807 if (!u.getLanguage().equals(language)) { 808 continue; 809 } 810 String s = u.getScript(); 811 String c = u.getCountry(); 812 String v = u.getVariant(); 813 if (!s.equals(script)) { 814 if (s.length() == 0 && c.length() == 0 && v.length() == 0) { 815 result.add(j, uloc); 816 bInserted = true; 817 break; 818 } else if (s.length() == 0 && c.equals(country)) { 819 // We want to see zh_Hant_HK before zh_HK 820 result.add(j, uloc); 821 bInserted = true; 822 break; 823 } else if (script.length() == 0 && country.length() > 0 && c.length() == 0) { 824 // We want to see zh_HK before zh_Hant 825 result.add(j, uloc); 826 bInserted = true; 827 break; 828 } 829 continue; 830 } 831 if (!c.equals(country)) { 832 if (c.length() == 0 && v.length() == 0) { 833 result.add(j, uloc); 834 bInserted = true; 835 break; 836 } 837 } 838 if (!v.equals(variant) && v.length() == 0) { 839 result.add(j, uloc); 840 bInserted = true; 841 break; 842 } 843 } 844 if (!bInserted) { 845 // Add this locale at the end of the list 846 result.add(uloc); 847 } 848 } 849 850 // TODO: Locale aliases might be resolved here 851 // For example, zh_Hant_TW = zh_TW 852 853 /* 854 * Step 2: Append fallback locales for each entry 855 * 856 * Example: 857 * Before - en_US_Boston, en_US, fr_FR, zh_TW, zh_Hant, zh, fr_CA 858 * After - en_US_Boston, en_US, en, en_US, en, fr_FR, fr, 859 * zh_TW, zn, zh_Hant, zh, zh, fr_CA, fr 860 */ 861 int index = 0; 862 while (index < result.size()) { 863 ULocale uloc = result.get(index); 864 while ((uloc = uloc.getFallback()) != null) { 865 if (uloc.getLanguage().length() == 0) { 866 break; 867 } 868 index++; 869 result.add(index, uloc); 870 } 871 index++; 872 } 873 874 /* 875 * Step 3: Remove earlier occurrence of duplicated locales 876 * 877 * Example: 878 * Before - en_US_Boston, en_US, en, en_US, en, fr_FR, fr, 879 * zh_TW, zn, zh_Hant, zh, zh, fr_CA, fr 880 * After - en_US_Boston, en_US, en, fr_FR, zh_TW, zh_Hant, 881 * zh, fr_CA, fr 882 */ 883 index = 0; 884 while (index < result.size() - 1) { 885 ULocale uloc = result.get(index); 886 boolean bRemoved = false; 887 for (int i = index + 1; i < result.size(); i++) { 888 if (uloc.equals(result.get(i))) { 889 // Remove earlier one 890 result.remove(index); 891 bRemoved = true; 892 break; 893 } 894 } 895 if (!bRemoved) { 896 index++; 897 } 898 } 899 return result; 900 } 901 902 903 /** 904 * This function can be overridden by subclasses to use different heuristics. 905 * <b>It MUST return a 'safe' value, 906 * one whose modification will not affect this object.</b> 907 * 908 * @param dateStyle 909 * @param timeStyle 910 * @hide draft / provisional / internal are hidden on OHOS 911 */ guessDateFormat(int dateStyle, int timeStyle)912 protected DateFormat guessDateFormat(int dateStyle, int timeStyle) { 913 DateFormat result; 914 ULocale dfLocale = getAvailableLocale(TYPE_DATEFORMAT); 915 if (dfLocale == null) { 916 dfLocale = ULocale.ROOT; 917 } 918 if (timeStyle == DF_NONE) { 919 result = DateFormat.getDateInstance(getCalendar(), dateStyle, dfLocale); 920 } else if (dateStyle == DF_NONE) { 921 result = DateFormat.getTimeInstance(getCalendar(), timeStyle, dfLocale); 922 } else { 923 result = DateFormat.getDateTimeInstance(getCalendar(), dateStyle, timeStyle, dfLocale); 924 } 925 return result; 926 } 927 928 /** 929 * This function can be overridden by subclasses to use different heuristics. 930 * <b>It MUST return a 'safe' value, 931 * one whose modification will not affect this object.</b> 932 * 933 * @param style 934 * @hide draft / provisional / internal are hidden on OHOS 935 */ guessNumberFormat(int style)936 protected NumberFormat guessNumberFormat(int style) { 937 NumberFormat result; 938 ULocale nfLocale = getAvailableLocale(TYPE_NUMBERFORMAT); 939 if (nfLocale == null) { 940 nfLocale = ULocale.ROOT; 941 } 942 switch (style) { 943 case NF_NUMBER: 944 result = NumberFormat.getInstance(nfLocale); 945 break; 946 case NF_SCIENTIFIC: 947 result = NumberFormat.getScientificInstance(nfLocale); 948 break; 949 case NF_INTEGER: 950 result = NumberFormat.getIntegerInstance(nfLocale); 951 break; 952 case NF_PERCENT: 953 result = NumberFormat.getPercentInstance(nfLocale); 954 break; 955 case NF_CURRENCY: 956 result = NumberFormat.getCurrencyInstance(nfLocale); 957 result.setCurrency(getCurrency()); 958 break; 959 default: 960 throw new IllegalArgumentException("Unknown number format style"); 961 } 962 return result; 963 } 964 965 /** 966 * This function can be overridden by subclasses to use different heuristics. 967 * 968 * @hide draft / provisional / internal are hidden on OHOS 969 */ guessTerritory()970 protected String guessTerritory() { 971 String result; 972 // pass through locales to see if there is a territory. 973 for (ULocale locale : getLocales()) { 974 result = locale.getCountry(); 975 if (result.length() != 0) { 976 return result; 977 } 978 } 979 // if not, guess from the first language tag, or maybe from 980 // intersection of languages, eg nl + fr => BE 981 // TODO: fix using real data 982 // for now, just use fixed values 983 ULocale firstLocale = getLocale(0); 984 String language = firstLocale.getLanguage(); 985 String script = firstLocale.getScript(); 986 result = null; 987 if (script.length() != 0) { 988 result = language_territory_hack_map.get(language + "_" + script); 989 } 990 if (result == null) { 991 result = language_territory_hack_map.get(language); 992 } 993 if (result == null) { 994 result = "US"; // need *some* default 995 } 996 return result; 997 } 998 999 /** 1000 * This function can be overridden by subclasses to use different heuristics 1001 * 1002 * @hide draft / provisional / internal are hidden on OHOS 1003 */ guessCurrency()1004 protected Currency guessCurrency() { 1005 return Currency.getInstance(new ULocale("und-" + getTerritory())); 1006 } 1007 1008 /** 1009 * This function can be overridden by subclasses to use different heuristics 1010 * <b>It MUST return a 'safe' value, 1011 * one whose modification will not affect this object.</b> 1012 * 1013 * @hide draft / provisional / internal are hidden on OHOS 1014 */ guessLocales()1015 protected List<ULocale> guessLocales() { 1016 if (implicitLocales == null) { 1017 List<ULocale> result = new ArrayList<>(1); 1018 result.add(ULocale.getDefault()); 1019 implicitLocales = processLocales(result); 1020 } 1021 return implicitLocales; 1022 } 1023 1024 /** 1025 * This function can be overridden by subclasses to use different heuristics. 1026 * <b>It MUST return a 'safe' value, 1027 * one whose modification will not affect this object.</b> 1028 * 1029 * @hide draft / provisional / internal are hidden on OHOS 1030 */ guessCollator()1031 protected Collator guessCollator() { 1032 ULocale collLocale = getAvailableLocale(TYPE_COLLATOR); 1033 if (collLocale == null) { 1034 collLocale = ULocale.ROOT; 1035 } 1036 return Collator.getInstance(collLocale); 1037 } 1038 1039 /** 1040 * This function can be overridden by subclasses to use different heuristics. 1041 * <b>It MUST return a 'safe' value, 1042 * one whose modification will not affect this object.</b> 1043 * 1044 * @param type 1045 * @hide draft / provisional / internal are hidden on OHOS 1046 */ guessBreakIterator(int type)1047 protected BreakIterator guessBreakIterator(int type) { 1048 BreakIterator bitr = null; 1049 ULocale brkLocale = getAvailableLocale(TYPE_BREAKITERATOR); 1050 if (brkLocale == null) { 1051 brkLocale = ULocale.ROOT; 1052 } 1053 switch (type) { 1054 case BI_CHARACTER: 1055 bitr = BreakIterator.getCharacterInstance(brkLocale); 1056 break; 1057 case BI_TITLE: 1058 bitr = BreakIterator.getTitleInstance(brkLocale); 1059 break; 1060 case BI_WORD: 1061 bitr = BreakIterator.getWordInstance(brkLocale); 1062 break; 1063 case BI_LINE: 1064 bitr = BreakIterator.getLineInstance(brkLocale); 1065 break; 1066 case BI_SENTENCE: 1067 bitr = BreakIterator.getSentenceInstance(brkLocale); 1068 break; 1069 default: 1070 throw new IllegalArgumentException("Unknown break iterator type"); 1071 } 1072 return bitr; 1073 } 1074 1075 /** 1076 * This function can be overridden by subclasses to use different heuristics. 1077 * <b>It MUST return a 'safe' value, 1078 * one whose modification will not affect this object.</b> 1079 * 1080 * @hide draft / provisional / internal are hidden on OHOS 1081 */ guessTimeZone()1082 protected TimeZone guessTimeZone() { 1083 // TODO fix using real data 1084 // for single-zone countries, pick that zone 1085 // for others, pick the most populous zone 1086 // for now, just use fixed value 1087 // NOTE: in a few cases can do better by looking at language. 1088 // Eg haw+US should go to Pacific/Honolulu 1089 // fr+CA should go to America/Montreal 1090 String timezoneString = territory_tzid_hack_map.get(getTerritory()); 1091 if (timezoneString == null) { 1092 String[] attempt = TimeZone.getAvailableIDs(getTerritory()); 1093 if (attempt.length == 0) { 1094 timezoneString = "Etc/GMT"; // gotta do something 1095 } else { 1096 int i; 1097 // this all needs to be fixed to use real data. But for now, do slightly better by skipping cruft 1098 for (i = 0; i < attempt.length; ++i) { 1099 if (attempt[i].indexOf("/") >= 0) break; 1100 } 1101 if (i > attempt.length) i = 0; 1102 timezoneString = attempt[i]; 1103 } 1104 } 1105 return TimeZone.getTimeZone(timezoneString); 1106 } 1107 1108 /** 1109 * This function can be overridden by subclasses to use different heuristics. 1110 * <b>It MUST return a 'safe' value, 1111 * one whose modification will not affect this object.</b> 1112 * 1113 * @hide draft / provisional / internal are hidden on OHOS 1114 */ guessCalendar()1115 protected Calendar guessCalendar() { 1116 ULocale calLocale = getAvailableLocale(TYPE_CALENDAR); 1117 if (calLocale == null) { 1118 calLocale = ULocale.US; 1119 } 1120 return Calendar.getInstance(getTimeZone(), calLocale); 1121 } 1122 1123 // PRIVATES 1124 1125 private List<ULocale> locales; 1126 private String territory; 1127 private Currency currency; 1128 private TimeZone timezone; 1129 private Calendar calendar; 1130 private Collator collator; 1131 private BreakIterator[] breakIterators; 1132 private DateFormat[][] dateFormats; 1133 private NumberFormat[] numberFormats; 1134 private List<ULocale> implicitLocales; 1135 1136 { reset()1137 reset(); 1138 } 1139 1140 getAvailableLocale(int type)1141 private ULocale getAvailableLocale(int type) { 1142 List<ULocale> locs = getLocales(); 1143 ULocale result = null; 1144 for (int i = 0; i < locs.size(); i++) { 1145 ULocale l = locs.get(i); 1146 if (isAvailableLocale(l, type)) { 1147 result = l; 1148 break; 1149 } 1150 } 1151 return result; 1152 } 1153 isAvailableLocale(ULocale loc, int type)1154 private boolean isAvailableLocale(ULocale loc, int type) { 1155 BitSet bits = available_locales.get(loc); 1156 if (bits != null && bits.get(type)) { 1157 return true; 1158 } 1159 return false; 1160 } 1161 1162 /* 1163 * Available locales for service types 1164 */ 1165 private static final HashMap<ULocale, BitSet> available_locales = new HashMap<>(); 1166 private static final int 1167 TYPE_GENERIC = 0, 1168 TYPE_CALENDAR = 1, 1169 TYPE_DATEFORMAT= 2, 1170 TYPE_NUMBERFORMAT = 3, 1171 TYPE_COLLATOR = 4, 1172 TYPE_BREAKITERATOR = 5, 1173 TYPE_LIMIT = TYPE_BREAKITERATOR + 1; 1174 1175 static { 1176 BitSet bits; 1177 ULocale[] allLocales = ULocale.getAvailableLocales(); 1178 for (int i = 0; i < allLocales.length; i++) { 1179 bits = new BitSet(TYPE_LIMIT); available_locales.put(allLocales[i], bits)1180 available_locales.put(allLocales[i], bits); 1181 bits.set(TYPE_GENERIC); 1182 } 1183 1184 ULocale[] calLocales = Calendar.getAvailableULocales(); 1185 for (int i = 0; i < calLocales.length; i++) { 1186 bits = available_locales.get(calLocales[i]); 1187 if (bits == null) { 1188 bits = new BitSet(TYPE_LIMIT); available_locales.put(allLocales[i], bits)1189 available_locales.put(allLocales[i], bits); 1190 } 1191 bits.set(TYPE_CALENDAR); 1192 } 1193 1194 ULocale[] dateLocales = DateFormat.getAvailableULocales(); 1195 for (int i = 0; i < dateLocales.length; i++) { 1196 bits = available_locales.get(dateLocales[i]); 1197 if (bits == null) { 1198 bits = new BitSet(TYPE_LIMIT); available_locales.put(allLocales[i], bits)1199 available_locales.put(allLocales[i], bits); 1200 } 1201 bits.set(TYPE_DATEFORMAT); 1202 } 1203 1204 ULocale[] numLocales = NumberFormat.getAvailableULocales(); 1205 for (int i = 0; i < numLocales.length; i++) { 1206 bits = available_locales.get(numLocales[i]); 1207 if (bits == null) { 1208 bits = new BitSet(TYPE_LIMIT); available_locales.put(allLocales[i], bits)1209 available_locales.put(allLocales[i], bits); 1210 } 1211 bits.set(TYPE_NUMBERFORMAT); 1212 } 1213 1214 ULocale[] collLocales = Collator.getAvailableULocales(); 1215 for (int i = 0; i < collLocales.length; i++) { 1216 bits = available_locales.get(collLocales[i]); 1217 if (bits == null) { 1218 bits = new BitSet(TYPE_LIMIT); available_locales.put(allLocales[i], bits)1219 available_locales.put(allLocales[i], bits); 1220 } 1221 bits.set(TYPE_COLLATOR); 1222 } 1223 1224 ULocale[] brkLocales = BreakIterator.getAvailableULocales(); 1225 for (int i = 0; i < brkLocales.length; i++) { 1226 bits = available_locales.get(brkLocales[i]); 1227 bits.set(TYPE_BREAKITERATOR); 1228 } 1229 } 1230 1231 /** WARNING: All of this data is temporary, until we start importing from CLDR!!! 1232 * 1233 */ 1234 private static final Map<String, String> language_territory_hack_map = new HashMap<>(); 1235 private static final String[][] language_territory_hack = { 1236 {"af", "ZA"}, 1237 {"am", "ET"}, 1238 {"ar", "SA"}, 1239 {"as", "IN"}, 1240 {"ay", "PE"}, 1241 {"az", "AZ"}, 1242 {"bal", "PK"}, 1243 {"be", "BY"}, 1244 {"bg", "BG"}, 1245 {"bn", "IN"}, 1246 {"bs", "BA"}, 1247 {"ca", "ES"}, 1248 {"ch", "MP"}, 1249 {"cpe", "SL"}, 1250 {"cs", "CZ"}, 1251 {"cy", "GB"}, 1252 {"da", "DK"}, 1253 {"de", "DE"}, 1254 {"dv", "MV"}, 1255 {"dz", "BT"}, 1256 {"el", "GR"}, 1257 {"en", "US"}, 1258 {"es", "ES"}, 1259 {"et", "EE"}, 1260 {"eu", "ES"}, 1261 {"fa", "IR"}, 1262 {"fi", "FI"}, 1263 {"fil", "PH"}, 1264 {"fj", "FJ"}, 1265 {"fo", "FO"}, 1266 {"fr", "FR"}, 1267 {"ga", "IE"}, 1268 {"gd", "GB"}, 1269 {"gl", "ES"}, 1270 {"gn", "PY"}, 1271 {"gu", "IN"}, 1272 {"gv", "GB"}, 1273 {"ha", "NG"}, 1274 {"he", "IL"}, 1275 {"hi", "IN"}, 1276 {"ho", "PG"}, 1277 {"hr", "HR"}, 1278 {"ht", "HT"}, 1279 {"hu", "HU"}, 1280 {"hy", "AM"}, 1281 {"id", "ID"}, 1282 {"is", "IS"}, 1283 {"it", "IT"}, 1284 {"ja", "JP"}, 1285 {"ka", "GE"}, 1286 {"kk", "KZ"}, 1287 {"kl", "GL"}, 1288 {"km", "KH"}, 1289 {"kn", "IN"}, 1290 {"ko", "KR"}, 1291 {"kok", "IN"}, 1292 {"ks", "IN"}, 1293 {"ku", "TR"}, 1294 {"ky", "KG"}, 1295 {"la", "VA"}, 1296 {"lb", "LU"}, 1297 {"ln", "CG"}, 1298 {"lo", "LA"}, 1299 {"lt", "LT"}, 1300 {"lv", "LV"}, 1301 {"mai", "IN"}, 1302 {"men", "GN"}, 1303 {"mg", "MG"}, 1304 {"mh", "MH"}, 1305 {"mk", "MK"}, 1306 {"ml", "IN"}, 1307 {"mn", "MN"}, 1308 {"mni", "IN"}, 1309 {"mo", "MD"}, 1310 {"mr", "IN"}, 1311 {"ms", "MY"}, 1312 {"mt", "MT"}, 1313 {"my", "MM"}, 1314 {"na", "NR"}, 1315 {"nb", "NO"}, 1316 {"nd", "ZA"}, 1317 {"ne", "NP"}, 1318 {"niu", "NU"}, 1319 {"nl", "NL"}, 1320 {"nn", "NO"}, 1321 {"no", "NO"}, 1322 {"nr", "ZA"}, 1323 {"nso", "ZA"}, 1324 {"ny", "MW"}, 1325 {"om", "KE"}, 1326 {"or", "IN"}, 1327 {"pa", "IN"}, 1328 {"pau", "PW"}, 1329 {"pl", "PL"}, 1330 {"ps", "PK"}, 1331 {"pt", "BR"}, 1332 {"qu", "PE"}, 1333 {"rn", "BI"}, 1334 {"ro", "RO"}, 1335 {"ru", "RU"}, 1336 {"rw", "RW"}, 1337 {"sd", "IN"}, 1338 {"sg", "CF"}, 1339 {"si", "LK"}, 1340 {"sk", "SK"}, 1341 {"sl", "SI"}, 1342 {"sm", "WS"}, 1343 {"so", "DJ"}, 1344 {"sq", "CS"}, 1345 {"sr", "CS"}, 1346 {"ss", "ZA"}, 1347 {"st", "ZA"}, 1348 {"sv", "SE"}, 1349 {"sw", "KE"}, 1350 {"ta", "IN"}, 1351 {"te", "IN"}, 1352 {"tem", "SL"}, 1353 {"tet", "TL"}, 1354 {"th", "TH"}, 1355 {"ti", "ET"}, 1356 {"tg", "TJ"}, 1357 {"tk", "TM"}, 1358 {"tkl", "TK"}, 1359 {"tvl", "TV"}, 1360 {"tl", "PH"}, 1361 {"tn", "ZA"}, 1362 {"to", "TO"}, 1363 {"tpi", "PG"}, 1364 {"tr", "TR"}, 1365 {"ts", "ZA"}, 1366 {"uk", "UA"}, 1367 {"ur", "IN"}, 1368 {"uz", "UZ"}, 1369 {"ve", "ZA"}, 1370 {"vi", "VN"}, 1371 {"wo", "SN"}, 1372 {"xh", "ZA"}, 1373 {"zh", "CN"}, 1374 {"zh_Hant", "TW"}, 1375 {"zu", "ZA"}, 1376 {"aa", "ET"}, 1377 {"byn", "ER"}, 1378 {"eo", "DE"}, 1379 {"gez", "ET"}, 1380 {"haw", "US"}, 1381 {"iu", "CA"}, 1382 {"kw", "GB"}, 1383 {"sa", "IN"}, 1384 {"sh", "HR"}, 1385 {"sid", "ET"}, 1386 {"syr", "SY"}, 1387 {"tig", "ER"}, 1388 {"tt", "RU"}, 1389 {"wal", "ET"}, }; 1390 static { 1391 for (int i = 0; i < language_territory_hack.length; ++i) { language_territory_hack_map.put(language_territory_hack[i][0],language_territory_hack[i][1])1392 language_territory_hack_map.put(language_territory_hack[i][0],language_territory_hack[i][1]); 1393 } 1394 } 1395 1396 static final Map<String, String> territory_tzid_hack_map = new HashMap<>(); 1397 static final String[][] territory_tzid_hack = { 1398 {"AQ", "Antarctica/McMurdo"}, 1399 {"AR", "America/Buenos_Aires"}, 1400 {"AU", "Australia/Sydney"}, 1401 {"BR", "America/Sao_Paulo"}, 1402 {"CA", "America/Toronto"}, 1403 {"CD", "Africa/Kinshasa"}, 1404 {"CL", "America/Santiago"}, 1405 {"CN", "Asia/Shanghai"}, 1406 {"EC", "America/Guayaquil"}, 1407 {"ES", "Europe/Madrid"}, 1408 {"GB", "Europe/London"}, 1409 {"GL", "America/Godthab"}, 1410 {"ID", "Asia/Jakarta"}, 1411 {"ML", "Africa/Bamako"}, 1412 {"MX", "America/Mexico_City"}, 1413 {"MY", "Asia/Kuala_Lumpur"}, 1414 {"NZ", "Pacific/Auckland"}, 1415 {"PT", "Europe/Lisbon"}, 1416 {"RU", "Europe/Moscow"}, 1417 {"UA", "Europe/Kiev"}, 1418 {"US", "America/New_York"}, 1419 {"UZ", "Asia/Tashkent"}, 1420 {"PF", "Pacific/Tahiti"}, 1421 {"FM", "Pacific/Kosrae"}, 1422 {"KI", "Pacific/Tarawa"}, 1423 {"KZ", "Asia/Almaty"}, 1424 {"MH", "Pacific/Majuro"}, 1425 {"MN", "Asia/Ulaanbaatar"}, 1426 {"SJ", "Arctic/Longyearbyen"}, 1427 {"UM", "Pacific/Midway"}, 1428 }; 1429 static { 1430 for (int i = 0; i < territory_tzid_hack.length; ++i) { territory_tzid_hack_map.put(territory_tzid_hack[i][0],territory_tzid_hack[i][1])1431 territory_tzid_hack_map.put(territory_tzid_hack[i][0],territory_tzid_hack[i][1]); 1432 } 1433 } 1434 1435 // Freezable implementation 1436 1437 private volatile boolean frozen; 1438 1439 /** 1440 * @hide draft / provisional / internal are hidden on OHOS 1441 */ 1442 @Override isFrozen()1443 public boolean isFrozen() { 1444 return frozen; 1445 } 1446 1447 /** 1448 * @hide draft / provisional / internal are hidden on OHOS 1449 */ 1450 @Override freeze()1451 public GlobalizationPreferences freeze() { 1452 frozen = true; 1453 return this; 1454 } 1455 1456 /** 1457 * @hide draft / provisional / internal are hidden on OHOS 1458 */ 1459 @Override cloneAsThawed()1460 public GlobalizationPreferences cloneAsThawed() { 1461 try { 1462 GlobalizationPreferences result = (GlobalizationPreferences) clone(); 1463 result.frozen = false; 1464 return result; 1465 } catch (CloneNotSupportedException e) { 1466 // will always work 1467 return null; 1468 } 1469 } 1470 } 1471 1472