12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */
2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *******************************************************************************
6f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * Copyright (C) 2001-2016, International Business Machines Corporation and
7f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * others. All Rights Reserved.
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *******************************************************************************
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.impl;
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Collections;
132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Locale;
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Map;
152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Set;
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale;
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
191537b2f39245c07b00aa78c3600f7aebcb172490Neil Fuller/**
201537b2f39245c07b00aa78c3600f7aebcb172490Neil Fuller * @hide Only a subset of ICU is exposed in Android
21836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller */
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class ICULocaleService extends ICUService {
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private ULocale fallbackLocale;
242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String fallbackLocaleName;
252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct an ICULocaleService.
282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public ICULocaleService() {
302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct an ICULocaleService with a name (useful for debugging).
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public ICULocaleService(String name) {
362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        super(name);
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience override for callers using locales.  This calls
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * get(ULocale, int, ULocale[]) with KIND_ANY for kind and null for
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * actualReturn.
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Object get(ULocale locale) {
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return get(locale, LocaleKey.KIND_ANY, null);
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience override for callers using locales.  This calls
502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * get(ULocale, int, ULocale[]) with a null actualReturn.
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Object get(ULocale locale, int kind) {
532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return get(locale, kind, null);
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience override for callers using locales.  This calls
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * get(ULocale, int, ULocale[]) with KIND_ANY for kind.
592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Object get(ULocale locale, ULocale[] actualReturn) {
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return get(locale, LocaleKey.KIND_ANY, actualReturn);
622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience override for callers using locales.  This uses
662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * createKey(ULocale.toString(), kind) to create a key, calls getKey, and then
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * if actualReturn is not null, returns the actualResult from
68f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * getKey (stripping any prefix) into a ULocale.
692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Object get(ULocale locale, int kind, ULocale[] actualReturn) {
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Key key = createKey(locale, kind);
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (actualReturn == null) {
732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return getKey(key);
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String[] temp = new String[1];
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Object result = getKey(key, temp);
782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (result != null) {
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int n = temp[0].indexOf("/");
802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (n >= 0) {
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                temp[0] = temp[0].substring(n+1);
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            actualReturn[0] = new ULocale(temp[0]);
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return result;
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience override for callers using locales.  This calls
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * registerObject(Object, ULocale, int kind, boolean visible)
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * passing KIND_ANY for the kind, and true for the visibility.
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Factory registerObject(Object obj, ULocale locale) {
942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return registerObject(obj, locale, LocaleKey.KIND_ANY, true);
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience override for callers using locales.  This calls
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * registerObject(Object, ULocale, int kind, boolean visible)
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * passing KIND_ANY for the kind.
1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Factory registerObject(Object obj, ULocale locale, boolean visible) {
1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return registerObject(obj, locale, LocaleKey.KIND_ANY, visible);
1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience function for callers using locales.  This calls
1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * registerObject(Object, ULocale, int kind, boolean visible)
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * passing true for the visibility.
1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Factory registerObject(Object obj, ULocale locale, int kind) {
1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return registerObject(obj, locale, kind, true);
1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience function for callers using locales.  This  instantiates
1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a SimpleLocaleKeyFactory, and registers the factory.
1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Factory registerObject(Object obj, ULocale locale, int kind, boolean visible) {
1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Factory factory = new SimpleLocaleKeyFactory(obj, locale, kind, visible);
1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return registerFactory(factory);
1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience method for callers using locales.  This returns the standard
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Locale list, built from the Set of visible ids.
1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Locale[] getAvailableLocales() {
1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // TODO make this wrap getAvailableULocales later
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Set<String> visIDs = getVisibleIDs();
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Locale[] locales = new Locale[visIDs.size()];
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int n = 0;
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (String id : visIDs) {
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Locale loc = LocaleUtility.getLocaleFromName(id);
1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            locales[n++] = loc;
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return locales;
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convenience method for callers using locales.  This returns the standard
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * ULocale list, built from the Set of visible ids.
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public ULocale[] getAvailableULocales() {
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Set<String> visIDs = getVisibleIDs();
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ULocale[] locales = new ULocale[visIDs.size()];
1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int n = 0;
1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (String id : visIDs) {
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            locales[n++] = new ULocale(id);
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return locales;
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
153f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * A subclass of Key that implements a locale fallback mechanism.
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The first locale to search for is the locale provided by the
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * client, and the fallback locale to search for is the current
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * default locale.  If a prefix is present, the currentDescriptor
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * includes it before the locale proper, separated by "/".  This
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is the default key instantiated by ICULocaleService.</p>
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>Canonicalization adjusts the locale string so that the
1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * section before the first understore is in lower case, and the rest
164f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * is in upper case, with no trailing underscores.</p>
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static class LocaleKey extends ICUService.Key {
1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        private int kind;
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        private int varstart;
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        private String primaryID;
1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        private String fallbackID;
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        private String currentID;
1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public static final int KIND_ANY = -1;
1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Create a LocaleKey with canonical primary and fallback IDs.
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID) {
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return createWithCanonicalFallback(primaryID, canonicalFallbackID, KIND_ANY);
1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
181f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Create a LocaleKey with canonical primary and fallback IDs.
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID, int kind) {
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (primaryID == null) {
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return null;
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String canonicalPrimaryID = ULocale.getName(primaryID);
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return new LocaleKey(primaryID, canonicalPrimaryID, canonicalFallbackID, kind);
1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
192f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Create a LocaleKey with canonical primary and fallback IDs.
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public static LocaleKey createWithCanonical(ULocale locale, String canonicalFallbackID, int kind) {
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (locale == null) {
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return null;
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String canonicalPrimaryID = locale.getName();
2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return new LocaleKey(canonicalPrimaryID, canonicalPrimaryID, canonicalFallbackID, kind);
2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
203f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * PrimaryID is the user's requested locale string,
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * canonicalPrimaryID is this string in canonical form,
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * fallbackID is the current default locale's string in
2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * canonical form.
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected LocaleKey(String primaryID, String canonicalPrimaryID, String canonicalFallbackID, int kind) {
2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            super(primaryID);
2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.kind = kind;
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (canonicalPrimaryID == null || canonicalPrimaryID.equalsIgnoreCase("root")) {
2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                this.primaryID = "";
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                this.fallbackID = null;
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int idx = canonicalPrimaryID.indexOf('@');
2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (idx == 4 && canonicalPrimaryID.regionMatches(true, 0, "root", 0, 4)) {
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.primaryID = canonicalPrimaryID.substring(4);
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.varstart = 0;
2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.fallbackID = null;
2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.primaryID = canonicalPrimaryID;
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.varstart = idx;
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (canonicalFallbackID == null || this.primaryID.equals(canonicalFallbackID)) {
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        this.fallbackID = "";
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        this.fallbackID = canonicalFallbackID;
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.currentID = varstart == -1 ? this.primaryID : this.primaryID.substring(0, varstart);
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Return the prefix associated with the kind, or null if the kind is KIND_ANY.
2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public String prefix() {
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return kind == KIND_ANY ? null : Integer.toString(kind());
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Return the kind code associated with this key.
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public int kind() {
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return kind;
2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Return the (canonical) original ID.
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
255f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public String canonicalID() {
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return primaryID;
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Return the (canonical) current ID, or null if no current id.
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
263f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public String currentID() {
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return currentID;
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Return the (canonical) current descriptor, or null if no current id.
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Includes the keywords, whereas the ID does not include keywords.
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
272f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public String currentDescriptor() {
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String result = currentID();
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (result != null) {
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                StringBuilder buf = new StringBuilder(); // default capacity 16 is usually good enough
2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (kind != KIND_ANY) {
2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    buf.append(prefix());
2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                buf.append('/');
2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                buf.append(result);
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (varstart != -1) {
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    buf.append(primaryID.substring(varstart, primaryID.length()));
2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = buf.toString();
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return result;
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Convenience method to return the locale corresponding to the (canonical) original ID.
2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public ULocale canonicalLocale() {
2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return new ULocale(primaryID);
2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Convenience method to return the ulocale corresponding to the (canonical) currentID.
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public ULocale currentLocale() {
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (varstart == -1) {
3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return new ULocale(currentID);
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return new ULocale(currentID + primaryID.substring(varstart));
3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * If the key has a fallback, modify the key and return true,
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * otherwise return false.</p>
3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         *
3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * <p>First falls back through the primary ID, then through
3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * the fallbackID.  The final fallback is "" (root)
3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * unless the primary id was "" (root), in which case
315f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert         * there is no fallback.
3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
317f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public boolean fallback() {
3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int x = currentID.lastIndexOf('_');
3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (x != -1) {
3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                while (--x >= 0 && currentID.charAt(x) == '_') { // handle zh__PINYIN
3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                currentID = currentID.substring(0, x+1);
3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return true;
3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (fallbackID != null) {
3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                currentID = fallbackID;
3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (fallbackID.length() == 0) {
3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    fallbackID = null;
3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    fallbackID = "";
3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return true;
3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            currentID = null;
3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
340f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert         * If a key created from id would eventually fallback to match the
3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * canonical ID of this key, return true.
3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
343f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public boolean isFallbackOf(String id) {
3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return LocaleUtility.isFallbackOf(canonicalID(), id);
3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * A subclass of Factory that uses LocaleKeys.  If 'visible' the
3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * factory reports its IDs.
3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static abstract class LocaleKeyFactory implements Factory {
3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected final String name;
3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected final boolean visible;
3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public static final boolean VISIBLE = true;
3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public static final boolean INVISIBLE = false;
3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Constructor used by subclasses.
3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected LocaleKeyFactory(boolean visible) {
3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.visible = visible;
3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.name = null;
3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Constructor used by subclasses.
3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected LocaleKeyFactory(boolean visible, String name) {
3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.visible = visible;
3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.name = name;
3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Implement superclass abstract method.  This checks the currentID of
3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * the key against the supported IDs, and passes the canonicalLocale and
3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * kind off to handleCreate (which subclasses must implement).
3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
381f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public Object create(Key key, ICUService service) {
3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (handlesKey(key)) {
3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                LocaleKey lkey = (LocaleKey)key;
3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int kind = lkey.kind();
386f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ULocale uloc = lkey.currentLocale();
3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return handleCreate(uloc, kind, service);
3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // System.out.println("factory: " + this + " did not support id: " + key.currentID());
3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // System.out.println("supported ids: " + getSupportedIDs());
3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return null;
3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected boolean handlesKey(Key key) {
3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (key != null) {
3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String id = key.currentID();
3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Set<String> supported = getSupportedIDs();
4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return supported.contains(id);
4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Override of superclass method.
4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
408f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public void updateVisibleIDs(Map<String, Factory> result) {
4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Set<String> cache = getSupportedIDs();
4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (String id : cache) {
4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (visible) {
4132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    result.put(id, this);
4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    result.remove(id);
4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       }
4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Return a localized name for the locale represented by id.
4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
423f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public String getDisplayName(String id, ULocale locale) {
4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // assume if the user called this on us, we must have handled some fallback of this id
4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            //          if (isSupportedID(id)) {
4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (locale == null) {
4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return id;
4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ULocale loc = new ULocale(id);
4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return loc.getDisplayName(locale);
4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            //              }
4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            //          return null;
4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ///CLOVER:OFF
4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Utility method used by create(Key, ICUService).  Subclasses can
4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * implement this instead of create.
4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected Object handleCreate(ULocale loc, int kind, ICUService service) {
4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return null;
4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ///CLOVER:ON
4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
447f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert         * Return true if this id is one the factory supports (visible or
4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * otherwise).
4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected boolean isSupportedID(String id) {
4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return getSupportedIDs().contains(id);
4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
453f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
455f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert         * Return the set of ids that this factory supports (visible or
4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * otherwise).  This can be called often and might need to be
4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * cached if it is expensive to create.
4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected Set<String> getSupportedIDs() {
4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return Collections.emptySet();
4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * For debugging.
4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
466f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public String toString() {
4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            StringBuilder buf = new StringBuilder(super.toString());
4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (name != null) {
4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                buf.append(", name: ");
4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                buf.append(name);
4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(", visible: ");
4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(visible);
4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return buf.toString();
4762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * A LocaleKeyFactory that just returns a single object for a kind/locale.
4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static class SimpleLocaleKeyFactory extends LocaleKeyFactory {
4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        private final Object obj;
4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        private final String id;
4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        private final int kind;
4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // TODO: remove when we no longer need this
4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public SimpleLocaleKeyFactory(Object obj, ULocale locale, int kind, boolean visible) {
4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this(obj, locale, kind, visible, null);
4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public SimpleLocaleKeyFactory(Object obj, ULocale locale, int kind, boolean visible, String name) {
4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            super(visible, name);
494f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.obj = obj;
4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.id = locale.getBaseName();
4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.kind = kind;
4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Returns the service object if kind/locale match.  Service is not used.
5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
503f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public Object create(Key key, ICUService service) {
5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (!(key instanceof LocaleKey)) {
5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return null;
5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
508f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            LocaleKey lkey = (LocaleKey)key;
5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (kind != LocaleKey.KIND_ANY && kind != lkey.kind()) {
5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return null;
5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (!id.equals(lkey.currentID())) {
5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return null;
5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
516f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return obj;
5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
520f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected boolean isSupportedID(String idToCheck) {
5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return this.id.equals(idToCheck);
5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
525f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public void updateVisibleIDs(Map<String, Factory> result) {
5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (visible) {
5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result.put(id, this);
5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result.remove(id);
5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
534f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public String toString() {
5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            StringBuilder buf = new StringBuilder(super.toString());
5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(", id: ");
5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(id);
5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(", kind: ");
5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(kind);
5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return buf.toString();
5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * A LocaleKeyFactory that creates a service based on the ICU locale data.
5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is a base class for most ICU factories.  Subclasses instantiate it
5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with a constructor that takes a bundle name, which determines the supported
5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * IDs.  Subclasses then override handleCreate to create the actual service
5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * object.  The default implementation returns a resource bundle.
5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static class ICUResourceBundleFactory extends LocaleKeyFactory {
5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected final String bundleName;
5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Convenience constructor that uses the main ICU bundle name.
5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public ICUResourceBundleFactory() {
559f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            this(ICUData.ICU_BASE_NAME);
5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * A service factory based on ICU resource data in resources
5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * with the given name.
5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public ICUResourceBundleFactory(String bundleName) {
5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            super(true);
5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.bundleName = bundleName;
5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Return the supported IDs.  This is the set of all locale names for the bundleName.
5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
575f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected Set<String> getSupportedIDs() {
577f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            return ICUResourceBundle.getFullLocaleNameSet(bundleName, loader());
5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Override of superclass method.
5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
583f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public void updateVisibleIDs(Map<String, Factory> result) {
5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          Set<String> visibleIDs = ICUResourceBundle.getAvailableLocaleNameSet(bundleName, loader()); // only visible ids
5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (String id : visibleIDs) {
5872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result.put(id, this);
5882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
5922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Create the service.  The default implementation returns the resource bundle
5932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * for the locale, ignoring kind, and service.
5942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
595f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected Object handleCreate(ULocale loc, int kind, ICUService service) {
5972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return ICUResourceBundle.getBundleInstance(bundleName, loc, loader());
5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        protected ClassLoader loader() {
6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return ClassLoaderUtil.getClassLoader(getClass());
6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
604f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
6052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public String toString() {
6062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return super.toString() + ", bundle: " + bundleName;
6072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return the name of the current fallback locale.  If it has changed since this was
6122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * last accessed, the service cache is cleared.
6132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String validateFallbackLocale() {
6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ULocale loc = ULocale.getDefault();
6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (loc != fallbackLocale) {
6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            synchronized (this) {
6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (loc != fallbackLocale) {
6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    fallbackLocale = loc;
6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    fallbackLocaleName = loc.getBaseName();
6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    clearServiceCache();
6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return fallbackLocaleName;
6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
628f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Key createKey(String id) {
6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale());
6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Key createKey(String id, int kind) {
6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale(), kind);
6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Key createKey(ULocale l, int kind) {
6382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return LocaleKey.createWithCanonical(l, validateFallbackLocale(), kind);
6392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}
641