• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package java.util;
19 
20 import java.io.Serializable;
21 import libcore.icu.ICU;
22 import libcore.icu.LocaleData;
23 
24 /**
25  * A currency corresponding to an <a href="http://en.wikipedia.org/wiki/ISO_4217">ISO 4217</a>
26  * currency code such as "EUR" or "USD".
27  */
28 public final class Currency implements Serializable {
29     private static final long serialVersionUID = -158308464356906721L;
30 
31     private static final HashMap<String, Currency> codesToCurrencies = new HashMap<String, Currency>();
32     private static final HashMap<Locale, Currency> localesToCurrencies = new HashMap<Locale, Currency>();
33 
34     private final String currencyCode;
35 
Currency(String currencyCode)36     private Currency(String currencyCode) {
37         this.currencyCode = currencyCode;
38         String symbol = ICU.getCurrencySymbol(Locale.US.toString(), currencyCode);
39         if (symbol == null) {
40             throw new IllegalArgumentException("Unsupported ISO 4217 currency code: " +
41                     currencyCode);
42         }
43     }
44 
45     /**
46      * Returns the {@code Currency} instance for the given ISO 4217 currency code.
47      * @throws IllegalArgumentException
48      *             if the currency code is not a supported ISO 4217 currency code.
49      */
getInstance(String currencyCode)50     public static Currency getInstance(String currencyCode) {
51         synchronized (codesToCurrencies) {
52             Currency currency = codesToCurrencies.get(currencyCode);
53             if (currency == null) {
54                 currency = new Currency(currencyCode);
55                 codesToCurrencies.put(currencyCode, currency);
56             }
57             return currency;
58         }
59     }
60 
61     /**
62      * Returns the {@code Currency} instance for this {@code Locale}'s country.
63      * @throws IllegalArgumentException
64      *             if the locale's country is not a supported ISO 3166 country.
65      */
getInstance(Locale locale)66     public static Currency getInstance(Locale locale) {
67         synchronized (localesToCurrencies) {
68             Currency currency = localesToCurrencies.get(locale);
69             if (currency != null) {
70                 return currency;
71             }
72             String country = locale.getCountry();
73             String variant = locale.getVariant();
74             if (!variant.isEmpty() && (variant.equals("EURO") || variant.equals("HK") ||
75                     variant.equals("PREEURO"))) {
76                 country = country + "_" + variant;
77             }
78 
79             String currencyCode = ICU.getCurrencyCode(country);
80             if (currencyCode == null) {
81                 throw new IllegalArgumentException("Unsupported ISO 3166 country: " + locale);
82             } else if (currencyCode.equals("XXX")) {
83                 return null;
84             }
85             Currency result = getInstance(currencyCode);
86             localesToCurrencies.put(locale, result);
87             return result;
88         }
89     }
90 
91     /**
92      * Returns a set of all known currencies.
93      * @since 1.7
94      * @hide 1.7
95      */
getAvailableCurrencies()96     public static Set<Currency> getAvailableCurrencies() {
97         Set<Currency> result = new LinkedHashSet<Currency>();
98         String[] currencyCodes = ICU.getAvailableCurrencyCodes();
99         for (String currencyCode : currencyCodes) {
100             result.add(Currency.getInstance(currencyCode));
101         }
102         return result;
103     }
104 
105     /**
106      * Returns this currency's ISO 4217 currency code.
107      */
getCurrencyCode()108     public String getCurrencyCode() {
109         return currencyCode;
110     }
111 
112     /**
113      * Equivalent to {@code getDisplayName(Locale.getDefault())}.
114      * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
115      * @since 1.7
116      * @hide 1.7
117      */
getDisplayName()118     public String getDisplayName() {
119         return getDisplayName(Locale.getDefault());
120     }
121 
122     /**
123      * Returns the localized name of this currency in the given {@code locale}.
124      * Returns the ISO 4217 currency code if no localized name is available.
125      * @since 1.7
126      * @hide 1.7
127      */
getDisplayName(Locale locale)128     public String getDisplayName(Locale locale) {
129         return ICU.getCurrencyDisplayName(locale.toString(), currencyCode);
130     }
131 
132     /**
133      * Equivalent to {@code getSymbol(Locale.getDefault())}.
134      * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
135      */
getSymbol()136     public String getSymbol() {
137         return getSymbol(Locale.getDefault());
138     }
139 
140     /**
141      * Returns the localized currency symbol for this currency in {@code locale}.
142      * That is, given "USD" and Locale.US, you'd get "$", but given "USD" and a non-US locale,
143      * you'd get "US$".
144      *
145      * <p>If the locale only specifies a language rather than a language and a country (such as
146      * {@code Locale.JAPANESE} or {new Locale("en", "")} rather than {@code Locale.JAPAN} or
147      * {new Locale("en", "US")}), the ISO 4217 currency code is returned.
148      *
149      * <p>If there is no locale-specific currency symbol, the ISO 4217 currency code is returned.
150      */
getSymbol(Locale locale)151     public String getSymbol(Locale locale) {
152         if (locale.getCountry().length() == 0) {
153             return currencyCode;
154         }
155 
156         // Check the locale first, in case the locale has the same currency.
157         LocaleData localeData = LocaleData.get(locale);
158         if (localeData.internationalCurrencySymbol.equals(currencyCode)) {
159             return localeData.currencySymbol;
160         }
161 
162         // Try ICU, and fall back to the currency code if ICU has nothing.
163         String symbol = ICU.getCurrencySymbol(locale.toString(), currencyCode);
164         return symbol != null ? symbol : currencyCode;
165     }
166 
167     /**
168      * Returns the default number of fraction digits for this currency.
169      * For instance, the default number of fraction digits for the US dollar is 2 because there are
170      * 100 US cents in a US dollar. For the Japanese Yen, the number is 0 because coins smaller
171      * than 1 Yen became invalid in 1953. In the case of pseudo-currencies, such as
172      * IMF Special Drawing Rights, -1 is returned.
173      */
getDefaultFractionDigits()174     public int getDefaultFractionDigits() {
175         // In some places the code XXX is used as the fall back currency.
176         // The RI returns -1, but ICU defaults to 2 for unknown currencies.
177         if (currencyCode.equals("XXX")) {
178             return -1;
179         }
180         return ICU.getCurrencyFractionDigits(currencyCode);
181     }
182 
183     /**
184      * Returns this currency's ISO 4217 currency code.
185      */
186     @Override
toString()187     public String toString() {
188         return currencyCode;
189     }
190 
readResolve()191     private Object readResolve() {
192         return getInstance(currencyCode);
193     }
194 }
195