1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27/* 28 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 29 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved 30 * 31 * The original version of this source code and documentation is copyrighted 32 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These 33 * materials are provided under terms of a License Agreement between Taligent 34 * and Sun. This technology is protected by multiple US and International 35 * patents. This notice and attribution to Taligent may not be removed. 36 * Taligent is a registered trademark of Taligent, Inc. 37 * 38 */ 39 40package java.text; 41 42import java.io.IOException; 43import java.io.ObjectInputStream; 44import java.io.ObjectOutputStream; 45import java.io.ObjectStreamField; 46import java.math.BigDecimal; 47import java.math.BigInteger; 48import java.math.RoundingMode; 49import java.util.Currency; 50import java.util.Locale; 51import java.util.Objects; 52import java.util.concurrent.ConcurrentHashMap; 53import java.util.concurrent.ConcurrentMap; 54import java.util.concurrent.atomic.AtomicInteger; 55import java.util.concurrent.atomic.AtomicLong; 56import libcore.icu.LocaleData; 57 58import android.icu.math.MathContext; 59 60/** 61 * <code>DecimalFormat</code> is a concrete subclass of 62 * <code>NumberFormat</code> that formats decimal numbers. It has a variety of 63 * features designed to make it possible to parse and format numbers in any 64 * locale, including support for Western, Arabic, and Indic digits. It also 65 * supports different kinds of numbers, including integers (123), fixed-point 66 * numbers (123.4), scientific notation (1.23E4), percentages (12%), and 67 * currency amounts ($123). All of these can be localized. 68 * 69 * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the 70 * default locale, call one of <code>NumberFormat</code>'s factory methods, such 71 * as <code>getInstance()</code>. In general, do not call the 72 * <code>DecimalFormat</code> constructors directly, since the 73 * <code>NumberFormat</code> factory methods may return subclasses other than 74 * <code>DecimalFormat</code>. If you need to customize the format object, do 75 * something like this: 76 * 77 * <blockquote><pre> 78 * NumberFormat f = NumberFormat.getInstance(loc); 79 * if (f instanceof DecimalFormat) { 80 * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true); 81 * } 82 * </pre></blockquote> 83 * 84 * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of 85 * <em>symbols</em>. The pattern may be set directly using 86 * <code>applyPattern()</code>, or indirectly using the API methods. The 87 * symbols are stored in a <code>DecimalFormatSymbols</code> object. When using 88 * the <code>NumberFormat</code> factory methods, the pattern and symbols are 89 * read from localized <code>ResourceBundle</code>s. 90 * 91 * <h3>Patterns</h3> 92 * 93 * <code>DecimalFormat</code> patterns have the following syntax: 94 * <blockquote><pre> 95 * <i>Pattern:</i> 96 * <i>PositivePattern</i> 97 * <i>PositivePattern</i> ; <i>NegativePattern</i> 98 * <i>PositivePattern:</i> 99 * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i> 100 * <i>NegativePattern:</i> 101 * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i> 102 * <i>Prefix:</i> 103 * any Unicode characters except \uFFFE, \uFFFF, and special characters 104 * <i>Suffix:</i> 105 * any Unicode characters except \uFFFE, \uFFFF, and special characters 106 * <i>Number:</i> 107 * <i>Integer</i> <i>Exponent<sub>opt</sub></i> 108 * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i> 109 * <i>Integer:</i> 110 * <i>MinimumInteger</i> 111 * # 112 * # <i>Integer</i> 113 * # , <i>Integer</i> 114 * <i>MinimumInteger:</i> 115 * 0 116 * 0 <i>MinimumInteger</i> 117 * 0 , <i>MinimumInteger</i> 118 * <i>Fraction:</i> 119 * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i> 120 * <i>MinimumFraction:</i> 121 * 0 <i>MinimumFraction<sub>opt</sub></i> 122 * <i>OptionalFraction:</i> 123 * # <i>OptionalFraction<sub>opt</sub></i> 124 * <i>Exponent:</i> 125 * E <i>MinimumExponent</i> 126 * <i>MinimumExponent:</i> 127 * 0 <i>MinimumExponent<sub>opt</sub></i> 128 * </pre></blockquote> 129 * 130 * <p>A <code>DecimalFormat</code> pattern contains a positive and negative 131 * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>. Each 132 * subpattern has a prefix, numeric part, and suffix. The negative subpattern 133 * is optional; if absent, then the positive subpattern prefixed with the 134 * localized minus sign (<code>'-'</code> in most locales) is used as the 135 * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to 136 * <code>"0.00;-0.00"</code>. If there is an explicit negative subpattern, it 137 * serves only to specify the negative prefix and suffix; the number of digits, 138 * minimal digits, and other characteristics are all the same as the positive 139 * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely 140 * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>. 141 * 142 * <p>The prefixes, suffixes, and various symbols used for infinity, digits, 143 * thousands separators, decimal separators, etc. may be set to arbitrary 144 * values, and they will appear properly during formatting. However, care must 145 * be taken that the symbols and strings do not conflict, or parsing will be 146 * unreliable. For example, either the positive and negative prefixes or the 147 * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able 148 * to distinguish positive from negative values. (If they are identical, then 149 * <code>DecimalFormat</code> will behave as if no negative subpattern was 150 * specified.) Another example is that the decimal separator and thousands 151 * separator should be distinct characters, or parsing will be impossible. 152 * 153 * <p>The grouping separator is commonly used for thousands, but in some 154 * countries it separates ten-thousands. The grouping size is a constant number 155 * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for 156 * 1,0000,0000. If you supply a pattern with multiple grouping characters, the 157 * interval between the last one and the end of the integer is the one that is 158 * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> == 159 * <code>"##,####,####"</code>. 160 * 161 * <h4>Special Pattern Characters</h4> 162 * 163 * <p>Many characters in a pattern are taken literally; they are matched during 164 * parsing and output unchanged during formatting. Special characters, on the 165 * other hand, stand for other characters, strings, or classes of characters. 166 * They must be quoted, unless noted otherwise, if they are to appear in the 167 * prefix or suffix as literals. 168 * 169 * <p>The characters listed here are used in non-localized patterns. Localized 170 * patterns use the corresponding characters taken from this formatter's 171 * <code>DecimalFormatSymbols</code> object instead, and these characters lose 172 * their special status. Two exceptions are the currency sign and quote, which 173 * are not localized. 174 * 175 * <blockquote> 176 * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol, 177 * location, localized, and meaning."> 178 * <tr style="background-color: rgb(204, 204, 255);"> 179 * <th align=left>Symbol 180 * <th align=left>Location 181 * <th align=left>Localized? 182 * <th align=left>Meaning 183 * <tr valign=top> 184 * <td><code>0</code> 185 * <td>Number 186 * <td>Yes 187 * <td>Digit 188 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 189 * <td><code>#</code> 190 * <td>Number 191 * <td>Yes 192 * <td>Digit, zero shows as absent 193 * <tr valign=top> 194 * <td><code>.</code> 195 * <td>Number 196 * <td>Yes 197 * <td>Decimal separator or monetary decimal separator 198 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 199 * <td><code>-</code> 200 * <td>Number 201 * <td>Yes 202 * <td>Minus sign 203 * <tr valign=top> 204 * <td><code>,</code> 205 * <td>Number 206 * <td>Yes 207 * <td>Grouping separator 208 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 209 * <td><code>E</code> 210 * <td>Number 211 * <td>Yes 212 * <td>Separates mantissa and exponent in scientific notation. 213 * <em>Need not be quoted in prefix or suffix.</em> 214 * <tr valign=top> 215 * <td><code>;</code> 216 * <td>Subpattern boundary 217 * <td>Yes 218 * <td>Separates positive and negative subpatterns 219 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 220 * <td><code>%</code> 221 * <td>Prefix or suffix 222 * <td>Yes 223 * <td>Multiply by 100 and show as percentage 224 * <tr valign=top> 225 * <td><code>\u2030</code> 226 * <td>Prefix or suffix 227 * <td>Yes 228 * <td>Multiply by 1000 and show as per mille value 229 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 230 * <td><code>¤</code> (<code>\u00A4</code>) 231 * <td>Prefix or suffix 232 * <td>No 233 * <td>Currency sign, replaced by currency symbol. If 234 * doubled, replaced by international currency symbol. 235 * If present in a pattern, the monetary decimal separator 236 * is used instead of the decimal separator. 237 * <tr valign=top> 238 * <td><code>'</code> 239 * <td>Prefix or suffix 240 * <td>No 241 * <td>Used to quote special characters in a prefix or suffix, 242 * for example, <code>"'#'#"</code> formats 123 to 243 * <code>"#123"</code>. To create a single quote 244 * itself, use two in a row: <code>"# o''clock"</code>. 245 * </table> 246 * </blockquote> 247 * 248 * <h4>Scientific Notation</h4> 249 * 250 * <p>Numbers in scientific notation are expressed as the product of a mantissa 251 * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The 252 * mantissa is often in the range 1.0 ≤ x {@literal <} 10.0, but it need not 253 * be. 254 * <code>DecimalFormat</code> can be instructed to format and parse scientific 255 * notation <em>only via a pattern</em>; there is currently no factory method 256 * that creates a scientific notation format. In a pattern, the exponent 257 * character immediately followed by one or more digit characters indicates 258 * scientific notation. Example: <code>"0.###E0"</code> formats the number 259 * 1234 as <code>"1.234E3"</code>. 260 * 261 * <ul> 262 * <li>The number of digit characters after the exponent character gives the 263 * minimum exponent digit count. There is no maximum. Negative exponents are 264 * formatted using the localized minus sign, <em>not</em> the prefix and suffix 265 * from the pattern. This allows patterns such as <code>"0.###E0 m/s"</code>. 266 * 267 * <li>The minimum and maximum number of integer digits are interpreted 268 * together: 269 * 270 * <ul> 271 * <li>If the maximum number of integer digits is greater than their minimum number 272 * and greater than 1, it forces the exponent to be a multiple of the maximum 273 * number of integer digits, and the minimum number of integer digits to be 274 * interpreted as 1. The most common use of this is to generate 275 * <em>engineering notation</em>, in which the exponent is a multiple of three, 276 * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345 277 * formats to <code>"12.345E3"</code>, and 123456 formats to 278 * <code>"123.456E3"</code>. 279 * 280 * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the 281 * exponent. Example: 0.00123 formatted with <code>"00.###E0"</code> yields 282 * <code>"12.3E-4"</code>. 283 * </ul> 284 * 285 * <li>The number of significant digits in the mantissa is the sum of the 286 * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is 287 * unaffected by the maximum integer digits. For example, 12345 formatted with 288 * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set 289 * the significant digits count to zero. The number of significant digits 290 * does not affect parsing. 291 * 292 * <li>Exponential patterns may not contain grouping separators. 293 * </ul> 294 * 295 * <h4>Rounding</h4> 296 * 297 * <code>DecimalFormat</code> provides rounding modes defined in 298 * {@link java.math.RoundingMode} for formatting. By default, it uses 299 * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}. 300 * 301 * <h4>Digits</h4> 302 * 303 * For formatting, <code>DecimalFormat</code> uses the ten consecutive 304 * characters starting with the localized zero digit defined in the 305 * <code>DecimalFormatSymbols</code> object as digits. For parsing, these 306 * digits as well as all Unicode decimal digits, as defined by 307 * {@link Character#digit Character.digit}, are recognized. 308 * 309 * <h4>Special Values</h4> 310 * 311 * <p><code>NaN</code> is formatted as a string, which typically has a single character 312 * <code>\uFFFD</code>. This string is determined by the 313 * <code>DecimalFormatSymbols</code> object. This is the only value for which 314 * the prefixes and suffixes are not used. 315 * 316 * <p>Infinity is formatted as a string, which typically has a single character 317 * <code>\u221E</code>, with the positive or negative prefixes and suffixes 318 * applied. The infinity string is determined by the 319 * <code>DecimalFormatSymbols</code> object. 320 * 321 * <p>Negative zero (<code>"-0"</code>) parses to 322 * <ul> 323 * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is 324 * true, 325 * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false 326 * and <code>isParseIntegerOnly()</code> is true, 327 * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code> 328 * and <code>isParseIntegerOnly()</code> are false. 329 * </ul> 330 * 331 * <h4><a name="synchronization">Synchronization</a></h4> 332 * 333 * <p> 334 * Decimal formats are generally not synchronized. 335 * It is recommended to create separate format instances for each thread. 336 * If multiple threads access a format concurrently, it must be synchronized 337 * externally. 338 * 339 * <h4>Example</h4> 340 * 341 * <blockquote><pre>{@code 342 * <strong>// Print out a number using the localized number, integer, currency, 343 * // and percent format for each locale</strong> 344 * Locale[] locales = NumberFormat.getAvailableLocales(); 345 * double myNumber = -1234.56; 346 * NumberFormat form; 347 * for (int j = 0; j < 4; ++j) { 348 * System.out.println("FORMAT"); 349 * for (int i = 0; i < locales.length; ++i) { 350 * if (locales[i].getCountry().length() == 0) { 351 * continue; // Skip language-only locales 352 * } 353 * System.out.print(locales[i].getDisplayName()); 354 * switch (j) { 355 * case 0: 356 * form = NumberFormat.getInstance(locales[i]); break; 357 * case 1: 358 * form = NumberFormat.getIntegerInstance(locales[i]); break; 359 * case 2: 360 * form = NumberFormat.getCurrencyInstance(locales[i]); break; 361 * default: 362 * form = NumberFormat.getPercentInstance(locales[i]); break; 363 * } 364 * if (form instanceof DecimalFormat) { 365 * System.out.print(": " + ((DecimalFormat) form).toPattern()); 366 * } 367 * System.out.print(" -> " + form.format(myNumber)); 368 * try { 369 * System.out.println(" -> " + form.parse(form.format(myNumber))); 370 * } catch (ParseException e) {} 371 * } 372 * } 373 * }</pre></blockquote> 374 * 375 * @see <a href="https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a> 376 * @see NumberFormat 377 * @see DecimalFormatSymbols 378 * @see ParsePosition 379 * @author Mark Davis 380 * @author Alan Liu 381 */ 382public class DecimalFormat extends NumberFormat { 383 384 // Android-note: This class is heavily modified from upstream OpenJDK. 385 // Android's version delegates most of its work to android.icu.text.DecimalFormat. This is done 386 // to avoid code duplication and to stay compatible with earlier releases that used ICU4C/ICU4J 387 // to implement DecimalFormat. 388 389 // Android-added: ICU DecimalFormat to delegate to. 390 // TODO(b/68143370): switch back to ICU DecimalFormat once it can reproduce ICU 58 behavior. 391 private transient android.icu.text.DecimalFormat_ICU58_Android icuDecimalFormat; 392 393 /** 394 * Creates a DecimalFormat using the default pattern and symbols 395 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. 396 * This is a convenient way to obtain a 397 * DecimalFormat when internationalization is not the main concern. 398 * <p> 399 * To obtain standard formats for a given locale, use the factory methods 400 * on NumberFormat such as getNumberInstance. These factories will 401 * return the most appropriate sub-class of NumberFormat for a given 402 * locale. 403 * 404 * @see java.text.NumberFormat#getInstance 405 * @see java.text.NumberFormat#getNumberInstance 406 * @see java.text.NumberFormat#getCurrencyInstance 407 * @see java.text.NumberFormat#getPercentInstance 408 */ 409 public DecimalFormat() { 410 // Get the pattern for the default locale. 411 Locale def = Locale.getDefault(Locale.Category.FORMAT); 412 // BEGIN Android-changed: Use ICU LocaleData. Remove SPI LocaleProviderAdapter. 413 /* 414 LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class, def); 415 if (!(adapter instanceof ResourceBundleBasedAdapter)) { 416 adapter = LocaleProviderAdapter.getResourceBundleBased(); 417 } 418 String[] all = adapter.getLocaleResources(def).getNumberPatterns(); 419 */ 420 String pattern = LocaleData.get(def).numberPattern; 421 // END Android-changed: Use ICU LocaleData. Remove SPI LocaleProviderAdapter. 422 423 // Always applyPattern after the symbols are set 424 this.symbols = DecimalFormatSymbols.getInstance(def); 425 // Android-changed: use initPattern() instead of removed applyPattern(String, boolean). 426 // applyPattern(all[0], false); 427 initPattern(pattern); 428 } 429 430 431 /** 432 * Creates a DecimalFormat using the given pattern and the symbols 433 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. 434 * This is a convenient way to obtain a 435 * DecimalFormat when internationalization is not the main concern. 436 * <p> 437 * To obtain standard formats for a given locale, use the factory methods 438 * on NumberFormat such as getNumberInstance. These factories will 439 * return the most appropriate sub-class of NumberFormat for a given 440 * locale. 441 * 442 * @param pattern a non-localized pattern string. 443 * @exception NullPointerException if <code>pattern</code> is null 444 * @exception IllegalArgumentException if the given pattern is invalid. 445 * @see java.text.NumberFormat#getInstance 446 * @see java.text.NumberFormat#getNumberInstance 447 * @see java.text.NumberFormat#getCurrencyInstance 448 * @see java.text.NumberFormat#getPercentInstance 449 */ 450 public DecimalFormat(String pattern) { 451 // Always applyPattern after the symbols are set 452 this.symbols = DecimalFormatSymbols.getInstance(Locale.getDefault(Locale.Category.FORMAT)); 453 // Android-changed: use initPattern() instead of removed applyPattern(String, boolean). 454 initPattern(pattern); 455 } 456 457 458 /** 459 * Creates a DecimalFormat using the given pattern and symbols. 460 * Use this constructor when you need to completely customize the 461 * behavior of the format. 462 * <p> 463 * To obtain standard formats for a given 464 * locale, use the factory methods on NumberFormat such as 465 * getInstance or getCurrencyInstance. If you need only minor adjustments 466 * to a standard format, you can modify the format returned by 467 * a NumberFormat factory method. 468 * 469 * @param pattern a non-localized pattern string 470 * @param symbols the set of symbols to be used 471 * @exception NullPointerException if any of the given arguments is null 472 * @exception IllegalArgumentException if the given pattern is invalid 473 * @see java.text.NumberFormat#getInstance 474 * @see java.text.NumberFormat#getNumberInstance 475 * @see java.text.NumberFormat#getCurrencyInstance 476 * @see java.text.NumberFormat#getPercentInstance 477 * @see java.text.DecimalFormatSymbols 478 */ 479 public DecimalFormat (String pattern, DecimalFormatSymbols symbols) { 480 // Always applyPattern after the symbols are set 481 this.symbols = (DecimalFormatSymbols)symbols.clone(); 482 // Android-changed: use initPattern() instead of removed applyPattern(String, boolean). 483 initPattern(pattern); 484 } 485 486 // BEGIN Android-added: initPattern() and conversion methods between ICU and Java values. 487 /** 488 * Applies the pattern similarly to {@link #applyPattern(String)}, except it initializes 489 * {@link #icuDecimalFormat} in the process. This should only be called from constructors. 490 */ 491 private void initPattern(String pattern) { 492 this.icuDecimalFormat = new android.icu.text.DecimalFormat_ICU58_Android(pattern, 493 symbols.getIcuDecimalFormatSymbols()); 494 updateFieldsFromIcu(); 495 } 496 497 /** 498 * Update local fields indicating maximum/minimum integer/fraction digit count from the ICU 499 * DecimalFormat. This needs to be called whenever a new pattern is applied. 500 */ 501 private void updateFieldsFromIcu() { 502 // Imitate behaviour of ICU4C NumberFormat that Android used up to M. 503 // If the pattern doesn't enforce a different value (some exponential 504 // patterns do), then set the maximum integer digits to 2 billion. 505 if (icuDecimalFormat.getMaximumIntegerDigits() == DOUBLE_INTEGER_DIGITS) { 506 icuDecimalFormat.setMaximumIntegerDigits(2000000000); 507 } 508 maximumIntegerDigits = icuDecimalFormat.getMaximumIntegerDigits(); 509 minimumIntegerDigits = icuDecimalFormat.getMinimumIntegerDigits(); 510 maximumFractionDigits = icuDecimalFormat.getMaximumFractionDigits(); 511 minimumFractionDigits = icuDecimalFormat.getMinimumFractionDigits(); 512 } 513 514 /** 515 * Converts between field positions used by Java/ICU. 516 * @param fp The java.text.NumberFormat.Field field position 517 * @return The android.icu.text.NumberFormat.Field field position 518 */ 519 private static FieldPosition getIcuFieldPosition(FieldPosition fp) { 520 Format.Field fieldAttribute = fp.getFieldAttribute(); 521 if (fieldAttribute == null) return fp; 522 523 android.icu.text.NumberFormat.Field attribute; 524 if (fieldAttribute == Field.INTEGER) { 525 attribute = android.icu.text.NumberFormat.Field.INTEGER; 526 } else if (fieldAttribute == Field.FRACTION) { 527 attribute = android.icu.text.NumberFormat.Field.FRACTION; 528 } else if (fieldAttribute == Field.DECIMAL_SEPARATOR) { 529 attribute = android.icu.text.NumberFormat.Field.DECIMAL_SEPARATOR; 530 } else if (fieldAttribute == Field.EXPONENT_SYMBOL) { 531 attribute = android.icu.text.NumberFormat.Field.EXPONENT_SYMBOL; 532 } else if (fieldAttribute == Field.EXPONENT_SIGN) { 533 attribute = android.icu.text.NumberFormat.Field.EXPONENT_SIGN; 534 } else if (fieldAttribute == Field.EXPONENT) { 535 attribute = android.icu.text.NumberFormat.Field.EXPONENT; 536 } else if (fieldAttribute == Field.GROUPING_SEPARATOR) { 537 attribute = android.icu.text.NumberFormat.Field.GROUPING_SEPARATOR; 538 } else if (fieldAttribute == Field.CURRENCY) { 539 attribute = android.icu.text.NumberFormat.Field.CURRENCY; 540 } else if (fieldAttribute == Field.PERCENT) { 541 attribute = android.icu.text.NumberFormat.Field.PERCENT; 542 } else if (fieldAttribute == Field.PERMILLE) { 543 attribute = android.icu.text.NumberFormat.Field.PERMILLE; 544 } else if (fieldAttribute == Field.SIGN) { 545 attribute = android.icu.text.NumberFormat.Field.SIGN; 546 } else { 547 throw new IllegalArgumentException("Unexpected field position attribute type."); 548 } 549 550 FieldPosition icuFieldPosition = new FieldPosition(attribute); 551 icuFieldPosition.setBeginIndex(fp.getBeginIndex()); 552 icuFieldPosition.setEndIndex(fp.getEndIndex()); 553 return icuFieldPosition; 554 } 555 556 /** 557 * Converts the Attribute that ICU returns in its AttributedCharacterIterator 558 * responses to the type that java uses. 559 * @param icuAttribute The AttributedCharacterIterator.Attribute field. 560 * @return Field converted to a java.text.NumberFormat.Field field. 561 */ 562 private static Field toJavaFieldAttribute(AttributedCharacterIterator.Attribute icuAttribute) { 563 String name = icuAttribute.getName(); 564 if (name.equals(Field.INTEGER.getName())) { 565 return Field.INTEGER; 566 } 567 if (name.equals(Field.CURRENCY.getName())) { 568 return Field.CURRENCY; 569 } 570 if (name.equals(Field.DECIMAL_SEPARATOR.getName())) { 571 return Field.DECIMAL_SEPARATOR; 572 } 573 if (name.equals(Field.EXPONENT.getName())) { 574 return Field.EXPONENT; 575 } 576 if (name.equals(Field.EXPONENT_SIGN.getName())) { 577 return Field.EXPONENT_SIGN; 578 } 579 if (name.equals(Field.EXPONENT_SYMBOL.getName())) { 580 return Field.EXPONENT_SYMBOL; 581 } 582 if (name.equals(Field.FRACTION.getName())) { 583 return Field.FRACTION; 584 } 585 if (name.equals(Field.GROUPING_SEPARATOR.getName())) { 586 return Field.GROUPING_SEPARATOR; 587 } 588 if (name.equals(Field.SIGN.getName())) { 589 return Field.SIGN; 590 } 591 if (name.equals(Field.PERCENT.getName())) { 592 return Field.PERCENT; 593 } 594 if (name.equals(Field.PERMILLE.getName())) { 595 return Field.PERMILLE; 596 } 597 throw new IllegalArgumentException("Unrecognized attribute: " + name); 598 } 599 // END Android-added: initPattern() and conversion methods between ICU and Java values. 600 601 // Overrides 602 /** 603 * Formats a number and appends the resulting text to the given string 604 * buffer. 605 * The number can be of any subclass of {@link java.lang.Number}. 606 * <p> 607 * This implementation uses the maximum precision permitted. 608 * @param number the number to format 609 * @param toAppendTo the <code>StringBuffer</code> to which the formatted 610 * text is to be appended 611 * @param pos On input: an alignment field, if desired. 612 * On output: the offsets of the alignment field. 613 * @return the value passed in as <code>toAppendTo</code> 614 * @exception IllegalArgumentException if <code>number</code> is 615 * null or not an instance of <code>Number</code>. 616 * @exception NullPointerException if <code>toAppendTo</code> or 617 * <code>pos</code> is null 618 * @exception ArithmeticException if rounding is needed with rounding 619 * mode being set to RoundingMode.UNNECESSARY 620 * @see java.text.FieldPosition 621 */ 622 @Override 623 public final StringBuffer format(Object number, 624 StringBuffer toAppendTo, 625 FieldPosition pos) { 626 if (number instanceof Long || number instanceof Integer || 627 number instanceof Short || number instanceof Byte || 628 number instanceof AtomicInteger || 629 number instanceof AtomicLong || 630 (number instanceof BigInteger && 631 ((BigInteger)number).bitLength () < 64)) { 632 return format(((Number)number).longValue(), toAppendTo, pos); 633 } else if (number instanceof BigDecimal) { 634 return format((BigDecimal)number, toAppendTo, pos); 635 } else if (number instanceof BigInteger) { 636 return format((BigInteger)number, toAppendTo, pos); 637 } else if (number instanceof Number) { 638 return format(((Number)number).doubleValue(), toAppendTo, pos); 639 } else { 640 throw new IllegalArgumentException("Cannot format given Object as a Number"); 641 } 642 } 643 644 /** 645 * Formats a double to produce a string. 646 * @param number The double to format 647 * @param result where the text is to be appended 648 * @param fieldPosition On input: an alignment field, if desired. 649 * On output: the offsets of the alignment field. 650 * @exception ArithmeticException if rounding is needed with rounding 651 * mode being set to RoundingMode.UNNECESSARY 652 * @return The formatted number string 653 * @see java.text.FieldPosition 654 */ 655 @Override 656 public StringBuffer format(double number, StringBuffer result, 657 FieldPosition fieldPosition) { 658 // BEGIN Android-changed: Use ICU. 659 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 660 icuDecimalFormat.format(number, result, icuFieldPosition); 661 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 662 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 663 return result; 664 // END Android-changed: Use ICU. 665 } 666 667 // Android-removed: private StringBuffer format(double, StringBuffer, FieldDelegate). 668 669 /** 670 * Format a long to produce a string. 671 * @param number The long to format 672 * @param result where the text is to be appended 673 * @param fieldPosition On input: an alignment field, if desired. 674 * On output: the offsets of the alignment field. 675 * @exception ArithmeticException if rounding is needed with rounding 676 * mode being set to RoundingMode.UNNECESSARY 677 * @return The formatted number string 678 * @see java.text.FieldPosition 679 */ 680 @Override 681 public StringBuffer format(long number, StringBuffer result, 682 FieldPosition fieldPosition) { 683 // BEGIN Android-changed: Use ICU. 684 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 685 icuDecimalFormat.format(number, result, icuFieldPosition); 686 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 687 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 688 return result; 689 // END Android-changed: Use ICU. 690 } 691 692 // Android-removed: private StringBuffer format(long, StringBuffer, FieldDelegate). 693 694 /** 695 * Formats a BigDecimal to produce a string. 696 * @param number The BigDecimal to format 697 * @param result where the text is to be appended 698 * @param fieldPosition On input: an alignment field, if desired. 699 * On output: the offsets of the alignment field. 700 * @return The formatted number string 701 * @exception ArithmeticException if rounding is needed with rounding 702 * mode being set to RoundingMode.UNNECESSARY 703 * @see java.text.FieldPosition 704 */ 705 private StringBuffer format(BigDecimal number, StringBuffer result, 706 FieldPosition fieldPosition) { 707 // BEGIN Android-changed: Use ICU. 708 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 709 icuDecimalFormat.format(number, result, fieldPosition); 710 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 711 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 712 return result; 713 // END Android-changed: Use ICU. 714 } 715 716 // Android-removed: private StringBuffer format(BigDecimal, StringBuffer, FieldDelegate). 717 718 /** 719 * Format a BigInteger to produce a string. 720 * @param number The BigInteger to format 721 * @param result where the text is to be appended 722 * @param fieldPosition On input: an alignment field, if desired. 723 * On output: the offsets of the alignment field. 724 * @return The formatted number string 725 * @exception ArithmeticException if rounding is needed with rounding 726 * mode being set to RoundingMode.UNNECESSARY 727 * @see java.text.FieldPosition 728 */ 729 private StringBuffer format(BigInteger number, StringBuffer result, 730 FieldPosition fieldPosition) { 731 // BEGIN Android-changed: Use ICU. 732 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 733 icuDecimalFormat.format(number, result, fieldPosition); 734 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 735 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 736 return result; 737 // END Android-changed: Use ICU. 738 } 739 740 // Android-removed: private StringBuffer format(BigInteger, StringBuffer, FieldDelegate). 741 742 /** 743 * Formats an Object producing an <code>AttributedCharacterIterator</code>. 744 * You can use the returned <code>AttributedCharacterIterator</code> 745 * to build the resulting String, as well as to determine information 746 * about the resulting String. 747 * <p> 748 * Each attribute key of the AttributedCharacterIterator will be of type 749 * <code>NumberFormat.Field</code>, with the attribute value being the 750 * same as the attribute key. 751 * 752 * @exception NullPointerException if obj is null. 753 * @exception IllegalArgumentException when the Format cannot format the 754 * given object. 755 * @exception ArithmeticException if rounding is needed with rounding 756 * mode being set to RoundingMode.UNNECESSARY 757 * @param obj The object to format 758 * @return AttributedCharacterIterator describing the formatted value. 759 * @since 1.4 760 */ 761 @Override 762 public AttributedCharacterIterator formatToCharacterIterator(Object obj) { 763 // BEGIN Android-changed: Use ICU. 764 if (obj == null) { 765 throw new NullPointerException("object == null"); 766 } 767 // Note: formatToCharacterIterator cannot be used directly because it returns attributes 768 // in terms of its own class: icu.text.NumberFormat instead of java.text.NumberFormat. 769 // http://bugs.icu-project.org/trac/ticket/11931 Proposes to use the NumberFormat constants. 770 771 AttributedCharacterIterator original = icuDecimalFormat.formatToCharacterIterator(obj); 772 773 // Extract the text out of the ICU iterator. 774 StringBuilder textBuilder = new StringBuilder( 775 original.getEndIndex() - original.getBeginIndex()); 776 777 for (int i = original.getBeginIndex(); i < original.getEndIndex(); i++) { 778 textBuilder.append(original.current()); 779 original.next(); 780 } 781 782 AttributedString result = new AttributedString(textBuilder.toString()); 783 784 for (int i = original.getBeginIndex(); i < original.getEndIndex(); i++) { 785 original.setIndex(i); 786 787 for (AttributedCharacterIterator.Attribute attribute 788 : original.getAttributes().keySet()) { 789 int start = original.getRunStart(); 790 int end = original.getRunLimit(); 791 Field javaAttr = toJavaFieldAttribute(attribute); 792 result.addAttribute(javaAttr, javaAttr, start, end); 793 } 794 } 795 796 return result.getIterator(); 797 // END Android-changed: Use ICU. 798 } 799 800 // Android-removed: "fast-path formating logic for double" (sic). 801 802 // Android-removed: subformat(), append(). 803 804 /** 805 * Parses text from a string to produce a <code>Number</code>. 806 * <p> 807 * The method attempts to parse text starting at the index given by 808 * <code>pos</code>. 809 * If parsing succeeds, then the index of <code>pos</code> is updated 810 * to the index after the last character used (parsing does not necessarily 811 * use all characters up to the end of the string), and the parsed 812 * number is returned. The updated <code>pos</code> can be used to 813 * indicate the starting point for the next call to this method. 814 * If an error occurs, then the index of <code>pos</code> is not 815 * changed, the error index of <code>pos</code> is set to the index of 816 * the character where the error occurred, and null is returned. 817 * <p> 818 * The subclass returned depends on the value of {@link #isParseBigDecimal} 819 * as well as on the string being parsed. 820 * <ul> 821 * <li>If <code>isParseBigDecimal()</code> is false (the default), 822 * most integer values are returned as <code>Long</code> 823 * objects, no matter how they are written: <code>"17"</code> and 824 * <code>"17.000"</code> both parse to <code>Long(17)</code>. 825 * Values that cannot fit into a <code>Long</code> are returned as 826 * <code>Double</code>s. This includes values with a fractional part, 827 * infinite values, <code>NaN</code>, and the value -0.0. 828 * <code>DecimalFormat</code> does <em>not</em> decide whether to 829 * return a <code>Double</code> or a <code>Long</code> based on the 830 * presence of a decimal separator in the source string. Doing so 831 * would prevent integers that overflow the mantissa of a double, 832 * such as <code>"-9,223,372,036,854,775,808.00"</code>, from being 833 * parsed accurately. 834 * <p> 835 * Callers may use the <code>Number</code> methods 836 * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain 837 * the type they want. 838 * <li>If <code>isParseBigDecimal()</code> is true, values are returned 839 * as <code>BigDecimal</code> objects. The values are the ones 840 * constructed by {@link java.math.BigDecimal#BigDecimal(String)} 841 * for corresponding strings in locale-independent format. The 842 * special cases negative and positive infinity and NaN are returned 843 * as <code>Double</code> instances holding the values of the 844 * corresponding <code>Double</code> constants. 845 * </ul> 846 * <p> 847 * <code>DecimalFormat</code> parses all Unicode characters that represent 848 * decimal digits, as defined by <code>Character.digit()</code>. In 849 * addition, <code>DecimalFormat</code> also recognizes as digits the ten 850 * consecutive characters starting with the localized zero digit defined in 851 * the <code>DecimalFormatSymbols</code> object. 852 * 853 * @param text the string to be parsed 854 * @param pos A <code>ParsePosition</code> object with index and error 855 * index information as described above. 856 * @return the parsed value, or <code>null</code> if the parse fails 857 * @exception NullPointerException if <code>text</code> or 858 * <code>pos</code> is null. 859 */ 860 @Override 861 public Number parse(String text, ParsePosition pos) { 862 // BEGIN Android-changed: Use ICU. 863 // Return early if the parse position is bogus. 864 if (pos.index < 0 || pos.index >= text.length()) { 865 return null; 866 } 867 868 // This might return android.icu.math.BigDecimal, java.math.BigInteger or a primitive type. 869 Number number = icuDecimalFormat.parse(text, pos); 870 if (number == null) { 871 return null; 872 } 873 if (isParseBigDecimal()) { 874 if (number instanceof Long) { 875 return new BigDecimal(number.longValue()); 876 } 877 if ((number instanceof Double) && !((Double) number).isInfinite() 878 && !((Double) number).isNaN()) { 879 return new BigDecimal(number.toString()); 880 } 881 if ((number instanceof Double) && 882 (((Double) number).isNaN() || ((Double) number).isInfinite())) { 883 return number; 884 } 885 if (number instanceof android.icu.math.BigDecimal) { 886 return ((android.icu.math.BigDecimal) number).toBigDecimal(); 887 } 888 } 889 if ((number instanceof android.icu.math.BigDecimal) || (number instanceof BigInteger)) { 890 return number.doubleValue(); 891 } 892 if (isParseIntegerOnly() && number.equals(new Double(-0.0))) { 893 return 0L; 894 } 895 return number; 896 // END Android-changed: Use ICU. 897 } 898 899 // Android-removed: STATUS_* constants, multiplier fields and methods and subparse(String, ...). 900 901 /** 902 * Returns a copy of the decimal format symbols, which is generally not 903 * changed by the programmer or user. 904 * @return a copy of the desired DecimalFormatSymbols 905 * @see java.text.DecimalFormatSymbols 906 */ 907 public DecimalFormatSymbols getDecimalFormatSymbols() { 908 // Android-changed: Use ICU. 909 return DecimalFormatSymbols.fromIcuInstance(icuDecimalFormat.getDecimalFormatSymbols()); 910 } 911 912 913 /** 914 * Sets the decimal format symbols, which is generally not changed 915 * by the programmer or user. 916 * @param newSymbols desired DecimalFormatSymbols 917 * @see java.text.DecimalFormatSymbols 918 */ 919 public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) { 920 try { 921 // don't allow multiple references 922 symbols = (DecimalFormatSymbols) newSymbols.clone(); 923 // Android-changed: Use ICU. 924 icuDecimalFormat.setDecimalFormatSymbols(symbols.getIcuDecimalFormatSymbols()); 925 } catch (Exception foo) { 926 // should never happen 927 } 928 } 929 930 /** 931 * Get the positive prefix. 932 * <P>Examples: +123, $123, sFr123 933 * 934 * @return the positive prefix 935 */ 936 public String getPositivePrefix () { 937 // Android-changed: Use ICU. 938 return icuDecimalFormat.getPositivePrefix(); 939 } 940 941 /** 942 * Set the positive prefix. 943 * <P>Examples: +123, $123, sFr123 944 * 945 * @param newValue the new positive prefix 946 */ 947 public void setPositivePrefix (String newValue) { 948 // Android-changed: Use ICU. 949 icuDecimalFormat.setPositivePrefix(newValue); 950 } 951 952 // Android-removed: private helper getPositivePrefixFieldPositions(). 953 954 /** 955 * Get the prefix. 956 * <P>Examples: -123, ($123) (with negative suffix), sFr-123 957 * 958 * @return the negative prefix 959 */ 960 public String getNegativePrefix () { 961 // Android-changed: Use ICU. 962 return icuDecimalFormat.getNegativePrefix(); 963 } 964 965 /** 966 * Set the negative prefix. 967 * <P>Examples: -123, ($123) (with negative suffix), sFr-123 968 * 969 * @param newValue the new negative prefix 970 */ 971 public void setNegativePrefix (String newValue) { 972 // Android-changed: Use ICU. 973 icuDecimalFormat.setNegativePrefix(newValue); 974 } 975 976 // Android-removed: private helper getNegativePrefixFieldPositions(). 977 978 /** 979 * Get the positive suffix. 980 * <P>Example: 123% 981 * 982 * @return the positive suffix 983 */ 984 public String getPositiveSuffix () { 985 // Android-changed: Use ICU. 986 return icuDecimalFormat.getPositiveSuffix(); 987 } 988 989 /** 990 * Set the positive suffix. 991 * <P>Example: 123% 992 * 993 * @param newValue the new positive suffix 994 */ 995 public void setPositiveSuffix (String newValue) { 996 // Android-changed: Use ICU. 997 icuDecimalFormat.setPositiveSuffix(newValue); 998 } 999 1000 // Android-removed: private helper getPositiveSuffixFieldPositions(). 1001 1002 /** 1003 * Get the negative suffix. 1004 * <P>Examples: -123%, ($123) (with positive suffixes) 1005 * 1006 * @return the negative suffix 1007 */ 1008 public String getNegativeSuffix () { 1009 // Android-changed: Use ICU. 1010 return icuDecimalFormat.getNegativeSuffix(); 1011 } 1012 1013 /** 1014 * Set the negative suffix. 1015 * <P>Examples: 123% 1016 * 1017 * @param newValue the new negative suffix 1018 */ 1019 public void setNegativeSuffix (String newValue) { 1020 // Android-changed: Use ICU. 1021 icuDecimalFormat.setNegativeSuffix(newValue); 1022 } 1023 1024 // Android-removed: private helper getNegativeSuffixFieldPositions(). 1025 1026 /** 1027 * Gets the multiplier for use in percent, per mille, and similar 1028 * formats. 1029 * 1030 * @return the multiplier 1031 * @see #setMultiplier(int) 1032 */ 1033 public int getMultiplier () { 1034 // Android-changed: Use ICU. 1035 return icuDecimalFormat.getMultiplier(); 1036 } 1037 1038 /** 1039 * Sets the multiplier for use in percent, per mille, and similar 1040 * formats. 1041 * For a percent format, set the multiplier to 100 and the suffixes to 1042 * have '%' (for Arabic, use the Arabic percent sign). 1043 * For a per mille format, set the multiplier to 1000 and the suffixes to 1044 * have '\u2030'. 1045 * 1046 * <P>Example: with multiplier 100, 1.23 is formatted as "123", and 1047 * "123" is parsed into 1.23. 1048 * 1049 * @param newValue the new multiplier 1050 * @see #getMultiplier 1051 */ 1052 public void setMultiplier (int newValue) { 1053 icuDecimalFormat.setMultiplier(newValue); 1054 } 1055 1056 /** 1057 * {@inheritDoc} 1058 */ 1059 @Override 1060 public void setGroupingUsed(boolean newValue) { 1061 // Android-changed: Use ICU. 1062 icuDecimalFormat.setGroupingUsed(newValue); 1063 // Android-removed: fast path related code. 1064 // fastPathCheckNeeded = true; 1065 } 1066 1067 // BEGIN Android-added: isGroupingUsed() override delegating to ICU. 1068 /** 1069 * {@inheritDoc} 1070 */ 1071 @Override 1072 public boolean isGroupingUsed() { 1073 return icuDecimalFormat.isGroupingUsed(); 1074 } 1075 // END Android-added: isGroupingUsed() override delegating to ICU. 1076 1077 /** 1078 * Return the grouping size. Grouping size is the number of digits between 1079 * grouping separators in the integer portion of a number. For example, 1080 * in the number "123,456.78", the grouping size is 3. 1081 * 1082 * @return the grouping size 1083 * @see #setGroupingSize 1084 * @see java.text.NumberFormat#isGroupingUsed 1085 * @see java.text.DecimalFormatSymbols#getGroupingSeparator 1086 */ 1087 public int getGroupingSize () { 1088 // Android-changed: Use ICU. 1089 return icuDecimalFormat.getGroupingSize(); 1090 } 1091 1092 /** 1093 * Set the grouping size. Grouping size is the number of digits between 1094 * grouping separators in the integer portion of a number. For example, 1095 * in the number "123,456.78", the grouping size is 3. 1096 * <br> 1097 * The value passed in is converted to a byte, which may lose information. 1098 * 1099 * @param newValue the new grouping size 1100 * @see #getGroupingSize 1101 * @see java.text.NumberFormat#setGroupingUsed 1102 * @see java.text.DecimalFormatSymbols#setGroupingSeparator 1103 */ 1104 public void setGroupingSize (int newValue) { 1105 // Android-changed: Use ICU. 1106 icuDecimalFormat.setGroupingSize(newValue); 1107 // Android-removed: fast path related code. 1108 // fastPathCheckNeeded = true; 1109 } 1110 1111 /** 1112 * Allows you to get the behavior of the decimal separator with integers. 1113 * (The decimal separator will always appear with decimals.) 1114 * <P>Example: Decimal ON: 12345 → 12345.; OFF: 12345 → 12345 1115 * 1116 * @return {@code true} if the decimal separator is always shown; 1117 * {@code false} otherwise 1118 */ 1119 public boolean isDecimalSeparatorAlwaysShown() { 1120 // Android-changed: Use ICU. 1121 return icuDecimalFormat.isDecimalSeparatorAlwaysShown(); 1122 } 1123 1124 /** 1125 * Allows you to set the behavior of the decimal separator with integers. 1126 * (The decimal separator will always appear with decimals.) 1127 * <P>Example: Decimal ON: 12345 → 12345.; OFF: 12345 → 12345 1128 * 1129 * @param newValue {@code true} if the decimal separator is always shown; 1130 * {@code false} otherwise 1131 */ 1132 public void setDecimalSeparatorAlwaysShown(boolean newValue) { 1133 // Android-changed: Use ICU. 1134 icuDecimalFormat.setDecimalSeparatorAlwaysShown(newValue); 1135 } 1136 1137 /** 1138 * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)} 1139 * method returns <code>BigDecimal</code>. The default value is false. 1140 * 1141 * @return {@code true} if the parse method returns BigDecimal; 1142 * {@code false} otherwise 1143 * @see #setParseBigDecimal 1144 * @since 1.5 1145 */ 1146 public boolean isParseBigDecimal() { 1147 // Android-changed: Use ICU. 1148 return icuDecimalFormat.isParseBigDecimal(); 1149 } 1150 1151 /** 1152 * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)} 1153 * method returns <code>BigDecimal</code>. 1154 * 1155 * @param newValue {@code true} if the parse method returns BigDecimal; 1156 * {@code false} otherwise 1157 * @see #isParseBigDecimal 1158 * @since 1.5 1159 */ 1160 public void setParseBigDecimal(boolean newValue) { 1161 // Android-changed: Use ICU. 1162 icuDecimalFormat.setParseBigDecimal(newValue); 1163 } 1164 1165 // BEGIN Android-added: setParseIntegerOnly()/isParseIntegerOnly() overrides delegating to ICU. 1166 /** 1167 * {@inheritDoc} 1168 */ 1169 @Override 1170 public boolean isParseIntegerOnly() { 1171 return icuDecimalFormat.isParseIntegerOnly(); 1172 } 1173 1174 /** 1175 * {@inheritDoc} 1176 */ 1177 @Override 1178 public void setParseIntegerOnly(boolean value) { 1179 super.setParseIntegerOnly(value); 1180 icuDecimalFormat.setParseIntegerOnly(value); 1181 } 1182 // END Android-added: setParseIntegerOnly()/isParseIntegerOnly() overrides delegating to ICU. 1183 1184 /** 1185 * Standard override; no change in semantics. 1186 */ 1187 @Override 1188 public Object clone() { 1189 // BEGIN Android-changed: Use ICU, remove fast path related code. 1190 try { 1191 DecimalFormat other = (DecimalFormat) super.clone(); 1192 other.icuDecimalFormat = (android.icu.text.DecimalFormat_ICU58_Android) icuDecimalFormat.clone(); 1193 other.symbols = (DecimalFormatSymbols) symbols.clone(); 1194 return other; 1195 } catch (Exception e) { 1196 throw new InternalError(); 1197 } 1198 // END Android-changed: Use ICU, remove fast path related code. 1199 } 1200 1201 // BEGIN Android-changed: re-implement equals() using ICU fields. 1202 /** 1203 * Overrides equals 1204 */ 1205 @Override 1206 public boolean equals(Object obj) 1207 { 1208 if (obj == null) { 1209 return false; 1210 } 1211 if (this == obj) { 1212 return true; 1213 } 1214 if (!(obj instanceof DecimalFormat)) { 1215 return false; 1216 } 1217 DecimalFormat other = (DecimalFormat) obj; 1218 return icuDecimalFormat.equals(other.icuDecimalFormat) 1219 && compareIcuRoundingIncrement(other.icuDecimalFormat); 1220 } 1221 1222 private boolean compareIcuRoundingIncrement(android.icu.text.DecimalFormat_ICU58_Android other) { 1223 BigDecimal increment = this.icuDecimalFormat.getRoundingIncrement(); 1224 if (increment != null) { 1225 return (other.getRoundingIncrement() != null) 1226 && increment.equals(other.getRoundingIncrement()); 1227 } 1228 return other.getRoundingIncrement() == null; 1229 } 1230 // END Android-changed: re-implement equals() using ICU fields. 1231 1232 /** 1233 * Overrides hashCode 1234 */ 1235 @Override 1236 public int hashCode() { 1237 // Android-changed: use getPositivePrefix() instead of positivePrefix field. 1238 return super.hashCode() * 37 + getPositivePrefix().hashCode(); 1239 // just enough fields for a reasonable distribution 1240 } 1241 1242 /** 1243 * Synthesizes a pattern string that represents the current state 1244 * of this Format object. 1245 * 1246 * @return a pattern string 1247 * @see #applyPattern 1248 */ 1249 public String toPattern() { 1250 // Android-changed: use ICU. 1251 return icuDecimalFormat.toPattern(); 1252 } 1253 1254 /** 1255 * Synthesizes a localized pattern string that represents the current 1256 * state of this Format object. 1257 * 1258 * @return a localized pattern string 1259 * @see #applyPattern 1260 */ 1261 public String toLocalizedPattern() { 1262 // Android-changed: use ICU. 1263 return icuDecimalFormat.toLocalizedPattern(); 1264 } 1265 1266 // Android-removed: private helper methods expandAffixes(), expandAffix(), toPattern(boolean). 1267 1268 /** 1269 * Apply the given pattern to this Format object. A pattern is a 1270 * short-hand specification for the various formatting properties. 1271 * These properties can also be changed individually through the 1272 * various setter methods. 1273 * <p> 1274 * There is no limit to integer digits set 1275 * by this routine, since that is the typical end-user desire; 1276 * use setMaximumInteger if you want to set a real value. 1277 * For negative numbers, use a second pattern, separated by a semicolon 1278 * <P>Example <code>"#,#00.0#"</code> → 1,234.56 1279 * <P>This means a minimum of 2 integer digits, 1 fraction digit, and 1280 * a maximum of 2 fraction digits. 1281 * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in 1282 * parentheses. 1283 * <p>In negative patterns, the minimum and maximum counts are ignored; 1284 * these are presumed to be set in the positive pattern. 1285 * 1286 * @param pattern a new pattern 1287 * @exception NullPointerException if <code>pattern</code> is null 1288 * @exception IllegalArgumentException if the given pattern is invalid. 1289 */ 1290 public void applyPattern(String pattern) { 1291 // Android-changed: use ICU. 1292 icuDecimalFormat.applyPattern(pattern); 1293 updateFieldsFromIcu(); 1294 } 1295 1296 /** 1297 * Apply the given pattern to this Format object. The pattern 1298 * is assumed to be in a localized notation. A pattern is a 1299 * short-hand specification for the various formatting properties. 1300 * These properties can also be changed individually through the 1301 * various setter methods. 1302 * <p> 1303 * There is no limit to integer digits set 1304 * by this routine, since that is the typical end-user desire; 1305 * use setMaximumInteger if you want to set a real value. 1306 * For negative numbers, use a second pattern, separated by a semicolon 1307 * <P>Example <code>"#,#00.0#"</code> → 1,234.56 1308 * <P>This means a minimum of 2 integer digits, 1 fraction digit, and 1309 * a maximum of 2 fraction digits. 1310 * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in 1311 * parentheses. 1312 * <p>In negative patterns, the minimum and maximum counts are ignored; 1313 * these are presumed to be set in the positive pattern. 1314 * 1315 * @param pattern a new pattern 1316 * @exception NullPointerException if <code>pattern</code> is null 1317 * @exception IllegalArgumentException if the given pattern is invalid. 1318 */ 1319 public void applyLocalizedPattern(String pattern) { 1320 // Android-changed: use ICU. 1321 icuDecimalFormat.applyLocalizedPattern(pattern); 1322 updateFieldsFromIcu(); 1323 } 1324 1325 // Android-removed: applyPattern(String, boolean) as apply[Localized]Pattern calls ICU directly. 1326 1327 /** 1328 * Sets the maximum number of digits allowed in the integer portion of a 1329 * number. 1330 * For formatting numbers other than <code>BigInteger</code> and 1331 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 1332 * 309 is used. Negative input values are replaced with 0. 1333 * @see NumberFormat#setMaximumIntegerDigits 1334 */ 1335 @Override 1336 public void setMaximumIntegerDigits(int newValue) { 1337 maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); 1338 super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 1339 DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); 1340 if (minimumIntegerDigits > maximumIntegerDigits) { 1341 minimumIntegerDigits = maximumIntegerDigits; 1342 super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 1343 DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); 1344 } 1345 // Android-changed: use ICU. 1346 icuDecimalFormat.setMaximumIntegerDigits(getMaximumIntegerDigits()); 1347 // Android-removed: fast path related code. 1348 // fastPathCheckNeeded = true; 1349 } 1350 1351 /** 1352 * Sets the minimum number of digits allowed in the integer portion of a 1353 * number. 1354 * For formatting numbers other than <code>BigInteger</code> and 1355 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 1356 * 309 is used. Negative input values are replaced with 0. 1357 * @see NumberFormat#setMinimumIntegerDigits 1358 */ 1359 @Override 1360 public void setMinimumIntegerDigits(int newValue) { 1361 minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); 1362 super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 1363 DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); 1364 if (minimumIntegerDigits > maximumIntegerDigits) { 1365 maximumIntegerDigits = minimumIntegerDigits; 1366 super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 1367 DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); 1368 } 1369 // Android-changed: use ICU. 1370 icuDecimalFormat.setMinimumIntegerDigits(getMinimumIntegerDigits()); 1371 // Android-removed: fast path related code. 1372 // fastPathCheckNeeded = true; 1373 } 1374 1375 /** 1376 * Sets the maximum number of digits allowed in the fraction portion of a 1377 * number. 1378 * For formatting numbers other than <code>BigInteger</code> and 1379 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 1380 * 340 is used. Negative input values are replaced with 0. 1381 * @see NumberFormat#setMaximumFractionDigits 1382 */ 1383 @Override 1384 public void setMaximumFractionDigits(int newValue) { 1385 maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); 1386 super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 1387 DOUBLE_FRACTION_DIGITS : maximumFractionDigits); 1388 if (minimumFractionDigits > maximumFractionDigits) { 1389 minimumFractionDigits = maximumFractionDigits; 1390 super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 1391 DOUBLE_FRACTION_DIGITS : minimumFractionDigits); 1392 } 1393 // Android-changed: use ICU. 1394 icuDecimalFormat.setMaximumFractionDigits(getMaximumFractionDigits()); 1395 // Android-removed: fast path related code. 1396 // fastPathCheckNeeded = true; 1397 } 1398 1399 /** 1400 * Sets the minimum number of digits allowed in the fraction portion of a 1401 * number. 1402 * For formatting numbers other than <code>BigInteger</code> and 1403 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 1404 * 340 is used. Negative input values are replaced with 0. 1405 * @see NumberFormat#setMinimumFractionDigits 1406 */ 1407 @Override 1408 public void setMinimumFractionDigits(int newValue) { 1409 minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); 1410 super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 1411 DOUBLE_FRACTION_DIGITS : minimumFractionDigits); 1412 if (minimumFractionDigits > maximumFractionDigits) { 1413 maximumFractionDigits = minimumFractionDigits; 1414 super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 1415 DOUBLE_FRACTION_DIGITS : maximumFractionDigits); 1416 } 1417 // Android-changed: use ICU. 1418 icuDecimalFormat.setMinimumFractionDigits(getMinimumFractionDigits()); 1419 // Android-removed: fast path related code. 1420 // fastPathCheckNeeded = true; 1421 } 1422 1423 /** 1424 * Gets the maximum number of digits allowed in the integer portion of a 1425 * number. 1426 * For formatting numbers other than <code>BigInteger</code> and 1427 * <code>BigDecimal</code> objects, the lower of the return value and 1428 * 309 is used. 1429 * @see #setMaximumIntegerDigits 1430 */ 1431 @Override 1432 public int getMaximumIntegerDigits() { 1433 return maximumIntegerDigits; 1434 } 1435 1436 /** 1437 * Gets the minimum number of digits allowed in the integer portion of a 1438 * number. 1439 * For formatting numbers other than <code>BigInteger</code> and 1440 * <code>BigDecimal</code> objects, the lower of the return value and 1441 * 309 is used. 1442 * @see #setMinimumIntegerDigits 1443 */ 1444 @Override 1445 public int getMinimumIntegerDigits() { 1446 return minimumIntegerDigits; 1447 } 1448 1449 /** 1450 * Gets the maximum number of digits allowed in the fraction portion of a 1451 * number. 1452 * For formatting numbers other than <code>BigInteger</code> and 1453 * <code>BigDecimal</code> objects, the lower of the return value and 1454 * 340 is used. 1455 * @see #setMaximumFractionDigits 1456 */ 1457 @Override 1458 public int getMaximumFractionDigits() { 1459 return maximumFractionDigits; 1460 } 1461 1462 /** 1463 * Gets the minimum number of digits allowed in the fraction portion of a 1464 * number. 1465 * For formatting numbers other than <code>BigInteger</code> and 1466 * <code>BigDecimal</code> objects, the lower of the return value and 1467 * 340 is used. 1468 * @see #setMinimumFractionDigits 1469 */ 1470 @Override 1471 public int getMinimumFractionDigits() { 1472 return minimumFractionDigits; 1473 } 1474 1475 /** 1476 * Gets the currency used by this decimal format when formatting 1477 * currency values. 1478 * The currency is obtained by calling 1479 * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency} 1480 * on this number format's symbols. 1481 * 1482 * @return the currency used by this decimal format, or <code>null</code> 1483 * @since 1.4 1484 */ 1485 @Override 1486 public Currency getCurrency() { 1487 return symbols.getCurrency(); 1488 } 1489 1490 /** 1491 * Sets the currency used by this number format when formatting 1492 * currency values. This does not update the minimum or maximum 1493 * number of fraction digits used by the number format. 1494 * The currency is set by calling 1495 * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency} 1496 * on this number format's symbols. 1497 * 1498 * @param currency the new currency to be used by this decimal format 1499 * @exception NullPointerException if <code>currency</code> is null 1500 * @since 1.4 1501 */ 1502 @Override 1503 public void setCurrency(Currency currency) { 1504 // BEGIN Android-changed: use ICU. 1505 // Set the international currency symbol, and currency symbol on the DecimalFormatSymbols 1506 // object and tell ICU to use that. 1507 if (currency != symbols.getCurrency() 1508 || !currency.getSymbol().equals(symbols.getCurrencySymbol())) { 1509 symbols.setCurrency(currency); 1510 icuDecimalFormat.setDecimalFormatSymbols(symbols.getIcuDecimalFormatSymbols()); 1511 // Giving the icuDecimalFormat a new currency will cause the fractional digits to be 1512 // updated. This class is specified to not touch the fraction digits, so we re-set them. 1513 icuDecimalFormat.setMinimumFractionDigits(minimumFractionDigits); 1514 icuDecimalFormat.setMaximumFractionDigits(maximumFractionDigits); 1515 } 1516 // END Android-changed: use ICU. 1517 // Android-removed: fast path related code. 1518 // fastPathCheckNeeded = true; 1519 } 1520 1521 /** 1522 * Gets the {@link java.math.RoundingMode} used in this DecimalFormat. 1523 * 1524 * @return The <code>RoundingMode</code> used for this DecimalFormat. 1525 * @see #setRoundingMode(RoundingMode) 1526 * @since 1.6 1527 */ 1528 @Override 1529 public RoundingMode getRoundingMode() { 1530 return roundingMode; 1531 } 1532 1533 // Android-added: convertRoundingMode() to convert between Java and ICU RoundingMode enums. 1534 private static int convertRoundingMode(RoundingMode rm) { 1535 switch (rm) { 1536 case UP: 1537 return MathContext.ROUND_UP; 1538 case DOWN: 1539 return MathContext.ROUND_DOWN; 1540 case CEILING: 1541 return MathContext.ROUND_CEILING; 1542 case FLOOR: 1543 return MathContext.ROUND_FLOOR; 1544 case HALF_UP: 1545 return MathContext.ROUND_HALF_UP; 1546 case HALF_DOWN: 1547 return MathContext.ROUND_HALF_DOWN; 1548 case HALF_EVEN: 1549 return MathContext.ROUND_HALF_EVEN; 1550 case UNNECESSARY: 1551 return MathContext.ROUND_UNNECESSARY; 1552 } 1553 throw new IllegalArgumentException("Invalid rounding mode specified"); 1554 } 1555 1556 /** 1557 * Sets the {@link java.math.RoundingMode} used in this DecimalFormat. 1558 * 1559 * @param roundingMode The <code>RoundingMode</code> to be used 1560 * @see #getRoundingMode() 1561 * @exception NullPointerException if <code>roundingMode</code> is null. 1562 * @since 1.6 1563 */ 1564 @Override 1565 public void setRoundingMode(RoundingMode roundingMode) { 1566 if (roundingMode == null) { 1567 throw new NullPointerException(); 1568 } 1569 1570 this.roundingMode = roundingMode; 1571 // Android-changed: use ICU. 1572 icuDecimalFormat.setRoundingMode(convertRoundingMode(roundingMode)); 1573 // Android-removed: fast path related code. 1574 // fastPathCheckNeeded = true; 1575 } 1576 1577 // BEGIN Android-added: 7u40 version of adjustForCurrencyDefaultFractionDigits(). 1578 // This method was removed in OpenJDK 8 in favor of doing equivalent work in the provider. Since 1579 // Android removed support for providers for NumberFormat we keep this method around as an 1580 // "Android addition". 1581 /** 1582 * Adjusts the minimum and maximum fraction digits to values that 1583 * are reasonable for the currency's default fraction digits. 1584 */ 1585 void adjustForCurrencyDefaultFractionDigits() { 1586 Currency currency = symbols.getCurrency(); 1587 if (currency == null) { 1588 try { 1589 currency = Currency.getInstance(symbols.getInternationalCurrencySymbol()); 1590 } catch (IllegalArgumentException e) { 1591 } 1592 } 1593 if (currency != null) { 1594 int digits = currency.getDefaultFractionDigits(); 1595 if (digits != -1) { 1596 int oldMinDigits = getMinimumFractionDigits(); 1597 // Common patterns are "#.##", "#.00", "#". 1598 // Try to adjust all of them in a reasonable way. 1599 if (oldMinDigits == getMaximumFractionDigits()) { 1600 setMinimumFractionDigits(digits); 1601 setMaximumFractionDigits(digits); 1602 } else { 1603 setMinimumFractionDigits(Math.min(digits, oldMinDigits)); 1604 setMaximumFractionDigits(digits); 1605 } 1606 } 1607 } 1608 } 1609 // END Android-added: Upstream code from earlier OpenJDK release. 1610 1611 // BEGIN Android-added: Custom serialization code for compatibility with RI serialization. 1612 // the fields list to be serialized 1613 private static final ObjectStreamField[] serialPersistentFields = { 1614 new ObjectStreamField("positivePrefix", String.class), 1615 new ObjectStreamField("positiveSuffix", String.class), 1616 new ObjectStreamField("negativePrefix", String.class), 1617 new ObjectStreamField("negativeSuffix", String.class), 1618 new ObjectStreamField("posPrefixPattern", String.class), 1619 new ObjectStreamField("posSuffixPattern", String.class), 1620 new ObjectStreamField("negPrefixPattern", String.class), 1621 new ObjectStreamField("negSuffixPattern", String.class), 1622 new ObjectStreamField("multiplier", int.class), 1623 new ObjectStreamField("groupingSize", byte.class), 1624 new ObjectStreamField("groupingUsed", boolean.class), 1625 new ObjectStreamField("decimalSeparatorAlwaysShown", boolean.class), 1626 new ObjectStreamField("parseBigDecimal", boolean.class), 1627 new ObjectStreamField("roundingMode", RoundingMode.class), 1628 new ObjectStreamField("symbols", DecimalFormatSymbols.class), 1629 new ObjectStreamField("useExponentialNotation", boolean.class), 1630 new ObjectStreamField("minExponentDigits", byte.class), 1631 new ObjectStreamField("maximumIntegerDigits", int.class), 1632 new ObjectStreamField("minimumIntegerDigits", int.class), 1633 new ObjectStreamField("maximumFractionDigits", int.class), 1634 new ObjectStreamField("minimumFractionDigits", int.class), 1635 new ObjectStreamField("serialVersionOnStream", int.class), 1636 }; 1637 1638 private void writeObject(ObjectOutputStream stream) throws IOException, ClassNotFoundException { 1639 ObjectOutputStream.PutField fields = stream.putFields(); 1640 fields.put("positivePrefix", icuDecimalFormat.getPositivePrefix()); 1641 fields.put("positiveSuffix", icuDecimalFormat.getPositiveSuffix()); 1642 fields.put("negativePrefix", icuDecimalFormat.getNegativePrefix()); 1643 fields.put("negativeSuffix", icuDecimalFormat.getNegativeSuffix()); 1644 fields.put("posPrefixPattern", (String) null); 1645 fields.put("posSuffixPattern", (String) null); 1646 fields.put("negPrefixPattern", (String) null); 1647 fields.put("negSuffixPattern", (String) null); 1648 fields.put("multiplier", icuDecimalFormat.getMultiplier()); 1649 fields.put("groupingSize", (byte) icuDecimalFormat.getGroupingSize()); 1650 fields.put("groupingUsed", icuDecimalFormat.isGroupingUsed()); 1651 fields.put("decimalSeparatorAlwaysShown", icuDecimalFormat.isDecimalSeparatorAlwaysShown()); 1652 fields.put("parseBigDecimal", icuDecimalFormat.isParseBigDecimal()); 1653 fields.put("roundingMode", roundingMode); 1654 fields.put("symbols", symbols); 1655 fields.put("useExponentialNotation", false); 1656 fields.put("minExponentDigits", (byte) 0); 1657 fields.put("maximumIntegerDigits", icuDecimalFormat.getMaximumIntegerDigits()); 1658 fields.put("minimumIntegerDigits", icuDecimalFormat.getMinimumIntegerDigits()); 1659 fields.put("maximumFractionDigits", icuDecimalFormat.getMaximumFractionDigits()); 1660 fields.put("minimumFractionDigits", icuDecimalFormat.getMinimumFractionDigits()); 1661 fields.put("serialVersionOnStream", currentSerialVersion); 1662 stream.writeFields(); 1663 } 1664 // BEGIN Android-added: Custom serialization code for compatibility with RI serialization. 1665 1666 /** 1667 * Reads the default serializable fields from the stream and performs 1668 * validations and adjustments for older serialized versions. The 1669 * validations and adjustments are: 1670 * <ol> 1671 * <li> 1672 * Verify that the superclass's digit count fields correctly reflect 1673 * the limits imposed on formatting numbers other than 1674 * <code>BigInteger</code> and <code>BigDecimal</code> objects. These 1675 * limits are stored in the superclass for serialization compatibility 1676 * with older versions, while the limits for <code>BigInteger</code> and 1677 * <code>BigDecimal</code> objects are kept in this class. 1678 * If, in the superclass, the minimum or maximum integer digit count is 1679 * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or 1680 * maximum fraction digit count is larger than 1681 * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid 1682 * and this method throws an <code>InvalidObjectException</code>. 1683 * <li> 1684 * If <code>serialVersionOnStream</code> is less than 4, initialize 1685 * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN 1686 * RoundingMode.HALF_EVEN}. This field is new with version 4. 1687 * <li> 1688 * If <code>serialVersionOnStream</code> is less than 3, then call 1689 * the setters for the minimum and maximum integer and fraction digits with 1690 * the values of the corresponding superclass getters to initialize the 1691 * fields in this class. The fields in this class are new with version 3. 1692 * <li> 1693 * If <code>serialVersionOnStream</code> is less than 1, indicating that 1694 * the stream was written by JDK 1.1, initialize 1695 * <code>useExponentialNotation</code> 1696 * to false, since it was not present in JDK 1.1. 1697 * <li> 1698 * Set <code>serialVersionOnStream</code> to the maximum allowed value so 1699 * that default serialization will work properly if this object is streamed 1700 * out again. 1701 * </ol> 1702 * 1703 * <p>Stream versions older than 2 will not have the affix pattern variables 1704 * <code>posPrefixPattern</code> etc. As a result, they will be initialized 1705 * to <code>null</code>, which means the affix strings will be taken as 1706 * literal values. This is exactly what we want, since that corresponds to 1707 * the pre-version-2 behavior. 1708 */ 1709 // BEGIN Android-added: Custom serialization code for compatibility with RI serialization. 1710 private void readObject(ObjectInputStream stream) 1711 throws IOException, ClassNotFoundException { 1712 ObjectInputStream.GetField fields = stream.readFields(); 1713 this.symbols = (DecimalFormatSymbols) fields.get("symbols", null); 1714 1715 initPattern("#"); 1716 1717 // Calling a setter method on an ICU DecimalFormat object will change the object's internal 1718 // state, even if the value set is the same as the default value (ICU Ticket #13266). 1719 // 1720 // In an attempt to create objects that are equals() to the ones that were serialized, it's 1721 // therefore assumed here that any values that are the same as the default values were the 1722 // default values (ie. no setter was called to explicitly set that value). 1723 1724 String positivePrefix = (String) fields.get("positivePrefix", ""); 1725 if (!Objects.equals(positivePrefix, icuDecimalFormat.getPositivePrefix())) { 1726 icuDecimalFormat.setPositivePrefix(positivePrefix); 1727 } 1728 1729 String positiveSuffix = (String) fields.get("positiveSuffix", ""); 1730 if (!Objects.equals(positiveSuffix, icuDecimalFormat.getPositiveSuffix())) { 1731 icuDecimalFormat.setPositiveSuffix(positiveSuffix); 1732 } 1733 1734 String negativePrefix = (String) fields.get("negativePrefix", "-"); 1735 if (!Objects.equals(negativePrefix, icuDecimalFormat.getNegativePrefix())) { 1736 icuDecimalFormat.setNegativePrefix(negativePrefix); 1737 } 1738 1739 String negativeSuffix = (String) fields.get("negativeSuffix", ""); 1740 if (!Objects.equals(negativeSuffix, icuDecimalFormat.getNegativeSuffix())) { 1741 icuDecimalFormat.setNegativeSuffix(negativeSuffix); 1742 } 1743 1744 int multiplier = fields.get("multiplier", 1); 1745 if (multiplier != icuDecimalFormat.getMultiplier()) { 1746 icuDecimalFormat.setMultiplier(multiplier); 1747 } 1748 1749 boolean groupingUsed = fields.get("groupingUsed", true); 1750 if (groupingUsed != icuDecimalFormat.isGroupingUsed()) { 1751 icuDecimalFormat.setGroupingUsed(groupingUsed); 1752 } 1753 1754 int groupingSize = fields.get("groupingSize", (byte) 3); 1755 if (groupingSize != icuDecimalFormat.getGroupingSize()) { 1756 icuDecimalFormat.setGroupingSize(groupingSize); 1757 } 1758 1759 boolean decimalSeparatorAlwaysShown = fields.get("decimalSeparatorAlwaysShown", false); 1760 if (decimalSeparatorAlwaysShown != icuDecimalFormat.isDecimalSeparatorAlwaysShown()) { 1761 icuDecimalFormat.setDecimalSeparatorAlwaysShown(decimalSeparatorAlwaysShown); 1762 } 1763 1764 RoundingMode roundingMode = 1765 (RoundingMode) fields.get("roundingMode", RoundingMode.HALF_EVEN); 1766 if (convertRoundingMode(roundingMode) != icuDecimalFormat.getRoundingMode()) { 1767 setRoundingMode(roundingMode); 1768 } 1769 1770 int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309); 1771 if (maximumIntegerDigits != icuDecimalFormat.getMaximumIntegerDigits()) { 1772 icuDecimalFormat.setMaximumIntegerDigits(maximumIntegerDigits); 1773 } 1774 1775 int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309); 1776 if (minimumIntegerDigits != icuDecimalFormat.getMinimumIntegerDigits()) { 1777 icuDecimalFormat.setMinimumIntegerDigits(minimumIntegerDigits); 1778 } 1779 1780 int maximumFractionDigits = fields.get("maximumFractionDigits", 340); 1781 if (maximumFractionDigits != icuDecimalFormat.getMaximumFractionDigits()) { 1782 icuDecimalFormat.setMaximumFractionDigits(maximumFractionDigits); 1783 } 1784 1785 int minimumFractionDigits = fields.get("minimumFractionDigits", 340); 1786 if (minimumFractionDigits != icuDecimalFormat.getMinimumFractionDigits()) { 1787 icuDecimalFormat.setMinimumFractionDigits(minimumFractionDigits); 1788 } 1789 1790 boolean parseBigDecimal = fields.get("parseBigDecimal", true); 1791 if (parseBigDecimal != icuDecimalFormat.isParseBigDecimal()) { 1792 icuDecimalFormat.setParseBigDecimal(parseBigDecimal); 1793 } 1794 1795 updateFieldsFromIcu(); 1796 1797 if (fields.get("serialVersionOnStream", 0) < 3) { 1798 setMaximumIntegerDigits(super.getMaximumIntegerDigits()); 1799 setMinimumIntegerDigits(super.getMinimumIntegerDigits()); 1800 setMaximumFractionDigits(super.getMaximumFractionDigits()); 1801 setMinimumFractionDigits(super.getMinimumFractionDigits()); 1802 } 1803 } 1804 // END Android-added: Custom serialization code for compatibility with RI serialization. 1805 1806 //---------------------------------------------------------------------- 1807 // INSTANCE VARIABLES 1808 //---------------------------------------------------------------------- 1809 1810 // Android-removed: various fields now stored in icuDecimalFormat. 1811 1812 /** 1813 * The <code>DecimalFormatSymbols</code> object used by this format. 1814 * It contains the symbols used to format numbers, e.g. the grouping separator, 1815 * decimal separator, and so on. 1816 * 1817 * @serial 1818 * @see #setDecimalFormatSymbols 1819 * @see java.text.DecimalFormatSymbols 1820 */ 1821 private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols(); 1822 1823 // Android-removed: useExponentialNotation, *FieldPositions, minExponentDigits. 1824 1825 /** 1826 * The maximum number of digits allowed in the integer portion of a 1827 * <code>BigInteger</code> or <code>BigDecimal</code> number. 1828 * <code>maximumIntegerDigits</code> must be greater than or equal to 1829 * <code>minimumIntegerDigits</code>. 1830 * 1831 * @serial 1832 * @see #getMaximumIntegerDigits 1833 * @since 1.5 1834 */ 1835 // Android-changed: removed initialisation. 1836 private int maximumIntegerDigits /* = super.getMaximumIntegerDigits() */; 1837 1838 /** 1839 * The minimum number of digits allowed in the integer portion of a 1840 * <code>BigInteger</code> or <code>BigDecimal</code> number. 1841 * <code>minimumIntegerDigits</code> must be less than or equal to 1842 * <code>maximumIntegerDigits</code>. 1843 * 1844 * @serial 1845 * @see #getMinimumIntegerDigits 1846 * @since 1.5 1847 */ 1848 // Android-changed: removed initialisation. 1849 private int minimumIntegerDigits /* = super.getMinimumIntegerDigits() */; 1850 1851 /** 1852 * The maximum number of digits allowed in the fractional portion of a 1853 * <code>BigInteger</code> or <code>BigDecimal</code> number. 1854 * <code>maximumFractionDigits</code> must be greater than or equal to 1855 * <code>minimumFractionDigits</code>. 1856 * 1857 * @serial 1858 * @see #getMaximumFractionDigits 1859 * @since 1.5 1860 */ 1861 // Android-changed: removed initialisation. 1862 private int maximumFractionDigits /* = super.getMaximumFractionDigits() */; 1863 1864 /** 1865 * The minimum number of digits allowed in the fractional portion of a 1866 * <code>BigInteger</code> or <code>BigDecimal</code> number. 1867 * <code>minimumFractionDigits</code> must be less than or equal to 1868 * <code>maximumFractionDigits</code>. 1869 * 1870 * @serial 1871 * @see #getMinimumFractionDigits 1872 * @since 1.5 1873 */ 1874 // Android-changed: removed initialisation. 1875 private int minimumFractionDigits /* = super.getMinimumFractionDigits() */; 1876 1877 /** 1878 * The {@link java.math.RoundingMode} used in this DecimalFormat. 1879 * 1880 * @serial 1881 * @since 1.6 1882 */ 1883 private RoundingMode roundingMode = RoundingMode.HALF_EVEN; 1884 1885 // Android-removed: FastPathData, isFastPath, fastPathCheckNeeded and fastPathData. 1886 1887 //---------------------------------------------------------------------- 1888 1889 static final int currentSerialVersion = 4; 1890 1891 // Android-removed: serialVersionOnStream. 1892 1893 //---------------------------------------------------------------------- 1894 // CONSTANTS 1895 //---------------------------------------------------------------------- 1896 1897 // Android-removed: Fast-Path for double Constants, various constants. 1898 1899 // Upper limit on integer and fraction digits for a Java double 1900 static final int DOUBLE_INTEGER_DIGITS = 309; 1901 static final int DOUBLE_FRACTION_DIGITS = 340; 1902 1903 // Upper limit on integer and fraction digits for BigDecimal and BigInteger 1904 static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE; 1905 static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE; 1906 1907 // Proclaim JDK 1.1 serial compatibility. 1908 static final long serialVersionUID = 864413376551465018L; 1909} 1910