1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.Serializable;
21162b0775772fa66b7eb634760a8159a60c1ddceaElliott Hughesimport libcore.icu.ICU;
22162b0775772fa66b7eb634760a8159a60c1ddceaElliott Hughesimport libcore.icu.LocaleData;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
250ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes * A currency corresponding to an <a href="http://en.wikipedia.org/wiki/ISO_4217">ISO 4217</a>
2652b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes * currency code such as "EUR" or "USD".
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic final class Currency implements Serializable {
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final long serialVersionUID = -158308464356906721L;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
310ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    private static final HashMap<String, Currency> codesToCurrencies = new HashMap<String, Currency>();
320ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    private static final HashMap<Locale, Currency> localesToCurrencies = new HashMap<Locale, Currency>();
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
342e3a41defb42a97b463194d859d2d4088a600fd8Elliott Hughes    private final String currencyCode;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Currency(String currencyCode) {
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.currencyCode = currencyCode;
380ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        String symbol = ICU.getCurrencySymbol(Locale.US.toString(), currencyCode);
39b0e5963793d8980b349f8e553067c19fd31601c5Elliott Hughes        if (symbol == null) {
400ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            throw new IllegalArgumentException("Unsupported ISO 4217 currency code: " +
410ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes                    currencyCode);
422e3a41defb42a97b463194d859d2d4088a600fd8Elliott Hughes        }
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
460ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * Returns the {@code Currency} instance for the given ISO 4217 currency code.
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
480ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     *             if the currency code is not a supported ISO 4217 currency code.
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static Currency getInstance(String currencyCode) {
510ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        synchronized (codesToCurrencies) {
520ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            Currency currency = codesToCurrencies.get(currencyCode);
530ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            if (currency == null) {
540ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes                currency = new Currency(currencyCode);
550ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes                codesToCurrencies.put(currencyCode, currency);
560ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            }
570ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            return currency;
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the {@code Currency} instance for this {@code Locale}'s country.
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
640ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     *             if the locale's country is not a supported ISO 3166 country.
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static Currency getInstance(Locale locale) {
670ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        synchronized (localesToCurrencies) {
680ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            Currency currency = localesToCurrencies.get(locale);
690ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            if (currency != null) {
700ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes                return currency;
710ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            }
720ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            String country = locale.getCountry();
730ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            String variant = locale.getVariant();
740ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            if (!variant.isEmpty() && (variant.equals("EURO") || variant.equals("HK") ||
750ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes                    variant.equals("PREEURO"))) {
760ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes                country = country + "_" + variant;
770ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            }
780ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes
790ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            String currencyCode = ICU.getCurrencyCode(country);
800ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            if (currencyCode == null) {
810ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes                throw new IllegalArgumentException("Unsupported ISO 3166 country: " + locale);
825b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho            } else if (currencyCode.equals("XXX")) {
830ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes                return null;
840ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            }
850ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            Currency result = getInstance(currencyCode);
860ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            localesToCurrencies.put(locale, result);
870ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            return result;
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
890ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    }
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
910ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    /**
920ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * Returns a set of all known currencies.
930ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * @since 1.7
940ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     */
950ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    public static Set<Currency> getAvailableCurrencies() {
960ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        Set<Currency> result = new LinkedHashSet<Currency>();
970ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        String[] currencyCodes = ICU.getAvailableCurrencyCodes();
980ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        for (String currencyCode : currencyCodes) {
990ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            result.add(Currency.getInstance(currencyCode));
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
10196474a05d47fcca92f7d511e41a20f994fc1e677Elliott Hughes        return result;
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1053106a99ccbe2e2a25bb66266d0ee42d98dd18099Elliott Hughes     * Returns this currency's ISO 4217 currency code.
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getCurrencyCode() {
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return currencyCode;
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1120ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * Equivalent to {@code getDisplayName(Locale.getDefault())}.
1130ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
1140ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * @since 1.7
1150ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     */
1160ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    public String getDisplayName() {
1170ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        return getDisplayName(Locale.getDefault());
1180ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    }
1190ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes
1200ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    /**
1210ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * Returns the localized name of this currency in the given {@code locale}.
1220ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * Returns the ISO 4217 currency code if no localized name is available.
1230ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * @since 1.7
1240ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     */
1250ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    public String getDisplayName(Locale locale) {
1260ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        return ICU.getCurrencyDisplayName(locale.toString(), currencyCode);
1270ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    }
1280ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes
1290ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes    /**
1300ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * Equivalent to {@code getSymbol(Locale.getDefault())}.
1313106a99ccbe2e2a25bb66266d0ee42d98dd18099Elliott Hughes     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getSymbol() {
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return getSymbol(Locale.getDefault());
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1383106a99ccbe2e2a25bb66266d0ee42d98dd18099Elliott Hughes     * Returns the localized currency symbol for this currency in {@code locale}.
139aba52f92911e0faa4ae1907becc5a66cdb3254deElliott Hughes     * That is, given "USD" and Locale.US, you'd get "$", but given "USD" and a non-US locale,
140aba52f92911e0faa4ae1907becc5a66cdb3254deElliott Hughes     * you'd get "US$".
141f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
1423106a99ccbe2e2a25bb66266d0ee42d98dd18099Elliott Hughes     * <p>If the locale only specifies a language rather than a language and a country (such as
1433106a99ccbe2e2a25bb66266d0ee42d98dd18099Elliott Hughes     * {@code Locale.JAPANESE} or {new Locale("en", "")} rather than {@code Locale.JAPAN} or
1443106a99ccbe2e2a25bb66266d0ee42d98dd18099Elliott Hughes     * {new Locale("en", "US")}), the ISO 4217 currency code is returned.
1453106a99ccbe2e2a25bb66266d0ee42d98dd18099Elliott Hughes     *
1463106a99ccbe2e2a25bb66266d0ee42d98dd18099Elliott Hughes     * <p>If there is no locale-specific currency symbol, the ISO 4217 currency code is returned.
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getSymbol(Locale locale) {
1492e3a41defb42a97b463194d859d2d4088a600fd8Elliott Hughes        if (locale.getCountry().length() == 0) {
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return currencyCode;
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
15333aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes        // Check the locale first, in case the locale has the same currency.
154757a7942eed2b0aa457f8517a0259d2ac82c5b18Elliott Hughes        LocaleData localeData = LocaleData.get(locale);
15533aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes        if (localeData.internationalCurrencySymbol.equals(currencyCode)) {
15633aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes            return localeData.currencySymbol;
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1592b1f1d31b83dbabc432a928bd30d443e01b16b46Elliott Hughes        // Try ICU, and fall back to the currency code if ICU has nothing.
1600ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        String symbol = ICU.getCurrencySymbol(locale.toString(), currencyCode);
1612b1f1d31b83dbabc432a928bd30d443e01b16b46Elliott Hughes        return symbol != null ? symbol : currencyCode;
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1650ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * Returns the default number of fraction digits for this currency.
1660ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * For instance, the default number of fraction digits for the US dollar is 2 because there are
1670ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * 100 US cents in a US dollar. For the Japanese Yen, the number is 0 because coins smaller
1680ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * than 1 Yen became invalid in 1953. In the case of pseudo-currencies, such as
1690ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes     * IMF Special Drawing Rights, -1 is returned.
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int getDefaultFractionDigits() {
1720ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        // In some places the code XXX is used as the fall back currency.
1730ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        // The RI returns -1, but ICU defaults to 2 for unknown currencies.
1740ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        if (currencyCode.equals("XXX")) {
1750ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes            return -1;
1760ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        }
1770ad1c14261c4db0731503770ec6a027e90cc6e38Elliott Hughes        return ICU.getCurrencyFractionDigits(currencyCode);
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns this currency's ISO 4217 currency code.
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String toString() {
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return currencyCode;
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Object readResolve() {
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return getInstance(currencyCode);
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
192