Currency.java revision 7d8588a5a508deb69849b8ed4f7af80a19adcb2b
1cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project/*
2cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * Copyright (C) 2014 The Android Open Source Project
3cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
4cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project *
6cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * This code is free software; you can redistribute it and/or modify it
7cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * under the terms of the GNU General Public License version 2 only, as
8cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * published by the Free Software Foundation.  Oracle designates this
9cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * particular file as subject to the "Classpath" exception as provided
10cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * by Oracle in the LICENSE file that accompanied this code.
11cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project *
12cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * This code is distributed in the hope that it will be useful, but WITHOUT
13cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * version 2 for more details (a copy is included in the LICENSE file that
16cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * accompanied this code).
17cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project *
18cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * You should have received a copy of the GNU General Public License version
19cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * 2 along with this work; if not, write to the Free Software Foundation,
20e81531e91ecae92aff471dbff9cbeb0f95ff4a80Dima Zavin * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project *
224a0748be283a8c9efa02243c3e1716c49443a87cDima Zavin * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * or visit www.oracle.com if you need additional information or have any
24e81531e91ecae92aff471dbff9cbeb0f95ff4a80Dima Zavin * questions.
25cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project */
26cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
27cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectpackage java.util;
283e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi
293e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Triviimport java.io.Serializable;
30cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectimport java.util.concurrent.ConcurrentHashMap;
31cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectimport java.util.concurrent.ConcurrentMap;
32cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
33cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Projectimport libcore.icu.ICU;
34cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
35cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project/**
36cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * Represents a currency. Currencies are identified by their ISO 4217 currency
373e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi * codes. Visit the <a href="http://www.iso.org/iso/home/standards/currency_codes.htm">
38cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * ISO web site</a> for more information.
39cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * <p>
403e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi * The class is designed so that there's never more than one
413e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi * <code>Currency</code> instance for any given currency. Therefore, there's
42cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * no public constructor. You obtain a <code>Currency</code> instance using
43cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project * the <code>getInstance</code> methods.
44cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project *
45dbfad0ce83535cea0940e04660bdfab5b6c867a4Eric Laurent * @since 1.4
46dbfad0ce83535cea0940e04660bdfab5b6c867a4Eric Laurent */
473e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi// Android-changed: Superseding runtime currency data via a properties file is not
48cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project// supported on Android.
49617c80a82e5620b2f16348e4bd3d7fc3b76e9021John Grossmanpublic final class Currency implements Serializable {
503e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi
51cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    private static final long serialVersionUID = -158308464356906721L;
52cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
53cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    /**
54cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project     * ISO 4217 currency code for this currency.
553e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi     *
563e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi     * @serial
573e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi     */
583e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi    private final String currencyCode;
593e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi
603e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi    // class data: instance map
613e480fa067136253ae05faaba77f814f42cd56f0Jean-Michel Trivi
62cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    private static ConcurrentMap<String, Currency> instances = new ConcurrentHashMap<>(7);
63cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    private static HashSet<Currency> available;
64cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project
65cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    // Android-changed: Implement Currency on top of ICU throughout.
66cc490161f6af9e4a6842ee827e4bfc43bc4509d5The Android Open Source Project    // We do not keep track of defaultFractionDigits and numericCode separately here.
67    private transient final android.icu.util.Currency icuCurrency;
68
69    /**
70     * Constructs a <code>Currency</code> instance. The constructor is private
71     * so that we can insure that there's never more than one instance for a
72     * given currency.
73     */
74    private Currency(android.icu.util.Currency icuCurrency) {
75        this.icuCurrency = icuCurrency;
76        this.currencyCode = icuCurrency.getCurrencyCode();
77    }
78
79    /**
80     * Returns the <code>Currency</code> instance for the given currency code.
81     *
82     * @param currencyCode the ISO 4217 code of the currency
83     * @return the <code>Currency</code> instance for the given currency code
84     * @exception NullPointerException if <code>currencyCode</code> is null
85     * @exception IllegalArgumentException if <code>currencyCode</code> is not
86     * a supported ISO 4217 code.
87     */
88    public static Currency getInstance(String currencyCode) {
89        // Android-changed BEGIN: use ICU
90        Currency instance = instances.get(currencyCode);
91        if (instance != null) {
92            return instance;
93        }
94        android.icu.util.Currency icuInstance =
95                  android.icu.util.Currency.getInstance(currencyCode);
96        if (icuInstance == null) {
97            return null;
98        }
99        Currency currencyVal = new Currency(icuInstance);
100        // ANDROID-changed END
101        instance = instances.putIfAbsent(currencyCode, currencyVal);
102        return (instance != null ? instance : currencyVal);
103    }
104
105    /**
106     * Returns the <code>Currency</code> instance for the country of the
107     * given locale. The language and variant components of the locale
108     * are ignored. The result may vary over time, as countries change their
109     * currencies. For example, for the original member countries of the
110     * European Monetary Union, the method returns the old national currencies
111     * until December 31, 2001, and the Euro from January 1, 2002, local time
112     * of the respective countries.
113     * <p>
114     * The method returns <code>null</code> for territories that don't
115     * have a currency, such as Antarctica.
116     *
117     * @param locale the locale for whose country a <code>Currency</code>
118     * instance is needed
119     * @return the <code>Currency</code> instance for the country of the given
120     * locale, or {@code null}
121     * @exception NullPointerException if <code>locale</code> or its country
122     * code is {@code null}
123     * @exception IllegalArgumentException if the country of the given {@code locale}
124     * is not a supported ISO 3166 country code.
125     */
126    public static Currency getInstance(Locale locale) {
127        // Android-changed BEGIN: use ICU
128        android.icu.util.Currency icuInstance =
129                android.icu.util.Currency.getInstance(locale);
130        String variant = locale.getVariant();
131        String country = locale.getCountry();
132        if (!variant.isEmpty() && (variant.equals("EURO") || variant.equals("HK") ||
133                variant.equals("PREEURO"))) {
134            country = country + "_" + variant;
135        }
136        String currencyCode = ICU.getCurrencyCode(country);
137        if (currencyCode == null) {
138            throw new IllegalArgumentException("Unsupported ISO 3166 country: " + locale);
139        }
140        if (icuInstance == null || icuInstance.getCurrencyCode().equals("XXX")) {
141            return null;
142        }
143        return getInstance(currencyCode);
144        // Android-changed END
145    }
146
147    /**
148     * Gets the set of available currencies.  The returned set of currencies
149     * contains all of the available currencies, which may include currencies
150     * that represent obsolete ISO 4217 codes.  The set can be modified
151     * without affecting the available currencies in the runtime.
152     *
153     * @return the set of available currencies.  If there is no currency
154     *    available in the runtime, the returned set is empty.
155     * @since 1.7
156     */
157    public static Set<Currency> getAvailableCurrencies() {
158        synchronized(Currency.class) {
159            if (available == null) {
160                // Android-changed BEGIN: use ICU
161                Set<android.icu.util.Currency> icuAvailableCurrencies
162                        = android.icu.util.Currency.getAvailableCurrencies();
163                available = new HashSet<>();
164                for (android.icu.util.Currency icuCurrency : icuAvailableCurrencies) {
165                    Currency currency = getInstance(icuCurrency.getCurrencyCode());
166                    if (currency == null) {
167                        currency = new Currency(icuCurrency);
168                        instances.put(currency.currencyCode, currency);
169                    }
170                    available.add(currency);
171                }
172                // Android-changed END
173            }
174        }
175
176        @SuppressWarnings("unchecked")
177        Set<Currency> result = (Set<Currency>) available.clone();
178        return result;
179    }
180
181    /**
182     * Gets the ISO 4217 currency code of this currency.
183     *
184     * @return the ISO 4217 currency code of this currency.
185     */
186    public String getCurrencyCode() {
187        return currencyCode;
188    }
189
190    /**
191     * Gets the symbol of this currency for the default
192     * {@link Locale.Category#DISPLAY DISPLAY} locale.
193     * For example, for the US Dollar, the symbol is "$" if the default
194     * locale is the US, while for other locales it may be "US$". If no
195     * symbol can be determined, the ISO 4217 currency code is returned.
196     * <p>
197     * This is equivalent to calling
198     * {@link #getSymbol(Locale)
199     *     getSymbol(Locale.getDefault(Locale.Category.DISPLAY))}.
200     *
201     * @return the symbol of this currency for the default
202     *     {@link Locale.Category#DISPLAY DISPLAY} locale
203     */
204    public String getSymbol() {
205        return icuCurrency.getSymbol();
206    }
207
208    /**
209     * Gets the symbol of this currency for the specified locale.
210     * For example, for the US Dollar, the symbol is "$" if the specified
211     * locale is the US, while for other locales it may be "US$". If no
212     * symbol can be determined, the ISO 4217 currency code is returned.
213     *
214     * @param locale the locale for which a display name for this currency is
215     * needed
216     * @return the symbol of this currency for the specified locale
217     * @exception NullPointerException if <code>locale</code> is null
218     */
219    public String getSymbol(Locale locale) {
220        // Android-changed BEGIN: use ICU
221        if (locale == null) {
222            throw new NullPointerException("locale == null");
223        }
224        return icuCurrency.getSymbol(locale);
225        // Android-changed END
226    }
227
228    /**
229     * Gets the default number of fraction digits used with this currency.
230     * For example, the default number of fraction digits for the Euro is 2,
231     * while for the Japanese Yen it's 0.
232     * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
233     * -1 is returned.
234     *
235     * @return the default number of fraction digits used with this currency
236     */
237    public int getDefaultFractionDigits() {
238        // Android-changed BEGIN: use ICU
239        if (icuCurrency.getCurrencyCode().equals("XXX")) {
240            return -1;
241        }
242        return icuCurrency.getDefaultFractionDigits();
243        // Android-changed END
244    }
245
246    /**
247     * Returns the ISO 4217 numeric code of this currency.
248     *
249     * @return the ISO 4217 numeric code of this currency
250     * @since 1.7
251     */
252    public int getNumericCode() {
253        // Android-changed: use ICU
254        // was: return numericCode;
255        return icuCurrency.getNumericCode();
256    }
257
258    /**
259     * Gets the name that is suitable for displaying this currency for
260     * the default {@link Locale.Category#DISPLAY DISPLAY} locale.
261     * If there is no suitable display name found
262     * for the default locale, the ISO 4217 currency code is returned.
263     * <p>
264     * This is equivalent to calling
265     * {@link #getDisplayName(Locale)
266     *     getDisplayName(Locale.getDefault(Locale.Category.DISPLAY))}.
267     *
268     * @return the display name of this currency for the default
269     *     {@link Locale.Category#DISPLAY DISPLAY} locale
270     * @since 1.7
271     */
272    public String getDisplayName() {
273        return icuCurrency.getDisplayName();
274    }
275
276    /**
277     * Gets the name that is suitable for displaying this currency for
278     * the specified locale.  If there is no suitable display name found
279     * for the specified locale, the ISO 4217 currency code is returned.
280     *
281     * @param locale the locale for which a display name for this currency is
282     * needed
283     * @return the display name of this currency for the specified locale
284     * @exception NullPointerException if <code>locale</code> is null
285     * @since 1.7
286     */
287    public String getDisplayName(Locale locale) {
288        // Android-changed: use ICU
289        return icuCurrency.getDisplayName(Objects.requireNonNull(locale));
290    }
291
292    /**
293     * Returns the ISO 4217 currency code of this currency.
294     *
295     * @return the ISO 4217 currency code of this currency
296     */
297    @Override
298    public String toString() {
299        // Android-changed: use ICU
300        return icuCurrency.toString();
301    }
302
303    /**
304     * Resolves instances being deserialized to a single instance per currency.
305     */
306    private Object readResolve() {
307        return getInstance(currencyCode);
308    }
309}
310