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) 2011-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.io.IOException; 132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.ObjectInputStream; 142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.Serializable; 152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.lang.ref.WeakReference; 162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.MessageFormat; 172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Collection; 182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.EnumSet; 192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Iterator; 202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.LinkedList; 212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.MissingResourceException; 222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Set; 232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.concurrent.ConcurrentHashMap; 242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.TextTrieMap.ResultHandler; 262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.LocaleDisplayNames; 272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.TimeZoneFormat.TimeType; 282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.TimeZoneNames; 292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.TimeZoneNames.MatchInfo; 302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.TimeZoneNames.NameType; 312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.BasicTimeZone; 322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Freezable; 332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Output; 342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZone; 352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZone.SystemTimeZoneType; 362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZoneTransition; 372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale; 382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/** 402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This class interact with TimeZoneNames and LocaleDisplayNames 412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to format and parse time zone's generic display names. 422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * It is not recommended to use this class directly, instead 431fba789ac68efdd9120a7373f49daef42833e674Neil Fuller * use android.icu.text.TimeZoneFormat. 44836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide Only a subset of ICU is exposed in Android 452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class TimeZoneGenericNames implements Serializable, Freezable<TimeZoneGenericNames> { 472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Note: This class implements Serializable, but we no longer serialize instance of 491fba789ac68efdd9120a7373f49daef42833e674Neil Fuller // TimeZoneGenericNames in ICU 49. ICU 4.8 android.icu.text.TimeZoneFormat used to 502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // serialize TimeZoneGenericNames field. TimeZoneFormat no longer read TimeZoneGenericNames 512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // field, we have to keep TimeZoneGenericNames Serializable. Otherwise it fails to read 522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // (unused) TimeZoneGenericNames serialized data. 532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final long serialVersionUID = 2729910342063468417L; 552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Generic name type enum 582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public enum GenericNameType { 602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller LOCATION ("LONG", "SHORT"), 612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller LONG (), 622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller SHORT (); 632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String[] _fallbackTypeOf; 652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller GenericNameType(String... fallbackTypeOf) { 662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _fallbackTypeOf = fallbackTypeOf; 672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean isFallbackTypeOf(GenericNameType type) { 702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String typeStr = type.toString(); 712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (String t : _fallbackTypeOf) { 722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (t.equals(typeStr)) { 732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Format pattern enum used for composing location and partial location names 822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public enum Pattern { 84f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // The format pattern such as "{0} Time", where {0} is the country or city. 852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller REGION_FORMAT("regionFormat", "({0})"), 862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Note: FALLBACK_REGION_FORMAT is no longer used since ICU 50/CLDR 22.1 882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // The format pattern such as "{1} Time ({0})", where {1} is the country and {0} is a city. 892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller //FALLBACK_REGION_FORMAT("fallbackRegionFormat", "{1} ({0})"), 902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // The format pattern such as "{1} ({0})", where {1} is the metazone, and {0} is the country or city. 922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FALLBACK_FORMAT("fallbackFormat", "{1} ({0})"); 932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String _key; 952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String _defaultVal; 962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Pattern(String key, String defaultVal) { 982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _key = key; 992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _defaultVal = defaultVal; 1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String key() { 1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return _key; 1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String defaultValue() { 1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return _defaultVal; 1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 111f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private final ULocale _locale; 1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private TimeZoneNames _tznames; 1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient volatile boolean _frozen; 1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient String _region; 1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient WeakReference<LocaleDisplayNames> _localeDisplayNamesRef; 1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient MessageFormat[] _patternFormatters; 1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient ConcurrentHashMap<String, String> _genericLocationNamesMap; 1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient ConcurrentHashMap<String, String> _genericPartialLocationNamesMap; 1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient TextTrieMap<NameInfo> _gnamesTrie; 1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient boolean _gnamesTrieFullyLoaded; 1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static Cache GENERIC_NAMES_CACHE = new Cache(); 1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Window size used for DST check for a zone in a metazone (about a half year) 1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final long DST_CHECK_RANGE = 184L*(24*60*60*1000); 1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final NameType[] GENERIC_NON_LOCATION_TYPES = 1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller {NameType.LONG_GENERIC, NameType.SHORT_GENERIC}; 1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Constructs a <code>TimeZoneGenericNames</code> with the given locale 1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and the <code>TimeZoneNames</code>. 1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param locale the locale 1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param tznames the TimeZoneNames 1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeZoneGenericNames(ULocale locale, TimeZoneNames tznames) { 1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _locale = locale; 1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _tznames = tznames; 1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller init(); 1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Private method initializing the instance of <code>TimeZoneGenericName</code>. 1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This method should be called from a constructor and readObject. 1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private void init() { 1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_tznames == null) { 1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _tznames = TimeZoneNames.getInstance(_locale); 1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _genericLocationNamesMap = new ConcurrentHashMap<String, String>(); 1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _genericPartialLocationNamesMap = new ConcurrentHashMap<String, String>(); 1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _gnamesTrie = new TextTrieMap<NameInfo>(true); 1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _gnamesTrieFullyLoaded = false; 1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Preload zone strings for the default time zone 1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZone tz = TimeZone.getDefault(); 1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String tzCanonicalID = ZoneMeta.getCanonicalCLDRID(tz); 1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tzCanonicalID != null) { 1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller loadStrings(tzCanonicalID); 1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Constructs a <code>TimeZoneGenericNames</code> with the given locale. 1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This constructor is private and called from {@link #getInstance(ULocale)}. 1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param locale the locale 1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private TimeZoneGenericNames(ULocale locale) { 1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this(locale, null); 1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The factory method of <code>TimeZoneGenericNames</code>. This static method 1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * returns a frozen instance of cached <code>TimeZoneGenericNames</code>. 1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param locale the locale 1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return A frozen <code>TimeZoneGenericNames</code>. 1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static TimeZoneGenericNames getInstance(ULocale locale) { 1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String key = locale.getBaseName(); 1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return GENERIC_NAMES_CACHE.getInstance(key, locale); 1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns the display name of the time zone for the given name type 1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * at the given date, or null if the display name is not available. 190f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * 1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param tz the time zone 1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param type the generic name type - see {@link GenericNameType} 1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param date the date 1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the display name of the time zone for the given name type 1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * at the given date, or null. 1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getDisplayName(TimeZone tz, GenericNameType type, long date) { 1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String name = null; 1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String tzCanonicalID = null; 2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller switch (type) { 2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case LOCATION: 2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzCanonicalID = ZoneMeta.getCanonicalCLDRID(tz); 2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tzCanonicalID != null) { 2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = getGenericLocationName(tzCanonicalID); 2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case LONG: 2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case SHORT: 2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = formatGenericNonLocationName(tz, type, date); 2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (name == null) { 2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzCanonicalID = ZoneMeta.getCanonicalCLDRID(tz); 2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tzCanonicalID != null) { 2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = getGenericLocationName(tzCanonicalID); 2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return name; 2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns the generic location name for the given canonical time zone ID. 223f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * 2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param canonicalTzID the canonical time zone ID 2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the generic location name for the given canonical time zone ID. 2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getGenericLocationName(String canonicalTzID) { 2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (canonicalTzID == null || canonicalTzID.length() == 0) { 2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String name = _genericLocationNamesMap.get(canonicalTzID); 2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (name != null) { 2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (name.length() == 0) { 2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // empty string to indicate the name is not available 2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return name; 2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Output<Boolean> isPrimary = new Output<Boolean>(); 2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String countryCode = ZoneMeta.getCanonicalCountry(canonicalTzID, isPrimary); 2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (countryCode != null) { 2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (isPrimary.value) { 2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If this is only the single zone in the country, use the country name 2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String country = getLocaleDisplayNames().regionDisplayName(countryCode); 2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = formatPattern(Pattern.REGION_FORMAT, country); 2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If there are multiple zones including this in the country, 2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // use the exemplar city name 2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // getExemplarLocationName should return non-empty String 2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // if the time zone is associated with a location 2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String city = _tznames.getExemplarLocationName(canonicalTzID); 2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = formatPattern(Pattern.REGION_FORMAT, city); 2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (name == null) { 2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _genericLocationNamesMap.putIfAbsent(canonicalTzID.intern(), ""); 2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller synchronized (this) { // we have to sync the name map and the trie 2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller canonicalTzID = canonicalTzID.intern(); 2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String tmp = _genericLocationNamesMap.putIfAbsent(canonicalTzID, name.intern()); 2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tmp == null) { 2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Also put the name info the to trie 266f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert NameInfo info = new NameInfo(canonicalTzID, GenericNameType.LOCATION); 2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _gnamesTrie.put(name, info); 2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = tmp; 2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return name; 2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Sets the pattern string for the pattern type. 2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Note: This method is designed for CLDR ST - not for common use. 2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param patType the pattern type 2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param patStr the pattern string 2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return this object. 2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeZoneGenericNames setFormatPattern(Pattern patType, String patStr) { 2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (isFrozen()) { 2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new UnsupportedOperationException("Attempt to modify frozen object"); 2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Changing pattern will invalidates cached names 2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!_genericLocationNamesMap.isEmpty()) { 2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _genericLocationNamesMap = new ConcurrentHashMap<String, String>(); 2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!_genericPartialLocationNamesMap.isEmpty()) { 2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _genericPartialLocationNamesMap = new ConcurrentHashMap<String, String>(); 2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _gnamesTrie = null; 2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _gnamesTrieFullyLoaded = false; 2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_patternFormatters == null) { 2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _patternFormatters = new MessageFormat[Pattern.values().length]; 3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _patternFormatters[patType.ordinal()] = new MessageFormat(patStr); 3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return this; 3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Private method to get a generic string, with fallback logics involved, 3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * that is, 308f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * 3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 1. If a generic non-location string is available for the zone, return it. 310f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * 2. If a generic non-location string is associated with a meta zone and 3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the zone never use daylight time around the given date, use the standard 3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * string (if available). 3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 3. If a generic non-location string is associated with a meta zone and 3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the offset at the given time is different from the preferred zone for the 3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * current locale, then return the generic partial location string (if available) 3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 4. If a generic non-location string is not available, use generic location 3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * string. 318f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * 3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param tz the requested time zone 3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param date the date 3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param type the generic name type, either LONG or SHORT 3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the name used for a generic name type, which could be the 3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * generic name, or the standard name (if the zone does not observes DST 3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * around the date), or the partial location name. 3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private String formatGenericNonLocationName(TimeZone tz, GenericNameType type, long date) { 3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller assert(type == GenericNameType.LONG || type == GenericNameType.SHORT); 3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String tzID = ZoneMeta.getCanonicalCLDRID(tz); 3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tzID == null) { 3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Try to get a name from time zone first 3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NameType nameType = (type == GenericNameType.LONG) ? NameType.LONG_GENERIC : NameType.SHORT_GENERIC; 3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String name = _tznames.getTimeZoneDisplayName(tzID, nameType); 3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (name != null) { 3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return name; 3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Try meta zone 3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String mzID = _tznames.getMetaZoneID(tzID, date); 3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (mzID != null) { 3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean useStandard = false; 3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] offsets = {0, 0}; 3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tz.getOffset(date, false, offsets); 3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (offsets[1] == 0) { 3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller useStandard = true; 3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Check if the zone actually uses daylight saving time around the time 3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tz instanceof BasicTimeZone) { 3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller BasicTimeZone btz = (BasicTimeZone)tz; 3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneTransition before = btz.getPreviousTransition(date, true); 3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (before != null 3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && (date - before.getTime() < DST_CHECK_RANGE) 3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && before.getFrom().getDSTSavings() != 0) { 3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller useStandard = false; 3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneTransition after = btz.getNextTransition(date, false); 3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (after != null 3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && (after.getTime() - date < DST_CHECK_RANGE) 3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && after.getTo().getDSTSavings() != 0) { 3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller useStandard = false; 3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If not BasicTimeZone... only if the instance is not an ICU's implementation. 3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // We may get a wrong answer in edge case, but it should practically work OK. 3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] tmpOffsets = new int[2]; 3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tz.getOffset(date - DST_CHECK_RANGE, false, tmpOffsets); 3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tmpOffsets[1] != 0) { 3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller useStandard = false; 3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tz.getOffset(date + DST_CHECK_RANGE, false, tmpOffsets); 3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tmpOffsets[1] != 0){ 3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller useStandard = false; 3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (useStandard) { 3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NameType stdNameType = (nameType == NameType.LONG_GENERIC) ? 3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NameType.LONG_STANDARD : NameType.SHORT_STANDARD; 3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String stdName = _tznames.getDisplayName(tzID, stdNameType, date); 3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (stdName != null) { 3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = stdName; 3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // TODO: revisit this issue later 3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // In CLDR, a same display name is used for both generic and standard 3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // for some meta zones in some locales. This looks like a data bugs. 3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // For now, we check if the standard name is different from its generic 3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // name below. 3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String mzGenericName = _tznames.getMetaZoneDisplayName(mzID, nameType); 3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (stdName.equalsIgnoreCase(mzGenericName)) { 3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = null; 3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (name == null) { 4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Get a name from meta zone 4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String mzName = _tznames.getMetaZoneDisplayName(mzID, nameType); 4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (mzName != null) { 4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Check if we need to use a partial location format. 4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // This check is done by comparing offset with the meta zone's 4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // golden zone at the given date. 4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String goldenID = _tznames.getReferenceZoneID(mzID, getTargetRegion()); 4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (goldenID != null && !goldenID.equals(tzID)) { 4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZone goldenZone = TimeZone.getFrozenTimeZone(goldenID); 4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] offsets1 = {0, 0}; 4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Check offset in the golden zone with wall time. 4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // With getOffset(date, false, offsets1), 4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // you may get incorrect results because of time overlap at DST->STD 4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // transition. 4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller goldenZone.getOffset(date + offsets[0] + offsets[1], true, offsets1); 4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (offsets[0] != offsets1[0] || offsets[1] != offsets1[1]) { 4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Now we need to use a partial location format. 4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = getPartialLocationName(tzID, mzID, (nameType == NameType.LONG_GENERIC), mzName); 4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = mzName; 4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = mzName; 4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return name; 4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Private simple pattern formatter used for formatting generic location names 4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and partial location names. We intentionally use JDK MessageFormat 4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * for performance reason. 438f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * 4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param pat the message pattern enum 4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param args the format argument(s) 4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the formatted string 4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private synchronized String formatPattern(Pattern pat, String... args) { 4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_patternFormatters == null) { 4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _patternFormatters = new MessageFormat[Pattern.values().length]; 4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int idx = pat.ordinal(); 4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_patternFormatters[idx] == null) { 4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String patText; 4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ICUResourceBundle bundle = (ICUResourceBundle) ICUResourceBundle.getBundleInstance( 453f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert ICUData.ICU_ZONE_BASE_NAME, _locale); 4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller patText = bundle.getStringWithFallback("zoneStrings/" + pat.key()); 4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } catch (MissingResourceException e) { 4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller patText = pat.defaultValue(); 4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _patternFormatters[idx] = new MessageFormat(patText); 4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return _patternFormatters[idx].format(args); 4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Private method returning LocaleDisplayNames instance for the locale of this 4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * instance. Because LocaleDisplayNames is only used for generic 4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * location formant and partial location format, the LocaleDisplayNames 4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is instantiated lazily. 469f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * 4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the instance of LocaleDisplayNames for the locale of this object. 4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private synchronized LocaleDisplayNames getLocaleDisplayNames() { 4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller LocaleDisplayNames locNames = null; 4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_localeDisplayNamesRef != null) { 4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller locNames = _localeDisplayNamesRef.get(); 4762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (locNames == null) { 4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller locNames = LocaleDisplayNames.getInstance(_locale); 4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _localeDisplayNamesRef = new WeakReference<LocaleDisplayNames>(locNames); 4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return locNames; 4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private synchronized void loadStrings(String tzCanonicalID) { 4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tzCanonicalID == null || tzCanonicalID.length() == 0) { 4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return; 4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // getGenericLocationName() formats a name and put it into the trie 489f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert getGenericLocationName(tzCanonicalID); 4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Generic partial location format 4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Set<String> mzIDs = _tznames.getAvailableMetaZoneIDs(tzCanonicalID); 4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (String mzID : mzIDs) { 4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // if this time zone is not the golden zone of the meta zone, 4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // partial location name (such as "PT (Los Angeles)") might be 4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // available. 4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String goldenID = _tznames.getReferenceZoneID(mzID, getTargetRegion()); 4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!tzCanonicalID.equals(goldenID)) { 4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (NameType genNonLocType : GENERIC_NON_LOCATION_TYPES) { 5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String mzGenName = _tznames.getMetaZoneDisplayName(mzID, genNonLocType); 5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (mzGenName != null) { 5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // getPartialLocationName() formats a name and put it into the trie 5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getPartialLocationName(tzCanonicalID, mzID, (genNonLocType == NameType.LONG_GENERIC), mzGenName); 5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Private method returning the target region. The target regions is determined by 5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the locale of this instance. When a generic name is coming from 5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * a meta zone, this region is used for checking if the time zone 5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is a reference zone of the meta zone. 515f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * 5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the target region 5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private synchronized String getTargetRegion() { 5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_region == null) { 5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _region = _locale.getCountry(); 5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_region.length() == 0) { 5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ULocale tmp = ULocale.addLikelySubtags(_locale); 5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _region = tmp.getCountry(); 5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_region.length() == 0) { 5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _region = "001"; 5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return _region; 5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Private method for formatting partial location names. This format 5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is used when a generic name of a meta zone is available, but the given 5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * time zone is not a reference zone (golden zone) of the meta zone. 536f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * 5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param tzID the canonical time zone ID 5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param mzID the meta zone ID 5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param isLong true when long generic name 5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param mzDisplayName the meta zone generic display name 5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the partial location format string 5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private String getPartialLocationName(String tzID, String mzID, boolean isLong, String mzDisplayName) { 5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String letter = isLong ? "L" : "S"; 5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String key = tzID + "&" + mzID + "#" + letter; 5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String name = _genericPartialLocationNamesMap.get(key); 5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (name != null) { 5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return name; 5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String location = null; 5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String countryCode = ZoneMeta.getCanonicalCountry(tzID); 5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (countryCode != null) { 5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Is this the golden zone for the region? 5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String regionalGolden = _tznames.getReferenceZoneID(mzID, countryCode); 5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tzID.equals(regionalGolden)) { 5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Use country name 5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller location = getLocaleDisplayNames().regionDisplayName(countryCode); 5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Otherwise, use exemplar city name 5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller location = _tznames.getExemplarLocationName(tzID); 5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller location = _tznames.getExemplarLocationName(tzID); 5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (location == null) { 5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // This could happen when the time zone is not associated with a country, 5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // and its ID is not hierarchical, for example, CST6CDT. 5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // We use the canonical ID itself as the location for this case. 5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller location = tzID; 5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = formatPattern(Pattern.FALLBACK_FORMAT, location, mzDisplayName); 5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller synchronized (this) { // we have to sync the name map and the trie 5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String tmp = _genericPartialLocationNamesMap.putIfAbsent(key.intern(), name.intern()); 5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tmp == null) { 575f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert NameInfo info = new NameInfo(tzID.intern(), 576f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert isLong ? GenericNameType.LONG : GenericNameType.SHORT); 5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _gnamesTrie.put(name, info); 5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = tmp; 5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return name; 5832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A private class used for storing the name information in the local trie. 5872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static class NameInfo { 589f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert final String tzID; 590f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert final GenericNameType type; 591f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 592f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert NameInfo(String tzID, GenericNameType type) { 593f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this.tzID = tzID; 594f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this.type = type; 595f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A class used for returning the name search result used by 6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@link TimeZoneGenericNames#find(String, int, EnumSet)}. 6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static class GenericMatchInfo { 603f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert final GenericNameType nameType; 604f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert final String tzID; 605f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert final int matchLength; 606f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert final TimeType timeType; 607f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 608f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private GenericMatchInfo(GenericNameType nameType, String tzID, int matchLength) { 609f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this(nameType, tzID, matchLength, TimeType.UNKNOWN); 610f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 611f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 612f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private GenericMatchInfo(GenericNameType nameType, String tzID, int matchLength, TimeType timeType) { 613f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this.nameType = nameType; 614f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this.tzID = tzID; 615f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this.matchLength = matchLength; 616f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this.timeType = timeType; 617f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public GenericNameType nameType() { 6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return nameType; 6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String tzID() { 6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return tzID; 6252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeType timeType() { 6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return timeType; 6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public int matchLength() { 6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return matchLength; 6332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A private class implementing the search callback interface in 6382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>TextTrieMap</code> for collecting match results. 6392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static class GenericNameSearchHandler implements ResultHandler<NameInfo> { 6412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private EnumSet<GenericNameType> _types; 6422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private Collection<GenericMatchInfo> _matches; 6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private int _maxMatchLen; 6442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller GenericNameSearchHandler(EnumSet<GenericNameType> types) { 6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _types = types; 6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* (non-Javadoc) 6501fba789ac68efdd9120a7373f49daef42833e674Neil Fuller * @see android.icu.impl.TextTrieMap.ResultHandler#handlePrefixMatch(int, java.util.Iterator) 6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 652f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean handlePrefixMatch(int matchLength, Iterator<NameInfo> values) { 6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (values.hasNext()) { 6552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NameInfo info = values.next(); 6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_types != null && !_types.contains(info.type)) { 6572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller continue; 6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 659f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert GenericMatchInfo matchInfo = new GenericMatchInfo(info.type, info.tzID, matchLength); 6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (_matches == null) { 6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _matches = new LinkedList<GenericMatchInfo>(); 6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _matches.add(matchInfo); 6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (matchLength > _maxMatchLen) { 6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _maxMatchLen = matchLength; 6662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns the match results 6732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the match results 6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Collection<GenericMatchInfo> getMatches() { 6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return _matches; 6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns the maximum match length, or 0 if no match was found 6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the maximum match length 6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public int getMaxMatchLen() { 6842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return _maxMatchLen; 6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Resets the match results 6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void resetResults() { 6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _matches = null; 6922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _maxMatchLen = 0; 6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns the best match of time zone display name for the specified types in the 6982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * given text at the given offset. 6992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param text the text 7002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param start the start offset in the text 7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param genericTypes the set of name types. 7022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the best matching name info. 7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public GenericMatchInfo findBestMatch(String text, int start, EnumSet<GenericNameType> genericTypes) { 7052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (text == null || text.length() == 0 || start < 0 || start >= text.length()) { 7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException("bad input text or range"); 7072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller GenericMatchInfo bestMatch = null; 7092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Find matches in the TimeZoneNames first 7112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Collection<MatchInfo> tznamesMatches = findTimeZoneNames(text, start, genericTypes); 7122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tznamesMatches != null) { 7132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller MatchInfo longestMatch = null; 7142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (MatchInfo match : tznamesMatches) { 7152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (longestMatch == null || match.matchLength() > longestMatch.matchLength()) { 7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller longestMatch = match; 7172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (longestMatch != null) { 7202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller bestMatch = createGenericMatchInfo(longestMatch); 7212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (bestMatch.matchLength() == (text.length() - start)) { 7222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Full match 7232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller //return bestMatch; 7242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // TODO Some time zone uses a same name for the long standard name 7262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // and the location name. When the match is a long standard name, 7272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // then we need to check if the name is same with the location name. 7282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // This is probably a data error or a design bug. 7292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller// if (bestMatch.nameType != GenericNameType.LONG || bestMatch.timeType != TimeType.STANDARD) { 7302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller// return bestMatch; 7312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller// } 7322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // TODO The deprecation of commonlyUsed flag introduced the name 7342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // conflict not only for long standard names, but short standard names too. 7352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // These short names (found in zh_Hant) should be gone once we clean 7362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // up CLDR time zone display name data. Once the short name conflict 7372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // problem (with location name) is resolved, we should change the condition 7382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // below back to the original one above. -Yoshito (2011-09-14) 7392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (bestMatch.timeType != TimeType.STANDARD) { 7402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return bestMatch; 7412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Find matches in the local trie 7472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Collection<GenericMatchInfo> localMatches = findLocal(text, start, genericTypes); 7482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (localMatches != null) { 7492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (GenericMatchInfo match : localMatches) { 7502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // TODO See the above TODO. We use match.matchLength() >= bestMatch.matcheLength() 7512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // for the reason described above. 7522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller //if (bestMatch == null || match.matchLength() > bestMatch.matchLength()) { 7532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (bestMatch == null || match.matchLength() >= bestMatch.matchLength()) { 7542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller bestMatch = match; 7552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return bestMatch; 7602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns a collection of time zone display name matches for the specified types in the 7642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * given text at the given offset. 7652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param text the text 7662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param start the start offset in the text 7672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param genericTypes the set of name types. 7682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return A collection of match info. 7692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Collection<GenericMatchInfo> find(String text, int start, EnumSet<GenericNameType> genericTypes) { 7712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (text == null || text.length() == 0 || start < 0 || start >= text.length()) { 7722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException("bad input text or range"); 7732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Find matches in the local trie 7752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Collection<GenericMatchInfo> results = findLocal(text, start, genericTypes); 7762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Also find matches in the TimeZoneNames 7782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Collection<MatchInfo> tznamesMatches = findTimeZoneNames(text, start, genericTypes); 7792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tznamesMatches != null) { 7802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // transform matches and append them to local matches 7812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (MatchInfo match : tznamesMatches) { 7822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (results == null) { 7832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller results = new LinkedList<GenericMatchInfo>(); 7842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller results.add(createGenericMatchInfo(match)); 7862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return results; 7892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 7922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns a <code>GenericMatchInfo</code> for the given <code>MatchInfo</code>. 7932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param matchInfo the MatchInfo 7942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return A GenericMatchInfo 7952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private GenericMatchInfo createGenericMatchInfo(MatchInfo matchInfo) { 7972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller GenericNameType nameType = null; 7982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeType timeType = TimeType.UNKNOWN; 7992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller switch (matchInfo.nameType()) { 8002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case LONG_STANDARD: 8012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nameType = GenericNameType.LONG; 8022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller timeType = TimeType.STANDARD; 8032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 8042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case LONG_GENERIC: 8052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nameType = GenericNameType.LONG; 8062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 8072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case SHORT_STANDARD: 8082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nameType = GenericNameType.SHORT; 8092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller timeType = TimeType.STANDARD; 8102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 8112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case SHORT_GENERIC: 8122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nameType = GenericNameType.SHORT; 8132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 8142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller default: 8152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException("Unexpected MatchInfo name type - " + matchInfo.nameType()); 8162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String tzID = matchInfo.tzID(); 8192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (tzID == null) { 8202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String mzID = matchInfo.mzID(); 8212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller assert(mzID != null); 8222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tzID = _tznames.getReferenceZoneID(mzID, getTargetRegion()); 8232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller assert(tzID != null); 8252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 826f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert GenericMatchInfo gmatch = new GenericMatchInfo(nameType, tzID, matchInfo.matchLength(), timeType); 8272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return gmatch; 8292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns a collection of time zone display name matches for the specified types in the 8332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * given text at the given offset. This method only finds matches from the TimeZoneNames 8342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * used by this object. 8352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param text the text 8362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param start the start offset in the text 8372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param types the set of name types. 8382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return A collection of match info. 8392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private Collection<MatchInfo> findTimeZoneNames(String text, int start, EnumSet<GenericNameType> types) { 8412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Collection<MatchInfo> tznamesMatches = null; 8422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Check if the target name type is really in the TimeZoneNames 8442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller EnumSet<NameType> nameTypes = EnumSet.noneOf(NameType.class); 8452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (types.contains(GenericNameType.LONG)) { 8462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nameTypes.add(NameType.LONG_GENERIC); 8472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nameTypes.add(NameType.LONG_STANDARD); 8482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (types.contains(GenericNameType.SHORT)) { 8502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nameTypes.add(NameType.SHORT_GENERIC); 8512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller nameTypes.add(NameType.SHORT_STANDARD); 8522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 853f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 8542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!nameTypes.isEmpty()) { 8552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Find matches in the TimeZoneNames 8562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller tznamesMatches = _tznames.find(text, start, nameTypes); 8572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return tznamesMatches; 8592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns a collection of time zone display name matches for the specified types in the 8632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * given text at the given offset. This method only finds matches from the local trie, 8642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * that contains 1) generic location names and 2) long/short generic partial location names, 8652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * used by this object. 8662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param text the text 8672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param start the start offset in the text 8682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param types the set of name types. 8692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return A collection of match info. 8702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private synchronized Collection<GenericMatchInfo> findLocal(String text, int start, EnumSet<GenericNameType> types) { 8722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller GenericNameSearchHandler handler = new GenericNameSearchHandler(types); 8732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _gnamesTrie.find(text, start, handler); 8742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (handler.getMaxMatchLen() == (text.length() - start) || _gnamesTrieFullyLoaded) { 8752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // perfect match 8762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return handler.getMatches(); 8772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // All names are not yet loaded into the local trie. 8802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Load all available names into the trie. This could be very heavy. 8812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Set<String> tzIDs = TimeZone.getAvailableIDs(SystemTimeZoneType.CANONICAL, null, null); 8832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (String tzID : tzIDs) { 8842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller loadStrings(tzID); 8852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _gnamesTrieFullyLoaded = true; 8872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // now, try it again 8892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller handler.resetResults(); 8902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _gnamesTrie.find(text, start, handler); 8912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return handler.getMatches(); 8922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>TimeZoneGenericNames</code> cache implementation. 8962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static class Cache extends SoftCache<String, TimeZoneGenericNames, ULocale> { 8982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* (non-Javadoc) 9001fba789ac68efdd9120a7373f49daef42833e674Neil Fuller * @see android.icu.impl.CacheBase#createInstance(java.lang.Object, java.lang.Object) 9012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 9022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 9032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected TimeZoneGenericNames createInstance(String key, ULocale data) { 9042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new TimeZoneGenericNames(data).freeze(); 9052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 906f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 9072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 9102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The custom deserialization method. 9112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This implementation only read locale used by the object. 9122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 9132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 9142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller in.defaultReadObject(); 9152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller init(); 9162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 9202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 921f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean isFrozen() { 9232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return _frozen; 9242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 9282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 929f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeZoneGenericNames freeze() { 9312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller _frozen = true; 9322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return this; 9332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 9372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 938f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public TimeZoneGenericNames cloneAsThawed() { 9402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeZoneGenericNames copy = null; 9412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 9422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller copy = (TimeZoneGenericNames)super.clone(); 9432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller copy._frozen = false; 9442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } catch (Throwable t) { 9452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // This should never happen 9462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return copy; 9482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller} 950