diff options
| -rw-r--r-- | packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java | 114 |
1 files changed, 62 insertions, 52 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java index 7b5bfb5e5dfc..26e8303d2bb8 100644 --- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java +++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java @@ -18,6 +18,7 @@ package com.android.settingslib.datetime; import android.content.Context; import android.content.res.XmlResourceParser; +import android.icu.text.TimeZoneNames; import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; import android.text.TextUtils; @@ -26,20 +27,18 @@ import android.view.View; import com.android.settingslib.R; -import libcore.icu.TimeZoneNames; - import org.xmlpull.v1.XmlPullParserException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; -import java.util.TreeSet; public class ZoneGetter { private static final String TAG = "ZoneGetter"; @@ -56,7 +55,8 @@ public class ZoneGetter { public static String getTimeZoneOffsetAndName(TimeZone tz, Date now) { Locale locale = Locale.getDefault(); String gmtString = getGmtOffsetString(locale, tz, now); - String zoneNameString = getZoneLongName(locale, tz, now); + TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale); + String zoneNameString = getZoneLongName(timeZoneNames, tz, now); if (zoneNameString == null) { return gmtString; } @@ -68,6 +68,7 @@ public class ZoneGetter { public static List<Map<String, Object>> getZonesList(Context context) { final Locale locale = Locale.getDefault(); final Date now = new Date(); + final TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale); // The display name chosen for each zone entry depends on whether the zone is one associated // with the country of the user's chosen locale. For "local" zones we prefer the "long name" @@ -85,25 +86,41 @@ public class ZoneGetter { // selecting the wrong olson ids. // Get the list of olson ids to display to the user. - List<String> olsonIdsToDisplay = readTimezonesToDisplay(context); + List<String> olsonIdsToDisplayList = readTimezonesToDisplay(context); + + // Store the information we are going to need more than once. + final int zoneCount = olsonIdsToDisplayList.size(); + final String[] olsonIdsToDisplay = new String[zoneCount]; + final TimeZone[] timeZones = new TimeZone[zoneCount]; + final String[] gmtOffsetStrings = new String[zoneCount]; + for (int i = 0; i < zoneCount; i++) { + String olsonId = olsonIdsToDisplayList.get(i); + olsonIdsToDisplay[i] = olsonId; + TimeZone tz = TimeZone.getTimeZone(olsonId); + timeZones[i] = tz; + gmtOffsetStrings[i] = getGmtOffsetString(locale, tz, now); + } // Create a lookup of local zone IDs. - Set<String> localZoneIds = new TreeSet<String>(); - for (String olsonId : TimeZoneNames.forLocale(locale)) { + Set<String> localZoneIds = new HashSet<String>(); + for (String olsonId : libcore.icu.TimeZoneNames.forLocale(locale)) { localZoneIds.add(olsonId); } - // Work out whether the long names for the local entries that we would show by default would - // be ambiguous. - Set<String> localZoneNames = new TreeSet<String>(); - boolean localLongNamesAreAmbiguous = false; - for (String olsonId : olsonIdsToDisplay) { + // Work out whether the display names we would show by default would be ambiguous. + Set<String> localZoneNames = new HashSet<String>(); + boolean useExemplarLocationForLocalNames = false; + for (int i = 0; i < zoneCount; i++) { + String olsonId = olsonIdsToDisplay[i]; if (localZoneIds.contains(olsonId)) { - TimeZone tz = TimeZone.getTimeZone(olsonId); - String zoneLongName = getZoneLongName(locale, tz, now); - boolean longNameIsUnique = localZoneNames.add(zoneLongName); - if (!longNameIsUnique) { - localLongNamesAreAmbiguous = true; + TimeZone tz = timeZones[i]; + String displayName = getZoneLongName(timeZoneNames, tz, now); + if (displayName == null) { + displayName = gmtOffsetStrings[i]; + } + boolean nameIsUnique = localZoneNames.add(displayName); + if (!nameIsUnique) { + useExemplarLocationForLocalNames = true; break; } } @@ -111,15 +128,27 @@ public class ZoneGetter { // Generate the list of zone entries to return. List<Map<String, Object>> zones = new ArrayList<Map<String, Object>>(); - for (String olsonId : olsonIdsToDisplay) { - final TimeZone tz = TimeZone.getTimeZone(olsonId); - // Exemplar location display is the default. The only time we intend to display the long - // name is when the olsonId is local AND long names are not ambiguous. + for (int i = 0; i < zoneCount; i++) { + String olsonId = olsonIdsToDisplay[i]; + TimeZone tz = timeZones[i]; + String gmtOffsetString = gmtOffsetStrings[i]; + boolean isLocalZoneId = localZoneIds.contains(olsonId); - boolean preferLongName = isLocalZoneId && !localLongNamesAreAmbiguous; - String displayName = getZoneDisplayName(locale, tz, now, preferLongName); + boolean preferLongName = isLocalZoneId && !useExemplarLocationForLocalNames; + String displayName; + if (preferLongName) { + displayName = getZoneLongName(timeZoneNames, tz, now); + } else { + displayName = timeZoneNames.getExemplarLocationName(tz.getID()); + if (displayName == null || displayName.isEmpty()) { + // getZoneExemplarLocation can return null. Fall back to the long name. + displayName = getZoneLongName(timeZoneNames, tz, now); + } + } + if (displayName == null || displayName.isEmpty()) { + displayName = gmtOffsetString; + } - String gmtOffsetString = getGmtOffsetString(locale, tz, now); int offsetMillis = tz.getOffset(now.getTime()); Map<String, Object> displayEntry = createDisplayEntry(tz, gmtOffsetString, displayName, offsetMillis); @@ -138,30 +167,6 @@ public class ZoneGetter { return map; } - /** - * Returns a name for the specific zone. If {@code preferLongName} is {@code true} then the - * long display name for the timezone will be used, otherwise the exemplar location will be - * preferred. - */ - private static String getZoneDisplayName(Locale locale, TimeZone tz, Date now, - boolean preferLongName) { - String zoneNameString; - if (preferLongName) { - zoneNameString = getZoneLongName(locale, tz, now); - } else { - zoneNameString = getZoneExemplarLocation(locale, tz); - if (zoneNameString == null || zoneNameString.isEmpty()) { - // getZoneExemplarLocation can return null. - zoneNameString = getZoneLongName(locale, tz, now); - } - } - return zoneNameString; - } - - private static String getZoneExemplarLocation(Locale locale, TimeZone tz) { - return TimeZoneNames.getExemplarLocation(locale.toString(), tz.getID()); - } - private static List<String> readTimezonesToDisplay(Context context) { List<String> olsonIds = new ArrayList<String>(); try (XmlResourceParser xrp = context.getResources().getXml(R.xml.timezones)) { @@ -193,10 +198,15 @@ public class ZoneGetter { return olsonIds; } - private static String getZoneLongName(Locale locale, TimeZone tz, Date now) { - boolean daylight = tz.inDaylightTime(now); - // This returns a name if it can, or will fall back to GMT+0X:00 format. - return tz.getDisplayName(daylight, TimeZone.LONG, locale); + /** + * Returns the long name for the timezone for the given locale at the time specified. + * Can return {@code null}. + */ + private static String getZoneLongName(TimeZoneNames names, TimeZone tz, Date now) { + TimeZoneNames.NameType nameType = + tz.inDaylightTime(now) ? TimeZoneNames.NameType.LONG_DAYLIGHT + : TimeZoneNames.NameType.LONG_STANDARD; + return names.getDisplayName(tz.getID(), nameType, now.getTime()); } private static String getGmtOffsetString(Locale locale, TimeZone tz, Date now) { |