blob: ceda24e6b17970b425a0346ef71abf22df548629 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.util;
import java.io.Serializable;
import libcore.icu.ICU;
import libcore.icu.LocaleData;
/**
* A currency corresponding to an <a href="http://en.wikipedia.org/wiki/ISO_4217">ISO 4217</a>
* currency code such as "EUR" or "USD".
*/
public final class Currency implements Serializable {
private static final long serialVersionUID = -158308464356906721L;
private static final HashMap<String, Currency> codesToCurrencies = new HashMap<String, Currency>();
private static final HashMap<Locale, Currency> localesToCurrencies = new HashMap<Locale, Currency>();
private final String currencyCode;
private Currency(String currencyCode) {
this.currencyCode = currencyCode;
String symbol = ICU.getCurrencySymbol(Locale.US.toString(), currencyCode);
if (symbol == null) {
throw new IllegalArgumentException("Unsupported ISO 4217 currency code: " +
currencyCode);
}
}
/**
* Returns the {@code Currency} instance for the given ISO 4217 currency code.
* @throws IllegalArgumentException
* if the currency code is not a supported ISO 4217 currency code.
*/
public static Currency getInstance(String currencyCode) {
synchronized (codesToCurrencies) {
Currency currency = codesToCurrencies.get(currencyCode);
if (currency == null) {
currency = new Currency(currencyCode);
codesToCurrencies.put(currencyCode, currency);
}
return currency;
}
}
/**
* Returns the {@code Currency} instance for this {@code Locale}'s country.
* @throws IllegalArgumentException
* if the locale's country is not a supported ISO 3166 country.
*/
public static Currency getInstance(Locale locale) {
synchronized (localesToCurrencies) {
Currency currency = localesToCurrencies.get(locale);
if (currency != null) {
return currency;
}
String country = locale.getCountry();
String variant = locale.getVariant();
if (!variant.isEmpty() && (variant.equals("EURO") || variant.equals("HK") ||
variant.equals("PREEURO"))) {
country = country + "_" + variant;
}
String currencyCode = ICU.getCurrencyCode(country);
if (currencyCode == null) {
throw new IllegalArgumentException("Unsupported ISO 3166 country: " + locale);
} else if (currencyCode.equals("XXX")) {
return null;
}
Currency result = getInstance(currencyCode);
localesToCurrencies.put(locale, result);
return result;
}
}
/**
* Returns a set of all known currencies.
* @since 1.7
* @hide 1.7
*/
public static Set<Currency> getAvailableCurrencies() {
Set<Currency> result = new LinkedHashSet<Currency>();
String[] currencyCodes = ICU.getAvailableCurrencyCodes();
for (String currencyCode : currencyCodes) {
result.add(Currency.getInstance(currencyCode));
}
return result;
}
/**
* Returns this currency's ISO 4217 currency code.
*/
public String getCurrencyCode() {
return currencyCode;
}
/**
* Equivalent to {@code getDisplayName(Locale.getDefault())}.
* See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
* @since 1.7
* @hide 1.7
*/
public String getDisplayName() {
return getDisplayName(Locale.getDefault());
}
/**
* Returns the localized name of this currency in the given {@code locale}.
* Returns the ISO 4217 currency code if no localized name is available.
* @since 1.7
* @hide 1.7
*/
public String getDisplayName(Locale locale) {
return ICU.getCurrencyDisplayName(locale.toString(), currencyCode);
}
/**
* Equivalent to {@code getSymbol(Locale.getDefault())}.
* See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
*/
public String getSymbol() {
return getSymbol(Locale.getDefault());
}
/**
* Returns the localized currency symbol for this currency in {@code locale}.
* That is, given "USD" and Locale.US, you'd get "$", but given "USD" and a non-US locale,
* you'd get "US$".
*
* <p>If the locale only specifies a language rather than a language and a country (such as
* {@code Locale.JAPANESE} or {new Locale("en", "")} rather than {@code Locale.JAPAN} or
* {new Locale("en", "US")}), the ISO 4217 currency code is returned.
*
* <p>If there is no locale-specific currency symbol, the ISO 4217 currency code is returned.
*/
public String getSymbol(Locale locale) {
if (locale.getCountry().length() == 0) {
return currencyCode;
}
// Check the locale first, in case the locale has the same currency.
LocaleData localeData = LocaleData.get(locale);
if (localeData.internationalCurrencySymbol.equals(currencyCode)) {
return localeData.currencySymbol;
}
// Try ICU, and fall back to the currency code if ICU has nothing.
String symbol = ICU.getCurrencySymbol(locale.toString(), currencyCode);
return symbol != null ? symbol : currencyCode;
}
/**
* Returns the default number of fraction digits for this currency.
* For instance, the default number of fraction digits for the US dollar is 2 because there are
* 100 US cents in a US dollar. For the Japanese Yen, the number is 0 because coins smaller
* than 1 Yen became invalid in 1953. In the case of pseudo-currencies, such as
* IMF Special Drawing Rights, -1 is returned.
*/
public int getDefaultFractionDigits() {
// In some places the code XXX is used as the fall back currency.
// The RI returns -1, but ICU defaults to 2 for unknown currencies.
if (currencyCode.equals("XXX")) {
return -1;
}
return ICU.getCurrencyFractionDigits(currencyCode);
}
/**
* Returns this currency's ISO 4217 currency code.
*/
@Override
public String toString() {
return currencyCode;
}
private Object readResolve() {
return getInstance(currencyCode);
}
}