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) 1996-2016, International Business Machines Corporation and 7 * others. All Rights Reserved. 8 ******************************************************************************* 9 */ 10package android.icu.text; 11 12import java.io.IOException; 13import java.io.ObjectInputStream; 14import java.io.Serializable; 15import java.util.Arrays; 16import java.util.Locale; 17import java.util.MissingResourceException; 18 19import android.icu.impl.CacheBase; 20import android.icu.impl.CurrencyData; 21import android.icu.impl.CurrencyData.CurrencyDisplayInfo; 22import android.icu.impl.CurrencyData.CurrencyFormatInfo; 23import android.icu.impl.CurrencyData.CurrencySpacingInfo; 24import android.icu.impl.ICUData; 25import android.icu.impl.ICUResourceBundle; 26import android.icu.impl.SoftCache; 27import android.icu.impl.UResource; 28import android.icu.util.Currency; 29import android.icu.util.ICUCloneNotSupportedException; 30import android.icu.util.ULocale; 31import android.icu.util.ULocale.Category; 32import android.icu.util.UResourceBundle; 33 34/** 35 * <strong>[icu enhancement]</strong> ICU's replacement for {@link java.text.DecimalFormatSymbols}. Methods, fields, and other functionality specific to ICU are labeled '<strong>[icu]</strong>'. 36 * 37 * This class represents the set of symbols (such as the decimal separator, the grouping 38 * separator, and so on) needed by <code>DecimalFormat</code> to format 39 * numbers. <code>DecimalFormat</code> creates for itself an instance of 40 * <code>DecimalFormatSymbols</code> from its locale data. If you need to change any of 41 * these symbols, you can get the <code>DecimalFormatSymbols</code> object from your 42 * <code>DecimalFormat</code> and modify it. 43 * 44 * @see java.util.Locale 45 * @see DecimalFormat 46 * @author Mark Davis 47 * @author Alan Liu 48 */ 49public class DecimalFormatSymbols implements Cloneable, Serializable { 50 /** 51 * Creates a DecimalFormatSymbols object for the default <code>FORMAT</code> locale. 52 * @see Category#FORMAT 53 */ 54 public DecimalFormatSymbols() { 55 initialize(ULocale.getDefault(Category.FORMAT)); 56 } 57 58 /** 59 * Creates a DecimalFormatSymbols object for the given locale. 60 * @param locale the locale 61 */ 62 public DecimalFormatSymbols(Locale locale) { 63 initialize(ULocale.forLocale(locale)); 64 } 65 66 /** 67 * <strong>[icu]</strong> Creates a DecimalFormatSymbols object for the given locale. 68 * @param locale the locale 69 */ 70 public DecimalFormatSymbols(ULocale locale) { 71 initialize(locale); 72 } 73 74 /** 75 * Returns a DecimalFormatSymbols instance for the default locale. 76 * 77 * <p><strong>Note:</strong> Unlike 78 * <code>java.text.DecimalFormatSymbols#getInstance</code>, this method simply returns 79 * <code>new android.icu.text.DecimalFormatSymbols()</code>. ICU currently does not 80 * support <code>DecimalFormatSymbolsProvider</code>, which was introduced in Java 6. 81 * 82 * @return A DecimalFormatSymbols instance. 83 */ 84 public static DecimalFormatSymbols getInstance() { 85 return new DecimalFormatSymbols(); 86 } 87 88 /** 89 * Returns a DecimalFormatSymbols instance for the given locale. 90 * 91 * <p><strong>Note:</strong> Unlike 92 * <code>java.text.DecimalFormatSymbols#getInstance</code>, this method simply returns 93 * <code>new android.icu.text.DecimalFormatSymbols(locale)</code>. ICU currently does 94 * not support <code>DecimalFormatSymbolsProvider</code>, which was introduced in Java 95 * 6. 96 * 97 * @param locale the locale. 98 * @return A DecimalFormatSymbols instance. 99 */ 100 public static DecimalFormatSymbols getInstance(Locale locale) { 101 return new DecimalFormatSymbols(locale); 102 } 103 104 /** 105 * Returns a DecimalFormatSymbols instance for the given locale. 106 * 107 * <p><strong>Note:</strong> Unlike 108 * <code>java.text.DecimalFormatSymbols#getInstance</code>, this method simply returns 109 * <code>new android.icu.text.DecimalFormatSymbols(locale)</code>. ICU currently does 110 * not support <code>DecimalFormatSymbolsProvider</code>, which was introduced in Java 111 * 6. 112 * 113 * @param locale the locale. 114 * @return A DecimalFormatSymbols instance. 115 */ 116 public static DecimalFormatSymbols getInstance(ULocale locale) { 117 return new DecimalFormatSymbols(locale); 118 } 119 120 /** 121 * Returns an array of all locales for which the <code>getInstance</code> methods of 122 * this class can return localized instances. 123 * 124 * <p><strong>Note:</strong> Unlike 125 * <code>java.text.DecimalFormatSymbols#getAvailableLocales</code>, this method simply 126 * returns the array of <code>Locale</code>s available for this class. ICU currently 127 * does not support <code>DecimalFormatSymbolsProvider</code>, which was introduced in 128 * Java 6. 129 * 130 * @return An array of <code>Locale</code>s for which localized 131 * <code>DecimalFormatSymbols</code> instances are available. 132 */ 133 public static Locale[] getAvailableLocales() { 134 return ICUResourceBundle.getAvailableLocales(); 135 } 136 137 /** 138 * <strong>[icu]</strong> Returns an array of all locales for which the <code>getInstance</code> 139 * methods of this class can return localized instances. 140 * 141 * <p><strong>Note:</strong> Unlike 142 * <code>java.text.DecimalFormatSymbols#getAvailableLocales</code>, this method simply 143 * returns the array of <code>ULocale</code>s available in this class. ICU currently 144 * does not support <code>DecimalFormatSymbolsProvider</code>, which was introduced in 145 * Java 6. 146 * 147 * @return An array of <code>ULocale</code>s for which localized 148 * <code>DecimalFormatSymbols</code> instances are available. 149 * @hide draft / provisional / internal are hidden on Android 150 */ 151 public static ULocale[] getAvailableULocales() { 152 return ICUResourceBundle.getAvailableULocales(); 153 } 154 155 156 /** 157 * Returns the character used for zero. Different for Arabic, etc. 158 * @return the character 159 */ 160 public char getZeroDigit() { 161 return zeroDigit; 162 } 163 164 /** 165 * Returns the array of characters used as digits, in order from 0 through 9 166 * @return The array 167 */ 168 public char[] getDigits() { 169 return digits.clone(); 170 } 171 172 /** 173 * Sets the character used for zero. 174 * <p> 175 * <b>Note:</b> When the specified zeroDigit is a Unicode decimal digit character 176 * (category:Nd) and the number value is 0, then this method propagate digit 1 to 177 * digit 9 by incrementing code point one by one. 178 * 179 * @param zeroDigit the zero character. 180 */ 181 public void setZeroDigit(char zeroDigit) { 182 this.zeroDigit = zeroDigit; 183 184 // digitStrings or digits might be referencing a cached copy for 185 // optimization purpose, so creating a copy before making a modification 186 digitStrings = digitStrings.clone(); 187 digits = digits.clone(); 188 189 // Make digitStrings field and digits field in sync 190 digitStrings[0] = String.valueOf(zeroDigit); 191 digits[0] = zeroDigit; 192 193 // Android patch (ticket #11903) begin. 194 for (int i = 1; i < 10; i++) { 195 char d = (char)(zeroDigit + i); 196 digitStrings[i] = String.valueOf(d); 197 digits[i] = d; 198 } 199 // Android patch (ticket #11903) end. 200 } 201 202 /** 203 * <strong>[icu]</strong> Returns the array of strings used as digits, in order from 0 through 9 204 * @return The array of ten digit strings 205 * @see #setDigitStrings(String[]) 206 * @hide draft / provisional / internal are hidden on Android 207 */ 208 public String[] getDigitStrings() { 209 return digitStrings.clone(); 210 } 211 212 /** 213 * Returns the array of strings used as digits, in order from 0 through 9 214 * Package private method - doesn't create a defensively copy. 215 * @return the array of digit strings 216 */ 217 String[] getDigitStringsLocal() { 218 return digitStrings; 219 } 220 221 /** 222 * <strong>[icu]</strong> Sets the array of strings used as digits, in order from 0 through 9 223 * <p> 224 * <b>Note:</b> 225 * <p> 226 * When the input array of digit strings contains any strings 227 * represented by multiple Java chars, then {@link #getDigits()} will return 228 * the default digits ('0' - '9') and {@link #getZeroDigit()} will return the 229 * default zero digit ('0'). 230 * 231 * @param digitStrings The array of digit strings. The length of the array must be exactly 10. 232 * @throws NullPointerException if the <code>digitStrings</code> is null. 233 * @throws IllegalArgumentException if the length of the array is not 10. 234 * @see #getDigitStrings() 235 * @hide draft / provisional / internal are hidden on Android 236 */ 237 public void setDigitStrings(String[] digitStrings) { 238 if (digitStrings == null) { 239 throw new NullPointerException("The input digit string array is null"); 240 } 241 if (digitStrings.length != 10) { 242 throw new IllegalArgumentException("Number of digit strings is not 10"); 243 } 244 245 // Scan input array and create char[] representation if possible 246 String[] tmpDigitStrings = new String[10]; 247 char[] tmpDigits = new char[10]; 248 for (int i = 0; i < 10; i++) { 249 if (digitStrings[i] == null) { 250 throw new IllegalArgumentException("The input digit string array contains a null element"); 251 } 252 tmpDigitStrings[i] = digitStrings[i]; 253 if (tmpDigits != null && digitStrings[i].length() == 1) { 254 tmpDigits[i] = digitStrings[i].charAt(0); 255 } else { 256 // contains digit string with multiple UTF-16 code units 257 tmpDigits = null; 258 } 259 } 260 261 this.digitStrings = tmpDigitStrings; 262 263 if (tmpDigits == null) { 264 // fallback to the default digit chars 265 this.zeroDigit = DEF_DIGIT_CHARS_ARRAY[0]; 266 this.digits = DEF_DIGIT_CHARS_ARRAY; 267 } else { 268 this.zeroDigit = tmpDigits[0]; 269 this.digits = tmpDigits; 270 } 271 } 272 273 /** 274 * Returns the character used to represent a significant digit in a pattern. 275 * @return the significant digit pattern character 276 */ 277 public char getSignificantDigit() { 278 return sigDigit; 279 } 280 281 /** 282 * Sets the character used to represent a significant digit in a pattern. 283 * @param sigDigit the significant digit pattern character 284 */ 285 public void setSignificantDigit(char sigDigit) { 286 this.sigDigit = sigDigit; 287 } 288 289 /** 290 * Returns the character used for grouping separator. Different for French, etc. 291 * @return the thousands character 292 */ 293 public char getGroupingSeparator() { 294 return groupingSeparator; 295 } 296 297 /** 298 * Sets the character used for grouping separator. Different for French, etc. 299 * @param groupingSeparator the thousands character 300 */ 301 public void setGroupingSeparator(char groupingSeparator) { 302 this.groupingSeparator = groupingSeparator; 303 this.groupingSeparatorString = String.valueOf(groupingSeparator); 304 } 305 306 /** 307 * <strong>[icu]</strong> Returns the string used for grouping separator. Different for French, etc. 308 * @return the grouping separator string 309 * @see #setGroupingSeparatorString(String) 310 * @hide draft / provisional / internal are hidden on Android 311 */ 312 public String getGroupingSeparatorString() { 313 return groupingSeparatorString; 314 } 315 316 /** 317 * <strong>[icu]</strong> Sets the string used for grouping separator. 318 * <p> 319 * <b>Note:</b> When the input grouping separator String is represented 320 * by multiple Java chars, then {@link #getGroupingSeparator()} will 321 * return the default grouping separator character (','). 322 * 323 * @param groupingSeparatorString the grouping separator string 324 * @throws NullPointerException if <code>groupingSeparatorString</code> is null. 325 * @see #getGroupingSeparatorString() 326 * @hide draft / provisional / internal are hidden on Android 327 */ 328 public void setGroupingSeparatorString(String groupingSeparatorString) { 329 if (groupingSeparatorString == null) { 330 throw new NullPointerException("The input grouping separator is null"); 331 } 332 this.groupingSeparatorString = groupingSeparatorString; 333 if (groupingSeparatorString.length() == 1) { 334 this.groupingSeparator = groupingSeparatorString.charAt(0); 335 } else { 336 // Use the default grouping separator character as fallback 337 this.groupingSeparator = DEF_GROUPING_SEPARATOR; 338 } 339 } 340 341 /** 342 * Returns the character used for decimal sign. Different for French, etc. 343 * @return the decimal character 344 */ 345 public char getDecimalSeparator() { 346 return decimalSeparator; 347 } 348 349 /** 350 * Sets the character used for decimal sign. Different for French, etc. 351 * @param decimalSeparator the decimal character 352 */ 353 public void setDecimalSeparator(char decimalSeparator) { 354 this.decimalSeparator = decimalSeparator; 355 this.decimalSeparatorString = String.valueOf(decimalSeparator); 356 } 357 358 /** 359 * <strong>[icu]</strong> Returns the string used for decimal sign. 360 * @return the decimal sign string 361 * @see #setDecimalSeparatorString(String) 362 * @hide draft / provisional / internal are hidden on Android 363 */ 364 public String getDecimalSeparatorString() { 365 return decimalSeparatorString; 366 } 367 368 /** 369 * <strong>[icu]</strong> Sets the string used for decimal sign. 370 * <p> 371 * <b>Note:</b> When the input decimal separator String is represented 372 * by multiple Java chars, then {@link #getDecimalSeparator()} will 373 * return the default decimal separator character ('.'). 374 * 375 * @param decimalSeparatorString the decimal sign string 376 * @throws NullPointerException if <code>decimalSeparatorString</code> is null. 377 * @see #getDecimalSeparatorString() 378 * @hide draft / provisional / internal are hidden on Android 379 */ 380 public void setDecimalSeparatorString(String decimalSeparatorString) { 381 if (decimalSeparatorString == null) { 382 throw new NullPointerException("The input decimal separator is null"); 383 } 384 this.decimalSeparatorString = decimalSeparatorString; 385 if (decimalSeparatorString.length() == 1) { 386 this.decimalSeparator = decimalSeparatorString.charAt(0); 387 } else { 388 // Use the default decimal separator character as fallback 389 this.decimalSeparator = DEF_DECIMAL_SEPARATOR; 390 } 391 } 392 393 /** 394 * Returns the character used for mille percent sign. Different for Arabic, etc. 395 * @return the mille percent character 396 */ 397 public char getPerMill() { 398 return perMill; 399 } 400 401 /** 402 * Sets the character used for mille percent sign. Different for Arabic, etc. 403 * @param perMill the mille percent character 404 */ 405 public void setPerMill(char perMill) { 406 this.perMill = perMill; 407 this.perMillString = String.valueOf(perMill); 408 } 409 410 /** 411 * <strong>[icu]</strong> Returns the string used for permille sign. 412 * @return the permille string 413 * @see #setPerMillString(String) 414 * @hide draft / provisional / internal are hidden on Android 415 */ 416 public String getPerMillString() { 417 return perMillString; 418 } 419 420 /** 421 * <strong>[icu]</strong> Sets the string used for permille sign. 422 * <p> 423 * <b>Note:</b> When the input permille String is represented 424 * by multiple Java chars, then {@link #getPerMill()} will 425 * return the default permille character ('‰'). 426 * 427 * @param perMillString the permille string 428 * @throws NullPointerException if <code>perMillString</code> is null. 429 * @see #getPerMillString() 430 * @hide draft / provisional / internal are hidden on Android 431 */ 432 public void setPerMillString(String perMillString) { 433 if (perMillString == null) { 434 throw new NullPointerException("The input permille string is null"); 435 } 436 this.perMillString = perMillString; 437 if (perMillString.length() == 1) { 438 this.perMill = perMillString.charAt(0); 439 } else { 440 // Use the default permille character as fallback 441 this.perMill = DEF_PERMILL; 442 } 443 } 444 445 /** 446 * Returns the character used for percent sign. Different for Arabic, etc. 447 * @return the percent character 448 */ 449 public char getPercent() { 450 return percent; 451 } 452 453 /** 454 * Sets the character used for percent sign. Different for Arabic, etc. 455 * @param percent the percent character 456 */ 457 public void setPercent(char percent) { 458 this.percent = percent; 459 this.percentString = String.valueOf(percent); 460 } 461 462 /** 463 * <strong>[icu]</strong> Returns the string used for percent sign. 464 * @return the percent string 465 * @see #setPercentString(String) 466 * @hide draft / provisional / internal are hidden on Android 467 */ 468 public String getPercentString() { 469 return percentString; 470 } 471 472 /** 473 * <strong>[icu]</strong> Sets the string used for percent sign. 474 * <p> 475 * <b>Note:</b> When the input grouping separator String is represented 476 * by multiple Java chars, then {@link #getPercent()} will 477 * return the default percent sign character ('%'). 478 * 479 * @param percentString the percent string 480 * @throws NullPointerException if <code>percentString</code> is null. 481 * @see #getPercentString() 482 * @hide draft / provisional / internal are hidden on Android 483 */ 484 public void setPercentString(String percentString) { 485 if (percentString == null) { 486 throw new NullPointerException("The input percent sign is null"); 487 } 488 this.percentString = percentString; 489 if (percentString.length() == 1) { 490 this.percent = percentString.charAt(0); 491 } else { 492 // Use default percent character as fallback 493 this.percent = DEF_PERCENT; 494 } 495 } 496 497 /** 498 * Returns the character used for a digit in a pattern. 499 * @return the digit pattern character 500 */ 501 public char getDigit() { 502 return digit; 503 } 504 505 /** 506 * Sets the character used for a digit in a pattern. 507 * @param digit the digit pattern character 508 */ 509 public void setDigit(char digit) { 510 this.digit = digit; 511 } 512 513 /** 514 * Returns the character used to separate positive and negative subpatterns 515 * in a pattern. 516 * @return the pattern separator character 517 */ 518 public char getPatternSeparator() { 519 return patternSeparator; 520 } 521 522 /** 523 * Sets the character used to separate positive and negative subpatterns 524 * in a pattern. 525 * @param patternSeparator the pattern separator character 526 */ 527 public void setPatternSeparator(char patternSeparator) { 528 this.patternSeparator = patternSeparator; 529 } 530 531 /** 532 * Returns the String used to represent infinity. Almost always left 533 * unchanged. 534 * @return the Infinity string 535 */ 536 //Bug 4194173 [Richard/GCL] 537 538 public String getInfinity() { 539 return infinity; 540 } 541 542 /** 543 * Sets the String used to represent infinity. Almost always left 544 * unchanged. 545 * @param infinity the Infinity String 546 */ 547 public void setInfinity(String infinity) { 548 this.infinity = infinity; 549 } 550 551 /** 552 * Returns the String used to represent NaN. Almost always left 553 * unchanged. 554 * @return the NaN String 555 */ 556 //Bug 4194173 [Richard/GCL] 557 public String getNaN() { 558 return NaN; 559 } 560 561 /** 562 * Sets the String used to represent NaN. Almost always left 563 * unchanged. 564 * @param NaN the NaN String 565 */ 566 public void setNaN(String NaN) { 567 this.NaN = NaN; 568 } 569 570 /** 571 * Returns the character used to represent minus sign. If no explicit 572 * negative format is specified, one is formed by prefixing 573 * minusSign to the positive format. 574 * @return the minus sign character 575 */ 576 public char getMinusSign() { 577 return minusSign; 578 } 579 580 /** 581 * Sets the character used to represent minus sign. If no explicit 582 * negative format is specified, one is formed by prefixing 583 * minusSign to the positive format. 584 * @param minusSign the minus sign character 585 */ 586 public void setMinusSign(char minusSign) { 587 this.minusSign = minusSign; 588 this.minusString = String.valueOf(minusSign); 589 } 590 591 /** 592 * <strong>[icu]</strong> Returns the string used to represent minus sign. 593 * @return the minus sign string 594 * @see #setMinusSignString(String) 595 * @hide draft / provisional / internal are hidden on Android 596 */ 597 public String getMinusSignString() { 598 return minusString; 599 } 600 601 /** 602 * <strong>[icu]</strong> Sets the string used to represent minus sign. 603 * <p> 604 * <b>Note:</b> When the input minus sign String is represented 605 * by multiple Java chars, then {@link #getMinusSign()} will 606 * return the default minus sign character ('-'). 607 * 608 * @param minusSignString the minus sign string 609 * @throws NullPointerException if <code>minusSignString</code> is null. 610 * @see #getGroupingSeparatorString() 611 * @hide draft / provisional / internal are hidden on Android 612 */ 613 public void setMinusSignString(String minusSignString) { 614 if (minusSignString == null) { 615 throw new NullPointerException("The input minus sign is null"); 616 } 617 this.minusString = minusSignString; 618 if (minusSignString.length() == 1) { 619 this.minusSign = minusSignString.charAt(0); 620 } else { 621 // Use the default minus sign as fallback 622 this.minusSign = DEF_MINUS_SIGN; 623 } 624 } 625 626 /** 627 * <strong>[icu]</strong> Returns the localized plus sign. 628 * @return the plus sign, used in localized patterns and formatted 629 * strings 630 * @see #setPlusSign 631 * @see #setMinusSign 632 * @see #getMinusSign 633 */ 634 public char getPlusSign() { 635 return plusSign; 636 } 637 638 /** 639 * <strong>[icu]</strong> Sets the localized plus sign. 640 * @param plus the plus sign, used in localized patterns and formatted 641 * strings 642 * @see #getPlusSign 643 * @see #setMinusSign 644 * @see #getMinusSign 645 */ 646 public void setPlusSign(char plus) { 647 this.plusSign = plus; 648 this.plusString = String.valueOf(plus); 649 } 650 651 /** 652 * <strong>[icu]</strong> Returns the string used to represent plus sign. 653 * @return the plus sign string 654 * @hide draft / provisional / internal are hidden on Android 655 */ 656 public String getPlusSignString() { 657 return plusString; 658 } 659 660 /** 661 * <strong>[icu]</strong> Sets the localized plus sign string. 662 * <p> 663 * <b>Note:</b> When the input plus sign String is represented 664 * by multiple Java chars, then {@link #getPlusSign()} will 665 * return the default plus sign character ('+'). 666 * 667 * @param plusSignString the plus sign string, used in localized patterns and formatted 668 * strings 669 * @throws NullPointerException if <code>plusSignString</code> is null. 670 * @see #getPlusSignString() 671 * @hide draft / provisional / internal are hidden on Android 672 */ 673 public void setPlusSignString(String plusSignString) { 674 if (plusSignString == null) { 675 throw new NullPointerException("The input plus sign is null"); 676 } 677 this.plusString = plusSignString; 678 if (plusSignString.length() == 1) { 679 this.plusSign = plusSignString.charAt(0); 680 } else { 681 // Use the default plus sign as fallback 682 this.plusSign = DEF_PLUS_SIGN; 683 } 684 } 685 686 /** 687 * Returns the string denoting the local currency. 688 * @return the local currency String. 689 */ 690 public String getCurrencySymbol() { 691 return currencySymbol; 692 } 693 694 /** 695 * Sets the string denoting the local currency. 696 * @param currency the local currency String. 697 */ 698 public void setCurrencySymbol(String currency) { 699 currencySymbol = currency; 700 } 701 702 /** 703 * Returns the international string denoting the local currency. 704 * @return the international string denoting the local currency 705 */ 706 public String getInternationalCurrencySymbol() { 707 return intlCurrencySymbol; 708 } 709 710 /** 711 * Sets the international string denoting the local currency. 712 * @param currency the international string denoting the local currency. 713 */ 714 public void setInternationalCurrencySymbol(String currency) { 715 intlCurrencySymbol = currency; 716 } 717 718 /** 719 * Returns the currency symbol, for {@link DecimalFormatSymbols#getCurrency()} API 720 * compatibility only. ICU clients should use the Currency API directly. 721 * @return the currency used, or null 722 */ 723 public Currency getCurrency() { 724 return currency; 725 } 726 727 /** 728 * Sets the currency. 729 * 730 * <p><strong>Note:</strong> ICU does not use the DecimalFormatSymbols for the currency 731 * any more. This API is present for API compatibility only. 732 * 733 * <p>This also sets the currency symbol attribute to the currency's symbol 734 * in the DecimalFormatSymbols' locale, and the international currency 735 * symbol attribute to the currency's ISO 4217 currency code. 736 * 737 * @param currency the new currency to be used 738 * @throws NullPointerException if <code>currency</code> is null 739 * @see #setCurrencySymbol 740 * @see #setInternationalCurrencySymbol 741 */ 742 public void setCurrency(Currency currency) { 743 if (currency == null) { 744 throw new NullPointerException(); 745 } 746 this.currency = currency; 747 intlCurrencySymbol = currency.getCurrencyCode(); 748 currencySymbol = currency.getSymbol(requestedLocale); 749 } 750 751 /** 752 * Returns the monetary decimal separator. 753 * @return the monetary decimal separator character 754 */ 755 public char getMonetaryDecimalSeparator() { 756 return monetarySeparator; 757 } 758 759 /** 760 * Sets the monetary decimal separator. 761 * @param sep the monetary decimal separator character 762 */ 763 public void setMonetaryDecimalSeparator(char sep) { 764 this.monetarySeparator = sep; 765 this.monetarySeparatorString = String.valueOf(sep); 766 } 767 768 /** 769 * <strong>[icu]</strong> Returns the monetary decimal separator string. 770 * @return the monetary decimal separator string 771 * @see #setMonetaryDecimalSeparatorString(String) 772 * @hide draft / provisional / internal are hidden on Android 773 */ 774 public String getMonetaryDecimalSeparatorString() { 775 return monetarySeparatorString; 776 } 777 778 /** 779 * <strong>[icu]</strong> Sets the monetary decimal separator string. 780 * <p> 781 * <b>Note:</b> When the input monetary decimal separator String is represented 782 * by multiple Java chars, then {@link #getMonetaryDecimalSeparatorString()} will 783 * return the default monetary decimal separator character ('.'). 784 * 785 * @param sep the monetary decimal separator string 786 * @throws NullPointerException if <code>sep</code> is null. 787 * @see #getMonetaryDecimalSeparatorString() 788 * @hide draft / provisional / internal are hidden on Android 789 */ 790 public void setMonetaryDecimalSeparatorString(String sep) { 791 if (sep == null) { 792 throw new NullPointerException("The input monetary decimal separator is null"); 793 } 794 this.monetarySeparatorString = sep; 795 if (sep.length() == 1) { 796 this.monetarySeparator = sep.charAt(0); 797 } else { 798 // Use default decimap separator character as fallbacl 799 this.monetarySeparator = DEF_DECIMAL_SEPARATOR; 800 } 801 } 802 803 /** 804 * <strong>[icu]</strong> Returns the monetary grouping separator. 805 * @return the monetary grouping separator character 806 */ 807 public char getMonetaryGroupingSeparator() { 808 return monetaryGroupingSeparator; 809 } 810 811 /** 812 * <strong>[icu]</strong> Sets the monetary grouping separator. 813 * @param sep the monetary grouping separator character 814 */ 815 public void setMonetaryGroupingSeparator(char sep) { 816 this.monetaryGroupingSeparator = sep; 817 this.monetaryGroupingSeparatorString = String.valueOf(sep); 818 } 819 820 /** 821 * <strong>[icu]</strong> Returns the monetary grouping separator. 822 * @return the monetary grouping separator string 823 * @see #setMonetaryGroupingSeparatorString(String) 824 * @hide draft / provisional / internal are hidden on Android 825 */ 826 public String getMonetaryGroupingSeparatorString() { 827 return monetaryGroupingSeparatorString; 828 } 829 830 /** 831 * <strong>[icu]</strong> Sets the monetary grouping separator string. 832 * <p> 833 * <b>Note:</b> When the input grouping separator String is represented 834 * by multiple Java chars, then {@link #getMonetaryGroupingSeparator()} will 835 * return the default monetary grouping separator character (','). 836 * 837 * @param sep the monetary grouping separator string 838 * @throws NullPointerException if <code>sep</code> is null. 839 * @see #getMonetaryGroupingSeparatorString() 840 * @hide draft / provisional / internal are hidden on Android 841 */ 842 public void setMonetaryGroupingSeparatorString(String sep) { 843 if (sep == null) { 844 throw new NullPointerException("The input monetary grouping separator is null"); 845 } 846 this.monetaryGroupingSeparatorString = sep; 847 if (sep.length() == 1) { 848 this.monetaryGroupingSeparator = sep.charAt(0); 849 } else { 850 // Use default grouping separator character as fallback 851 this.monetaryGroupingSeparator = DEF_GROUPING_SEPARATOR; 852 } 853 } 854 855 /** 856 } 857 * Internal API for NumberFormat 858 * @return String currency pattern string 859 */ 860 String getCurrencyPattern() { 861 return currencyPattern; 862 } 863 864 /** 865 * Returns the multiplication sign 866 */ 867 public String getExponentMultiplicationSign() { 868 return exponentMultiplicationSign; 869 } 870 871 /** 872 * Sets the multiplication sign 873 */ 874 public void setExponentMultiplicationSign(String exponentMultiplicationSign) { 875 this.exponentMultiplicationSign = exponentMultiplicationSign; 876 } 877 878 /** 879 * <strong>[icu]</strong> Returns the string used to separate the mantissa from the exponent. 880 * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. 881 * @return the localized exponent symbol, used in localized patterns 882 * and formatted strings 883 * @see #setExponentSeparator 884 */ 885 public String getExponentSeparator() { 886 return exponentSeparator; 887 } 888 889 /** 890 * <strong>[icu]</strong> Sets the string used to separate the mantissa from the exponent. 891 * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. 892 * @param exp the localized exponent symbol, used in localized patterns 893 * and formatted strings 894 * @see #getExponentSeparator 895 */ 896 public void setExponentSeparator(String exp) { 897 exponentSeparator = exp; 898 } 899 900 /** 901 * <strong>[icu]</strong> Returns the character used to pad numbers out to a specified width. This is 902 * not the pad character itself; rather, it is the special pattern character 903 * <em>preceding</em> the pad character. In the pattern "*_#,##0", '*' is the pad 904 * escape, and '_' is the pad character. 905 * @return the character 906 * @see #setPadEscape 907 * @see DecimalFormat#getFormatWidth 908 * @see DecimalFormat#getPadPosition 909 * @see DecimalFormat#getPadCharacter 910 */ 911 public char getPadEscape() { 912 return padEscape; 913 } 914 915 /** 916 * <strong>[icu]</strong> Sets the character used to pad numbers out to a specified width. This is not 917 * the pad character itself; rather, it is the special pattern character 918 * <em>preceding</em> the pad character. In the pattern "*_#,##0", '*' is the pad 919 * escape, and '_' is the pad character. 920 * @see #getPadEscape 921 * @see DecimalFormat#setFormatWidth 922 * @see DecimalFormat#setPadPosition 923 * @see DecimalFormat#setPadCharacter 924 */ 925 public void setPadEscape(char c) { 926 padEscape = c; 927 } 928 929 /** 930 * <strong>[icu]</strong> Indicates the currency match pattern used in {@link #getPatternForCurrencySpacing}. 931 */ 932 public static final int CURRENCY_SPC_CURRENCY_MATCH = 0; 933 934 /** 935 * <strong>[icu]</strong> Indicates the surrounding match pattern used in {@link 936 * #getPatternForCurrencySpacing}. 937 */ 938 public static final int CURRENCY_SPC_SURROUNDING_MATCH = 1; 939 940 /** 941 * <strong>[icu]</strong> Indicates the insertion value used in {@link #getPatternForCurrencySpacing}. 942 */ 943 public static final int CURRENCY_SPC_INSERT = 2; 944 945 private String[] currencySpcBeforeSym; 946 private String[] currencySpcAfterSym; 947 948 /** 949 * <strong>[icu]</strong> Returns the desired currency spacing value. Original values come from ICU's 950 * CLDR data based on the locale provided during construction, and can be null. These 951 * values govern what and when text is inserted between a currency code/name/symbol 952 * and the currency amount when formatting money. 953 * 954 * <p>For more information, see <a href="http://www.unicode.org/reports/tr35/#Currencies" 955 * >UTS#35 section 5.10.2</a>. 956 * 957 * <p><strong>Note:</strong> ICU4J does not currently use this information. 958 * 959 * @param itemType one of CURRENCY_SPC_CURRENCY_MATCH, CURRENCY_SPC_SURROUNDING_MATCH 960 * or CURRENCY_SPC_INSERT 961 * @param beforeCurrency true to get the <code>beforeCurrency</code> values, false 962 * to get the <code>afterCurrency</code> values. 963 * @return the value, or null. 964 * @see #setPatternForCurrencySpacing(int, boolean, String) 965 */ 966 public String getPatternForCurrencySpacing(int itemType, boolean beforeCurrency) { 967 if (itemType < CURRENCY_SPC_CURRENCY_MATCH || 968 itemType > CURRENCY_SPC_INSERT ) { 969 throw new IllegalArgumentException("unknown currency spacing: " + itemType); 970 } 971 if (beforeCurrency) { 972 return currencySpcBeforeSym[itemType]; 973 } 974 return currencySpcAfterSym[itemType]; 975 } 976 977 /** 978 * <strong>[icu]</strong> Sets the indicated currency spacing pattern or value. See {@link 979 * #getPatternForCurrencySpacing} for more information. 980 * 981 * <p>Values for currency match and surrounding match must be {@link 982 * android.icu.text.UnicodeSet} patterns. Values for insert can be any string. 983 * 984 * <p><strong>Note:</strong> ICU4J does not currently use this information. 985 * 986 * @param itemType one of CURRENCY_SPC_CURRENCY_MATCH, CURRENCY_SPC_SURROUNDING_MATCH 987 * or CURRENCY_SPC_INSERT 988 * @param beforeCurrency true if the pattern is for before the currency symbol. 989 * false if the pattern is for after it. 990 * @param pattern string to override current setting; can be null. 991 * @see #getPatternForCurrencySpacing(int, boolean) 992 */ 993 public void setPatternForCurrencySpacing(int itemType, boolean beforeCurrency, String pattern) { 994 if (itemType < CURRENCY_SPC_CURRENCY_MATCH || 995 itemType > CURRENCY_SPC_INSERT ) { 996 throw new IllegalArgumentException("unknown currency spacing: " + itemType); 997 } 998 if (beforeCurrency) { 999 currencySpcBeforeSym[itemType] = pattern; 1000 } else { 1001 currencySpcAfterSym[itemType] = pattern; 1002 } 1003 } 1004 1005 /** 1006 * Returns the locale for which this object was constructed. 1007 * @return the locale for which this object was constructed 1008 */ 1009 public Locale getLocale() { 1010 return requestedLocale; 1011 } 1012 1013 /** 1014 * Returns the locale for which this object was constructed. 1015 * @return the locale for which this object was constructed 1016 */ 1017 public ULocale getULocale() { 1018 return ulocale; 1019 } 1020 1021 /** 1022 * {@inheritDoc} 1023 */ 1024 @Override 1025 public Object clone() { 1026 try { 1027 return super.clone(); 1028 // other fields are bit-copied 1029 } catch (CloneNotSupportedException e) { 1030 ///CLOVER:OFF 1031 throw new ICUCloneNotSupportedException(e); 1032 ///CLOVER:ON 1033 } 1034 } 1035 1036 /** 1037 * {@inheritDoc} 1038 */ 1039 @Override 1040 public boolean equals(Object obj) { 1041 if (!(obj instanceof DecimalFormatSymbols)) { 1042 return false; 1043 } 1044 if (this == obj) { 1045 return true; 1046 } 1047 DecimalFormatSymbols other = (DecimalFormatSymbols) obj; 1048 for (int i = 0; i <= CURRENCY_SPC_INSERT; i++) { 1049 if (!currencySpcBeforeSym[i].equals(other.currencySpcBeforeSym[i])) { 1050 return false; 1051 } 1052 if (!currencySpcAfterSym[i].equals(other.currencySpcAfterSym[i])) { 1053 return false; 1054 } 1055 } 1056 1057 if ( other.digits == null ) { 1058 for (int i = 0 ; i < 10 ; i++) { 1059 if (digits[i] != other.zeroDigit + i) { 1060 return false; 1061 } 1062 } 1063 } else if (!Arrays.equals(digits,other.digits)) { 1064 return false; 1065 } 1066 1067 return ( 1068 groupingSeparator == other.groupingSeparator && 1069 decimalSeparator == other.decimalSeparator && 1070 percent == other.percent && 1071 perMill == other.perMill && 1072 digit == other.digit && 1073 minusSign == other.minusSign && 1074 minusString.equals(other.minusString) && 1075 patternSeparator == other.patternSeparator && 1076 infinity.equals(other.infinity) && 1077 NaN.equals(other.NaN) && 1078 currencySymbol.equals(other.currencySymbol) && 1079 intlCurrencySymbol.equals(other.intlCurrencySymbol) && 1080 padEscape == other.padEscape && 1081 plusSign == other.plusSign && 1082 plusString.equals(other.plusString) && 1083 exponentSeparator.equals(other.exponentSeparator) && 1084 monetarySeparator == other.monetarySeparator && 1085 monetaryGroupingSeparator == other.monetaryGroupingSeparator && 1086 exponentMultiplicationSign.equals(other.exponentMultiplicationSign)); 1087 } 1088 1089 /** 1090 * {@inheritDoc} 1091 */ 1092 @Override 1093 public int hashCode() { 1094 int result = digits[0]; 1095 result = result * 37 + groupingSeparator; 1096 result = result * 37 + decimalSeparator; 1097 return result; 1098 } 1099 1100 /** 1101 * List of field names to be loaded from the data files. 1102 * The indices of each name into the array correspond to the position of that item in the 1103 * numberElements array. 1104 */ 1105 private static final String[] SYMBOL_KEYS = { 1106 "decimal", 1107 "group", 1108 "list", 1109 "percentSign", 1110 "minusSign", 1111 "plusSign", 1112 "exponential", 1113 "perMille", 1114 "infinity", 1115 "nan", 1116 "currencyDecimal", 1117 "currencyGroup", 1118 "superscriptingExponent" 1119 }; 1120 1121 /* 1122 * Default digits 1123 */ 1124 private static final String[] DEF_DIGIT_STRINGS_ARRAY = 1125 {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; 1126 1127 private static final char[] DEF_DIGIT_CHARS_ARRAY = 1128 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; 1129 1130 /* 1131 * Default symbol characters, used for fallbacks. 1132 */ 1133 private static final char DEF_DECIMAL_SEPARATOR = '.'; 1134 private static final char DEF_GROUPING_SEPARATOR = ','; 1135 private static final char DEF_PERCENT = '%'; 1136 private static final char DEF_MINUS_SIGN = '-'; 1137 private static final char DEF_PLUS_SIGN = '+'; 1138 private static final char DEF_PERMILL = '\u2030'; 1139 1140 /** 1141 * List of default values for the symbols. 1142 */ 1143 private static final String[] SYMBOL_DEFAULTS = new String[] { 1144 String.valueOf(DEF_DECIMAL_SEPARATOR), // decimal 1145 String.valueOf(DEF_GROUPING_SEPARATOR), // group 1146 ";", // list 1147 String.valueOf(DEF_PERCENT), // percentSign 1148 String.valueOf(DEF_MINUS_SIGN), // minusSign 1149 String.valueOf(DEF_PLUS_SIGN), // plusSign 1150 "E", // exponential 1151 String.valueOf(DEF_PERMILL), // perMille 1152 "\u221e", // infinity 1153 "NaN", // NaN 1154 null, // currency decimal 1155 null, // currency group 1156 "\u00D7" // superscripting exponent 1157 }; 1158 1159 /** 1160 * Constants for path names in the data bundles. 1161 */ 1162 private static final String LATIN_NUMBERING_SYSTEM = "latn"; 1163 private static final String NUMBER_ELEMENTS = "NumberElements"; 1164 private static final String SYMBOLS = "symbols"; 1165 1166 /** 1167 * Sink for enumerating all of the decimal format symbols (more specifically, anything 1168 * under the "NumberElements.symbols" tree). 1169 * 1170 * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root): 1171 * Only store a value if it is still missing, that is, it has not been overridden. 1172 */ 1173 private static final class DecFmtDataSink extends UResource.Sink { 1174 1175 private String[] numberElements; // Array where to store the characters (set in constructor) 1176 1177 public DecFmtDataSink(String[] numberElements) { 1178 this.numberElements = numberElements; 1179 } 1180 1181 @Override 1182 public void put(UResource.Key key, UResource.Value value, boolean noFallback) { 1183 UResource.Table symbolsTable = value.getTable(); 1184 for (int j = 0; symbolsTable.getKeyAndValue(j, key, value); ++j) { 1185 for (int i = 0; i < SYMBOL_KEYS.length; i++) { 1186 if (key.contentEquals(SYMBOL_KEYS[i])) { 1187 if (numberElements[i] == null) { 1188 numberElements[i] = value.toString(); 1189 } 1190 break; 1191 } 1192 } 1193 } 1194 } 1195 } 1196 1197 /** 1198 * Initializes the symbols from the locale data. 1199 */ 1200 private void initialize( ULocale locale ) { 1201 this.requestedLocale = locale.toLocale(); 1202 this.ulocale = locale; 1203 CacheData data = cachedLocaleData.getInstance(locale, null /* unused */); 1204 setLocale(data.validLocale, data.validLocale); 1205 setDigitStrings(data.digits); 1206 String[] numberElements = data.numberElements; 1207 1208 // Copy data from the numberElements map into instance fields 1209 setDecimalSeparatorString(numberElements[0]); 1210 setGroupingSeparatorString(numberElements[1]); 1211 1212 // See CLDR #9781 1213 // assert numberElements[2].length() == 1; 1214 patternSeparator = numberElements[2].charAt(0); 1215 1216 setPercentString(numberElements[3]); 1217 setMinusSignString(numberElements[4]); 1218 setPlusSignString(numberElements[5]); 1219 setExponentSeparator(numberElements[6]); 1220 setPerMillString(numberElements[7]); 1221 setInfinity(numberElements[8]); 1222 setNaN(numberElements[9]); 1223 setMonetaryDecimalSeparatorString(numberElements[10]); 1224 setMonetaryGroupingSeparatorString(numberElements[11]); 1225 setExponentMultiplicationSign(numberElements[12]); 1226 1227 digit = DecimalFormat.PATTERN_DIGIT; // Localized pattern character no longer in CLDR 1228 padEscape = DecimalFormat.PATTERN_PAD_ESCAPE; 1229 sigDigit = DecimalFormat.PATTERN_SIGNIFICANT_DIGIT; 1230 1231 1232 CurrencyDisplayInfo info = CurrencyData.provider.getInstance(locale, true); 1233 1234 // Obtain currency data from the currency API. This is strictly 1235 // for backward compatibility; we don't use DecimalFormatSymbols 1236 // for currency data anymore. 1237 currency = Currency.getInstance(locale); 1238 if (currency != null) { 1239 intlCurrencySymbol = currency.getCurrencyCode(); 1240 currencySymbol = currency.getName(locale, Currency.SYMBOL_NAME, null); 1241 CurrencyFormatInfo fmtInfo = info.getFormatInfo(intlCurrencySymbol); 1242 if (fmtInfo != null) { 1243 currencyPattern = fmtInfo.currencyPattern; 1244 setMonetaryDecimalSeparatorString(fmtInfo.monetarySeparator); 1245 setMonetaryGroupingSeparatorString(fmtInfo.monetaryGroupingSeparator); 1246 } 1247 } else { 1248 intlCurrencySymbol = "XXX"; 1249 currencySymbol = "\u00A4"; // 'OX' currency symbol 1250 } 1251 1252 1253 // Get currency spacing data. 1254 initSpacingInfo(info.getSpacingInfo()); 1255 } 1256 1257 private static CacheData loadData(ULocale locale) { 1258 String nsName; 1259 // Attempt to set the decimal digits based on the numbering system for the requested locale. 1260 NumberingSystem ns = NumberingSystem.getInstance(locale); 1261 String[] digits = new String[10]; 1262 if (ns != null && ns.getRadix() == 10 && !ns.isAlgorithmic() && 1263 NumberingSystem.isValidDigitString(ns.getDescription())) { 1264 String digitString = ns.getDescription(); 1265 1266 for (int i = 0, offset = 0; i < 10; i++) { 1267 int cp = digitString.codePointAt(offset); 1268 int nextOffset = offset + Character.charCount(cp); 1269 digits[i] = digitString.substring(offset, nextOffset); 1270 offset = nextOffset; 1271 } 1272 nsName = ns.getName(); 1273 } else { 1274 // Default numbering system 1275 digits = DEF_DIGIT_STRINGS_ARRAY; 1276 nsName = "latn"; 1277 } 1278 1279 // Open the resource bundle and get the locale IDs. 1280 // TODO: Is there a better way to get the locale than making an ICUResourceBundle instance? 1281 ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle. 1282 getBundleInstance(ICUData.ICU_BASE_NAME, locale); 1283 // TODO: Determine actual and valid locale correctly. 1284 ULocale validLocale = rb.getULocale(); 1285 1286 String[] numberElements = new String[SYMBOL_KEYS.length]; 1287 1288 // Load using a data sink 1289 DecFmtDataSink sink = new DecFmtDataSink(numberElements); 1290 try { 1291 rb.getAllItemsWithFallback(NUMBER_ELEMENTS + "/" + nsName + "/" + SYMBOLS, sink); 1292 } catch (MissingResourceException e) { 1293 // The symbols don't exist for the given nsName and resource bundle. 1294 // Silently ignore and fall back to Latin. 1295 } 1296 1297 // Load the Latin fallback if necessary 1298 boolean hasNull = false; 1299 for (String entry : numberElements) { 1300 if (entry == null) { 1301 hasNull = true; 1302 break; 1303 } 1304 } 1305 if (hasNull && !nsName.equals(LATIN_NUMBERING_SYSTEM)) { 1306 rb.getAllItemsWithFallback(NUMBER_ELEMENTS + "/" + LATIN_NUMBERING_SYSTEM + "/" + SYMBOLS, sink); 1307 } 1308 1309 // Fill in any remaining missing values 1310 for (int i = 0; i < SYMBOL_KEYS.length; i++) { 1311 if (numberElements[i] == null) { 1312 numberElements[i] = SYMBOL_DEFAULTS[i]; 1313 } 1314 } 1315 1316 // If monetary decimal or grouping were not explicitly set, then set them to be the same as 1317 // their non-monetary counterparts. 1318 if (numberElements[10] == null) { 1319 numberElements[10] = numberElements[0]; 1320 } 1321 if (numberElements[11] == null) { 1322 numberElements[11] = numberElements[1]; 1323 } 1324 1325 return new CacheData(validLocale, digits, numberElements); 1326 } 1327 1328 private void initSpacingInfo(CurrencySpacingInfo spcInfo) { 1329 currencySpcBeforeSym = spcInfo.getBeforeSymbols(); 1330 currencySpcAfterSym = spcInfo.getAfterSymbols(); 1331 } 1332 1333 /** 1334 * Reads the default serializable fields, then if <code>serialVersionOnStream</code> 1335 * is less than 1, initialize <code>monetarySeparator</code> to be 1336 * the same as <code>decimalSeparator</code> and <code>exponential</code> 1337 * to be 'E'. 1338 * Finally, sets serialVersionOnStream back to the maximum allowed value so that 1339 * default serialization will work properly if this object is streamed out again. 1340 */ 1341 private void readObject(ObjectInputStream stream) 1342 throws IOException, ClassNotFoundException { 1343 1344 // TODO: it looks to me {dlf} that the serialization code was never updated 1345 // to handle the actual/valid ulocale fields. 1346 1347 stream.defaultReadObject(); 1348 ///CLOVER:OFF 1349 // we don't have data for these old serialized forms any more 1350 if (serialVersionOnStream < 1) { 1351 // Didn't have monetarySeparator or exponential field; 1352 // use defaults. 1353 monetarySeparator = decimalSeparator; 1354 exponential = 'E'; 1355 } 1356 if (serialVersionOnStream < 2) { 1357 padEscape = DecimalFormat.PATTERN_PAD_ESCAPE; 1358 plusSign = DecimalFormat.PATTERN_PLUS_SIGN; 1359 exponentSeparator = String.valueOf(exponential); 1360 // Although we read the exponential field on stream to create the 1361 // exponentSeparator, we don't do the reverse, since scientific 1362 // notation isn't supported by the old classes, even though the 1363 // symbol is there. 1364 } 1365 ///CLOVER:ON 1366 if (serialVersionOnStream < 3) { 1367 // Resurrected objects from old streams will have no 1368 // locale. There is no 100% fix for this. A 1369 // 90% fix is to construct a mapping of data back to 1370 // locale, perhaps a hash of all our members. This is 1371 // expensive and doesn't seem worth it. 1372 requestedLocale = Locale.getDefault(); 1373 } 1374 if (serialVersionOnStream < 4) { 1375 // use same default behavior as for versions with no Locale 1376 ulocale = ULocale.forLocale(requestedLocale); 1377 } 1378 if (serialVersionOnStream < 5) { 1379 // use the same one for groupingSeparator 1380 monetaryGroupingSeparator = groupingSeparator; 1381 } 1382 if (serialVersionOnStream < 6) { 1383 // Set null to CurrencySpacing related fields. 1384 if (currencySpcBeforeSym == null) { 1385 currencySpcBeforeSym = new String[CURRENCY_SPC_INSERT+1]; 1386 } 1387 if (currencySpcAfterSym == null) { 1388 currencySpcAfterSym = new String[CURRENCY_SPC_INSERT+1]; 1389 } 1390 initSpacingInfo(CurrencyData.CurrencySpacingInfo.DEFAULT); 1391 } 1392 if (serialVersionOnStream < 7) { 1393 // Set minusString,plusString from minusSign,plusSign 1394 if (minusString == null) { 1395 minusString = String.valueOf(minusSign); 1396 } 1397 if (plusString == null) { 1398 plusString = String.valueOf(plusSign); 1399 } 1400 } 1401 if (serialVersionOnStream < 8) { 1402 if (exponentMultiplicationSign == null) { 1403 exponentMultiplicationSign = "\u00D7"; 1404 } 1405 } 1406 if (serialVersionOnStream < 9) { 1407 // String version of digits 1408 if (digitStrings == null) { 1409 digitStrings = new String[10]; 1410 if (digits != null && digits.length == 10) { 1411 zeroDigit = digits[0]; 1412 for (int i = 0; i < 10; i++) { 1413 digitStrings[i] = String.valueOf(digits[i]); 1414 } 1415 } else { 1416 char digit = zeroDigit; 1417 if (digits == null) { 1418 digits = new char[10]; 1419 } 1420 for (int i = 0; i < 10; i++) { 1421 digits[i] = digit; 1422 digitStrings[i] = String.valueOf(digit); 1423 digit++; 1424 } 1425 } 1426 } 1427 1428 // String version of symbols 1429 if (decimalSeparatorString == null) { 1430 decimalSeparatorString = String.valueOf(decimalSeparator); 1431 } 1432 if (groupingSeparatorString == null) { 1433 groupingSeparatorString = String.valueOf(groupingSeparator); 1434 } 1435 if (percentString == null) { 1436 percentString = String.valueOf(percentString); 1437 } 1438 if (perMillString == null) { 1439 perMillString = String.valueOf(perMill); 1440 } 1441 if (monetarySeparatorString == null) { 1442 monetarySeparatorString = String.valueOf(monetarySeparator); 1443 } 1444 if (monetaryGroupingSeparatorString == null) { 1445 monetaryGroupingSeparatorString = String.valueOf(monetaryGroupingSeparator); 1446 } 1447 } 1448 1449 serialVersionOnStream = currentSerialVersion; 1450 1451 // recreate 1452 currency = Currency.getInstance(intlCurrencySymbol); 1453 } 1454 1455 /** 1456 * Character used for zero. This remains only for backward compatibility 1457 * purposes. The digits array below is now used to actively store the digits. 1458 * 1459 * @serial 1460 * @see #getZeroDigit 1461 */ 1462 private char zeroDigit; 1463 1464 /** 1465 * Array of characters used for the digits 0-9 in order. 1466 */ 1467 private char digits[]; 1468 1469 /** 1470 * Array of Strings used for the digits 0-9 in order. 1471 * @serial 1472 */ 1473 private String digitStrings[]; 1474 1475 /** 1476 * Character used for thousands separator. 1477 * 1478 * @serial 1479 * @see #getGroupingSeparator 1480 */ 1481 private char groupingSeparator; 1482 1483 /** 1484 * String used for thousands separator. 1485 * @serial 1486 */ 1487 private String groupingSeparatorString; 1488 1489 /** 1490 * Character used for decimal sign. 1491 * 1492 * @serial 1493 * @see #getDecimalSeparator 1494 */ 1495 private char decimalSeparator; 1496 1497 /** 1498 * String used for decimal sign. 1499 * @serial 1500 */ 1501 private String decimalSeparatorString; 1502 1503 /** 1504 * Character used for mille percent sign. 1505 * 1506 * @serial 1507 * @see #getPerMill 1508 */ 1509 private char perMill; 1510 1511 /** 1512 * String used for mille percent sign. 1513 * @serial 1514 */ 1515 private String perMillString; 1516 1517 /** 1518 * Character used for percent sign. 1519 * @serial 1520 * @see #getPercent 1521 */ 1522 private char percent; 1523 1524 /** 1525 * String used for percent sign. 1526 * @serial 1527 */ 1528 private String percentString; 1529 1530 /** 1531 * Character used for a digit in a pattern. 1532 * 1533 * @serial 1534 * @see #getDigit 1535 */ 1536 private char digit; 1537 1538 /** 1539 * Character used for a significant digit in a pattern. 1540 * 1541 * @serial 1542 * @see #getSignificantDigit 1543 */ 1544 private char sigDigit; 1545 1546 /** 1547 * Character used to separate positive and negative subpatterns 1548 * in a pattern. 1549 * 1550 * @serial 1551 * @see #getPatternSeparator 1552 */ 1553 private char patternSeparator; 1554 1555 /** 1556 * Character used to represent infinity. 1557 * @serial 1558 * @see #getInfinity 1559 */ 1560 private String infinity; 1561 1562 /** 1563 * Character used to represent NaN. 1564 * @serial 1565 * @see #getNaN 1566 */ 1567 private String NaN; 1568 1569 /** 1570 * Character used to represent minus sign. 1571 * @serial 1572 * @see #getMinusSign 1573 */ 1574 private char minusSign; 1575 1576 /** 1577 * String versions of minus sign. 1578 * @serial 1579 */ 1580 private String minusString; 1581 1582 /** 1583 * The character used to indicate a plus sign. 1584 * @serial 1585 */ 1586 private char plusSign; 1587 1588 /** 1589 * String versions of plus sign. 1590 * @serial 1591 */ 1592 private String plusString; 1593 1594 /** 1595 * String denoting the local currency, e.g. "$". 1596 * @serial 1597 * @see #getCurrencySymbol 1598 */ 1599 private String currencySymbol; 1600 1601 /** 1602 * International string denoting the local currency, e.g. "USD". 1603 * @serial 1604 * @see #getInternationalCurrencySymbol 1605 */ 1606 private String intlCurrencySymbol; 1607 1608 /** 1609 * The decimal separator character used when formatting currency values. 1610 * @serial 1611 * @see #getMonetaryDecimalSeparator 1612 */ 1613 private char monetarySeparator; // Field new in JDK 1.1.6 1614 1615 /** 1616 * The decimal separator string used when formatting currency values. 1617 * @serial 1618 */ 1619 private String monetarySeparatorString; 1620 1621 /** 1622 * The grouping separator character used when formatting currency values. 1623 * @serial 1624 * @see #getMonetaryGroupingSeparator 1625 */ 1626 private char monetaryGroupingSeparator; // Field new in JDK 1.1.6 1627 1628 /** 1629 * The grouping separator string used when formatting currency values. 1630 * @serial 1631 */ 1632 private String monetaryGroupingSeparatorString; 1633 1634 /** 1635 * The character used to distinguish the exponent in a number formatted 1636 * in exponential notation, e.g. 'E' for a number such as "1.23E45". 1637 * <p> 1638 * Note that this field has been superseded by <code>exponentSeparator</code>. 1639 * It is retained for backward compatibility. 1640 * 1641 * @serial 1642 */ 1643 private char exponential; // Field new in JDK 1.1.6 1644 1645 /** 1646 * The string used to separate the mantissa from the exponent. 1647 * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4. 1648 * <p> 1649 * Note that this supersedes the <code>exponential</code> field. 1650 * 1651 * @serial 1652 */ 1653 private String exponentSeparator; 1654 1655 /** 1656 * The character used to indicate a padding character in a format, 1657 * e.g., '*' in a pattern such as "$*_#,##0.00". 1658 * @serial 1659 */ 1660 private char padEscape; 1661 1662 /** 1663 * The locale for which this object was constructed. Set to the 1664 * default locale for objects resurrected from old streams. 1665 */ 1666 private Locale requestedLocale; 1667 1668 /** 1669 * The requested ULocale. We keep the old locale for serialization compatibility. 1670 */ 1671 private ULocale ulocale; 1672 1673 /** 1674 * Exponent multiplication sign. e.g "x" 1675 * @serial 1676 */ 1677 private String exponentMultiplicationSign = null; 1678 1679 // Proclaim JDK 1.1 FCS compatibility 1680 private static final long serialVersionUID = 5772796243397350300L; 1681 1682 // The internal serial version which says which version was written 1683 // - 0 (default) for version up to JDK 1.1.5 1684 // - 1 for version from JDK 1.1.6, which includes two new fields: 1685 // monetarySeparator and exponential. 1686 // - 2 for version from AlphaWorks, which includes 3 new fields: 1687 // padEscape, exponentSeparator, and plusSign. 1688 // - 3 for ICU 2.2, which includes the locale field 1689 // - 4 for ICU 3.2, which includes the ULocale field 1690 // - 5 for ICU 3.6, which includes the monetaryGroupingSeparator field 1691 // - 6 for ICU 4.2, which includes the currencySpc* fields 1692 // - 7 for ICU 52, which includes the minusString and plusString fields 1693 // - 8 for ICU 54, which includes exponentMultiplicationSign field. 1694 // - 9 for ICU 58, which includes a series of String symbol fields. 1695 private static final int currentSerialVersion = 8; 1696 1697 /** 1698 * Describes the version of <code>DecimalFormatSymbols</code> present on the stream. 1699 * Possible values are: 1700 * <ul> 1701 * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6. 1702 * 1703 * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which includes 1704 * two new fields: <code>monetarySeparator</code> and <code>exponential</code>. 1705 * <li><b>2</b>: Version for AlphaWorks. Adds padEscape, exponentSeparator, 1706 * and plusSign. 1707 * <li><b>3</b>: Version for ICU 2.2, which adds locale. 1708 * <li><b>4</b>: Version for ICU 3.2, which adds ulocale. 1709 * <li><b>5</b>: Version for ICU 3.6, which adds monetaryGroupingSeparator. 1710 * <li><b>6</b>: Version for ICU 4.2, which adds currencySpcBeforeSym and 1711 * currencySpcAfterSym. 1712 * <li><b>7</b>: Version for ICU 52, which adds minusString and plusString. 1713 * </ul> 1714 * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format 1715 * (corresponding to the highest allowable <code>serialVersionOnStream</code>) 1716 * is always written. 1717 * 1718 * @serial 1719 */ 1720 private int serialVersionOnStream = currentSerialVersion; 1721 1722 /** 1723 * cache to hold the NumberElements of a Locale. 1724 */ 1725 private static final CacheBase<ULocale, CacheData, Void> cachedLocaleData = 1726 new SoftCache<ULocale, CacheData, Void>() { 1727 @Override 1728 protected CacheData createInstance(ULocale locale, Void unused) { 1729 return DecimalFormatSymbols.loadData(locale); 1730 } 1731 }; 1732 1733 /** 1734 * 1735 */ 1736 private String currencyPattern = null; 1737 1738 // -------- BEGIN ULocale boilerplate -------- 1739 1740 /** 1741 * <strong>[icu]</strong> Returns the locale that was used to create this object, or null. 1742 * This may may differ from the locale requested at the time of 1743 * this object's creation. For example, if an object is created 1744 * for locale <tt>en_US_CALIFORNIA</tt>, the actual data may be 1745 * drawn from <tt>en</tt> (the <i>actual</i> locale), and 1746 * <tt>en_US</tt> may be the most specific locale that exists (the 1747 * <i>valid</i> locale). 1748 * 1749 * <p>Note: The <i>actual</i> locale is returned correctly, but the <i>valid</i> 1750 * locale is not, in most cases. 1751 * @param type type of information requested, either {@link 1752 * android.icu.util.ULocale#VALID_LOCALE} or {@link 1753 * android.icu.util.ULocale#ACTUAL_LOCALE}. 1754 * @return the information specified by <i>type</i>, or null if 1755 * this object was not constructed from locale data. 1756 * @see android.icu.util.ULocale 1757 * @see android.icu.util.ULocale#VALID_LOCALE 1758 * @see android.icu.util.ULocale#ACTUAL_LOCALE 1759 * @hide draft / provisional / internal are hidden on Android 1760 */ 1761 public final ULocale getLocale(ULocale.Type type) { 1762 return type == ULocale.ACTUAL_LOCALE ? 1763 this.actualLocale : this.validLocale; 1764 } 1765 1766 /** 1767 * <strong>[icu]</strong> Sets information about the locales that were used to create this 1768 * object. If the object was not constructed from locale data, 1769 * both arguments should be set to null. Otherwise, neither 1770 * should be null. The actual locale must be at the same level or 1771 * less specific than the valid locale. This method is intended 1772 * for use by factories or other entities that create objects of 1773 * this class. 1774 * @param valid the most specific locale containing any resource 1775 * data, or null 1776 * @param actual the locale containing data used to construct this 1777 * object, or null 1778 * @see android.icu.util.ULocale 1779 * @see android.icu.util.ULocale#VALID_LOCALE 1780 * @see android.icu.util.ULocale#ACTUAL_LOCALE 1781 */ 1782 final void setLocale(ULocale valid, ULocale actual) { 1783 // Change the following to an assertion later 1784 if ((valid == null) != (actual == null)) { 1785 ///CLOVER:OFF 1786 throw new IllegalArgumentException(); 1787 ///CLOVER:ON 1788 } 1789 // Another check we could do is that the actual locale is at 1790 // the same level or less specific than the valid locale. 1791 this.validLocale = valid; 1792 this.actualLocale = actual; 1793 } 1794 1795 /** 1796 * The most specific locale containing any resource data, or null. 1797 * @see android.icu.util.ULocale 1798 */ 1799 private ULocale validLocale; 1800 1801 /** 1802 * The locale containing data used to construct this object, or 1803 * null. 1804 * @see android.icu.util.ULocale 1805 */ 1806 private ULocale actualLocale; 1807 1808 // not serialized, reconstructed from intlCurrencyCode 1809 private transient Currency currency; 1810 1811 // -------- END ULocale boilerplate -------- 1812 1813 private static class CacheData { 1814 final ULocale validLocale; 1815 final String[] digits; 1816 final String[] numberElements; 1817 1818 public CacheData(ULocale loc, String[] digits, String[] numberElements) { 1819 validLocale = loc; 1820 this.digits = digits; 1821 this.numberElements = numberElements; 1822 } 1823 } 1824} 1825