Merge "Fix for Settings timezone names when boot time is wrong"
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 7b5bfb5..26e8303 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 @@
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 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 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 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 @@
// 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 @@
// 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.
- boolean isLocalZoneId = localZoneIds.contains(olsonId);
- boolean preferLongName = isLocalZoneId && !localLongNamesAreAmbiguous;
- String displayName = getZoneDisplayName(locale, tz, now, preferLongName);
+ for (int i = 0; i < zoneCount; i++) {
+ String olsonId = olsonIdsToDisplay[i];
+ TimeZone tz = timeZones[i];
+ String gmtOffsetString = gmtOffsetStrings[i];
- String gmtOffsetString = getGmtOffsetString(locale, tz, now);
+ boolean isLocalZoneId = localZoneIds.contains(olsonId);
+ 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;
+ }
+
int offsetMillis = tz.getOffset(now.getTime());
Map<String, Object> displayEntry =
createDisplayEntry(tz, gmtOffsetString, displayName, offsetMillis);
@@ -138,30 +167,6 @@
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 @@
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) {