Adds gmt descriptors to tz settings list. Do not merge

This adds the GMT offset to the name of the timezones in the
Calendar's time zone settings. Also fixes bug where gototoday
would be off by several hours when in a home tz.

Change-Id: I4ad92a734eb0c15671c4391586694e8e1539d27d
diff --git a/src/com/android/calendar/CalendarActivity.java b/src/com/android/calendar/CalendarActivity.java
index c261f66..5eb9c45 100644
--- a/src/com/android/calendar/CalendarActivity.java
+++ b/src/com/android/calendar/CalendarActivity.java
@@ -238,6 +238,7 @@
 
     public void goToToday() {
         mSelectedDay.set(System.currentTimeMillis());
+        mSelectedDay.normalize(true);
         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
         view.setSelectedDay(mSelectedDay);
         view.reloadEvents();
diff --git a/src/com/android/calendar/CalendarPreferenceActivity.java b/src/com/android/calendar/CalendarPreferenceActivity.java
index 4213d1a..43e3b07 100644
--- a/src/com/android/calendar/CalendarPreferenceActivity.java
+++ b/src/com/android/calendar/CalendarPreferenceActivity.java
@@ -30,10 +30,6 @@
 import android.preference.PreferenceManager;
 import android.preference.PreferenceScreen;
 import android.preference.RingtonePreference;
-import android.text.format.Time;
-
-import java.util.Locale;
-import java.util.TimeZone;
 
 public class CalendarPreferenceActivity extends PreferenceActivity implements
         OnSharedPreferenceChangeListener, OnPreferenceChangeListener {
@@ -76,8 +72,7 @@
     CheckBoxPreference mUseHomeTZ;
     ListPreference mHomeTZ;
 
-    private StringBuilder mTZSummary = new StringBuilder();
-
+    private static CharSequence[][] mTimezones;
 
     /** Return a properly configured SharedPreferences instance */
     public static SharedPreferences getSharedPreferences(Context context) {
@@ -112,14 +107,13 @@
         mUseHomeTZ.setOnPreferenceChangeListener(this);
         mHomeTZ = (ListPreference) preferenceScreen.findPreference(KEY_HOME_TZ);
         String tz = mHomeTZ.getValue();
-        boolean isDST = (new Time(tz)).isDst != 0;
 
-        TimeZone timeZone = TimeZone.getTimeZone(tz);
-        mTZSummary.setLength(0);
-        mTZSummary.append(mHomeTZ.getEntry()).append(" (")
-                .append(timeZone.getDisplayName(isDST, TimeZone.SHORT, Locale.getDefault()))
-                .append(")");
-        mHomeTZ.setSummary(mTZSummary.toString());
+        if (mTimezones == null) {
+            mTimezones = (new TimezoneAdapter(this, tz)).getAllTimezones();
+        }
+        mHomeTZ.setEntryValues(mTimezones[0]);
+        mHomeTZ.setEntries(mTimezones[1]);
+        mHomeTZ.setSummary(mHomeTZ.getEntry());
         mHomeTZ.setOnPreferenceChangeListener(this);
 
         // If needed, migrate vibration setting from a previous version
@@ -171,14 +165,9 @@
             }
         } else if (preference == mHomeTZ) {
             tz = (String)newValue;
+            // We set the value here so we can read back the entry
             mHomeTZ.setValue(tz);
-            boolean isDST = (new Time(tz)).isDst != 0;
-            TimeZone timeZone = TimeZone.getTimeZone(tz);
-            mTZSummary.setLength(0);
-            mTZSummary.append(mHomeTZ.getEntry()).append(" (")
-                    .append(timeZone.getDisplayName(isDST, TimeZone.SHORT, Locale.getDefault()))
-                    .append(")");
-            mHomeTZ.setSummary(mTZSummary.toString());
+            mHomeTZ.setSummary(mHomeTZ.getEntry());
         } else {
             return false;
         }
diff --git a/src/com/android/calendar/TimezoneAdapter.java b/src/com/android/calendar/TimezoneAdapter.java
index 457cce0..bb10fbc 100644
--- a/src/com/android/calendar/TimezoneAdapter.java
+++ b/src/com/android/calendar/TimezoneAdapter.java
@@ -16,21 +16,20 @@
 
 package com.android.calendar;
 
+import com.android.calendar.TimezoneAdapter.TimezoneRow;
+
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.text.format.DateUtils;
 import android.widget.ArrayAdapter;
 
-import com.android.calendar.TimezoneAdapter.TimezoneRow;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.TimeZone;
 
 /**
@@ -166,9 +165,13 @@
 
     /**
      * Static cache of all known timezones, mapped to their string IDs. This is
-     * lazily-loaded on the first call to {@link #loadFromResources(Resources)}
+     * lazily-loaded on the first call to {@link #loadFromResources(Resources)}.
+     * Loading is called in a synchronized block during initialization of this
+     * class and is based off the resources available to the calling context.
+     * This class should not be used outside of the initial context.
+     * LinkedHashMap is used to preserve ordering.
      */
-    private static Map<String, TimezoneRow> sTimezones;
+    private static LinkedHashMap<String, TimezoneRow> sTimezones;
 
     private Context mContext;
 
@@ -217,7 +220,6 @@
      * @param currentTimezone
      */
     public void showInitialTimezones() {
-        loadFromResources(mContext.getResources());
 
         // we use a linked hash set to guarantee only unique IDs are added, and
         // also to maintain the insertion order of the timezones
@@ -241,21 +243,24 @@
 
         clear();
 
-        TimeZone gmt = TimeZone.getTimeZone("GMT");
-        for (String id : ids) {
-            if (!sTimezones.containsKey(id)) {
-                // a timezone we don't know about, so try to add it...
-                TimeZone newTz = TimeZone.getTimeZone(id);
-                // since TimeZone.getTimeZone actually returns a clone of GMT
-                // when it doesn't recognize the ID, this appears to be the only
-                // reliable way to check to see if the ID is a valid timezone
-                if (!newTz.equals(gmt)) {
-                    sTimezones.put(id, new TimezoneRow(id, newTz.getDisplayName()));
-                } else {
-                    continue;
+        synchronized (TimezoneAdapter.class) {
+            loadFromResources(mContext.getResources());
+            TimeZone gmt = TimeZone.getTimeZone("GMT");
+            for (String id : ids) {
+                if (!sTimezones.containsKey(id)) {
+                    // a timezone we don't know about, so try to add it...
+                    TimeZone newTz = TimeZone.getTimeZone(id);
+                    // since TimeZone.getTimeZone actually returns a clone of GMT
+                    // when it doesn't recognize the ID, this appears to be the only
+                    // reliable way to check to see if the ID is a valid timezone
+                    if (!newTz.equals(gmt)) {
+                        sTimezones.put(id, new TimezoneRow(id, newTz.getDisplayName()));
+                    } else {
+                        continue;
+                    }
                 }
+                add(sTimezones.get(id));
             }
-            add(sTimezones.get(id));
         }
         mShowingAll = false;
     }
@@ -264,7 +269,6 @@
      * Populates this adapter with all known timezones.
      */
     public void showAllTimezones() {
-        loadFromResources(mContext.getResources());
         List<TimezoneRow> timezones = new ArrayList<TimezoneRow>(sTimezones.values());
         Collections.sort(timezones);
         clear();
@@ -314,10 +318,32 @@
         prefs.edit().putString(KEY_RECENT_TIMEZONES, recentsString).commit();
     }
 
-    private static void loadFromResources(Resources resources) {
+    /**
+     * Returns an array of ids/time zones.
+     *
+     * This returns a double indexed array of ids and time zones
+     * for Calendar. It is an inefficient method and shouldn't be
+     * called often, but can be used for one time generation of
+     * this list.
+     *
+     * @return double array of tz ids and tz names
+     */
+    public CharSequence[][] getAllTimezones() {
+        CharSequence[][] timeZones = new CharSequence[2][sTimezones.size()];
+        List<String> ids = new ArrayList<String>(sTimezones.keySet());
+        List<TimezoneRow> timezones = new ArrayList<TimezoneRow>(sTimezones.values());
+        int i = 0;
+        for (TimezoneRow row : timezones) {
+            timeZones[0][i] = ids.get(i);
+            timeZones[1][i++] = row.toString();
+        }
+        return timeZones;
+    }
+
+    private void loadFromResources(Resources resources) {
         if (sTimezones == null) {
-            sTimezones = new HashMap<String, TimezoneRow>(90);
             List<String> ids = Arrays.asList(resources.getStringArray(R.array.timezone_values));
+            sTimezones = new LinkedHashMap<String, TimezoneRow>(ids.size());
             List<String> labels = Arrays.asList(resources.getStringArray(R.array.timezone_labels));
             int i = 0;
             for (String id : ids) {