Merge "Use pre-set timezone display names when default is low quality." into jb-mr2-dev
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 56e6564..5b1e2b5 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -70,7 +70,13 @@
         <item>"Europe/Minsk"</item>
         <!-- Only had GMT as the display string -->
         <item>"Europe/Kaliningrad"</item>
-    </string-array>
+
+        <!-- Brazil -->
+        <!-- Non DST version -->
+        <item>"America/Porto_Velho"</item>
+        <!-- Non DST version -->
+        <item>"America/Belem"</item>
+</string-array>
 
     <!--
         Replacement display strings for time zones. The order should match the entries in
@@ -110,6 +116,37 @@
         <item>"Atlantic Standard Time"</item>
         <item>"Eastern European Time"</item>
         <item>"Kaliningrad Time"</item>
+
+        <!-- Brazil -->
+        <!-- Non DST version of Amazon Standard Time -->
+        <item>"Amazon - Rondônia"</item>
+        <!-- Non DST version of Brasilia Standard Time -->
+        <item>"Brasilia - Pará"</item>
+        </string-array>
+
+    <!--
+        Country codes
+        The order should match the entries in backup_country_names
+        ALWAYS ADD NEW ENTRIES AT THE END. Othewise the entries after the insertion point will
+        not match for languages that didn't get the translations.
+    -->
+    <string-array name="backup_country_codes" translatable="false">
+        <item>"SX"</item>
+        <item>"BQ"</item>
+        <item>"CW"</item>
+        <item>"SS"</item>
     </string-array>
 
-</resources>
\ No newline at end of file
+    <!--
+        Display strings for country names. Used only if framework doesn't have translated
+        country names. The order should match the entries in backup_country_codes
+        ALWAYS ADD NEW ENTRIES AT THE END. Othewise the array will not be the same size until
+        all the translations are available. [CHAR LIMIT=32]
+    -->
+    <string-array name="backup_country_names">
+        <item>"Sint Maarten"</item>
+        <item>"Caribbean Netherlands"</item>
+        <item>"Curaçao"</item>
+        <item>"South Sudan"</item>
+    </string-array>
+</resources>
diff --git a/src/com/android/timezonepicker/TimeZoneData.java b/src/com/android/timezonepicker/TimeZoneData.java
index a0cfa4b..c6eeeaa 100644
--- a/src/com/android/timezonepicker/TimeZoneData.java
+++ b/src/com/android/timezonepicker/TimeZoneData.java
@@ -123,10 +123,9 @@
             }
 
             /*
-             * Dropping non-GMT tzs without a country code. They are not
-             * really needed and they are dups but missing proper
-             * country codes. e.g. WET CET MST7MDT PST8PDT Asia/Khandyga
-             * Asia/Ust-Nera EST
+             * Dropping non-GMT tzs without a country code. They are not really
+             * needed and they are dups but missing proper country codes. e.g.
+             * WET CET MST7MDT PST8PDT Asia/Khandyga Asia/Ust-Nera EST
              */
             if (!tzId.startsWith("Etc/GMT")) {
                 continue;
@@ -170,32 +169,6 @@
 
         // Don't change the order of mTimeZones after this sort
         Collections.sort(mTimeZones);
-        // TimeZoneInfo last = null;
-        // boolean first = true;
-        // for (TimeZoneInfo tz : mTimeZones) {
-        // // All
-        // Log.e("ALL", tz.toString());
-        //
-        // // GMT
-        // String name = tz.mTz.getDisplayName();
-        // if (name.startsWith("GMT") && !tz.mTzId.startsWith("Etc/GMT")) {
-        // Log.e("GMT", tz.toString());
-        // }
-        //
-        // // Dups
-        // if (last != null) {
-        // if (last.compareTo(tz) == 0) {
-        // if (first) {
-        // Log.e("SAME", last.toString());
-        // first = false;
-        // }
-        // Log.e("SAME", tz.toString());
-        // } else {
-        // first = true;
-        // }
-        // }
-        // last = tz;
-        // }
 
         mTimeZonesByCountry = new LinkedHashMap<String, ArrayList<Integer>>();
         mTimeZonesByOffsets = new SparseArray<ArrayList<Integer>>(mHasTimeZonesInHrOffset.length);
@@ -243,6 +216,42 @@
 
             idx++;
         }
+
+        // printTimeZones();
+    }
+
+    private void printTimeZones() {
+        TimeZoneInfo last = null;
+        boolean first = true;
+        for (TimeZoneInfo tz : mTimeZones) {
+            // All
+            if (false) {
+                Log.e("ALL", tz.toString());
+            }
+
+            // GMT
+            if (true) {
+                String name = tz.mTz.getDisplayName();
+                if (name.startsWith("GMT") && !tz.mTzId.startsWith("Etc/GMT")) {
+                    Log.e("GMT", tz.toString());
+                }
+            }
+
+            // Dups
+            if (true && last != null) {
+                if (last.compareTo(tz) == 0) {
+                    if (first) {
+                        Log.e("SAME", last.toString());
+                        first = false;
+                    }
+                    Log.e("SAME", tz.toString());
+                } else {
+                    first = true;
+                }
+            }
+            last = tz;
+        }
+        Log.e(TAG, "Total number of tz's = " + mTimeZones.size());
     }
 
     private void populateDisplayNameOverrides(Resources resources) {
@@ -385,8 +394,7 @@
                     // name
                     String country = mCountryCodeToNameMap.get(countryCode);
                     if (country == null) {
-                        country = new Locale(lang, countryCode)
-                                .getDisplayCountry(Locale.getDefault());
+                        country = getCountryNames(lang, countryCode);
                         mCountryCodeToNameMap.put(countryCode, country);
                     }
 
@@ -456,6 +464,38 @@
         return processedTimeZones;
     }
 
+    @SuppressWarnings("unused")
+    private static Locale mBackupCountryLocale;
+    private static String[] mBackupCountryCodes;
+    private static String[] mBackupCountryNames;
+
+    private String getCountryNames(String lang, String countryCode) {
+        final Locale defaultLocale = Locale.getDefault();
+        String countryDisplayName = new Locale(lang, countryCode).getDisplayCountry(defaultLocale);
+
+        if (!countryCode.equals(countryDisplayName)) {
+            return countryDisplayName;
+        }
+
+        if (mBackupCountryCodes == null || !defaultLocale.equals(mBackupCountryLocale)) {
+            mBackupCountryLocale = defaultLocale;
+            mBackupCountryCodes = mContext.getResources().getStringArray(
+                    R.array.backup_country_codes);
+            mBackupCountryNames = mContext.getResources().getStringArray(
+                    R.array.backup_country_names);
+        }
+
+        int length = Math.min(mBackupCountryCodes.length, mBackupCountryNames.length);
+
+        for (int i = 0; i < length; i++) {
+            if (mBackupCountryCodes[i].equals(countryCode)) {
+                return mBackupCountryNames[i];
+            }
+        }
+
+        return countryCode;
+    }
+
     private int getIdenticalTimeZoneInTheCountry(TimeZoneInfo timeZoneInfo) {
         int idx = 0;
         for (TimeZoneInfo tzi : mTimeZones) {
@@ -472,50 +512,4 @@
         }
         return -1;
     }
-
-    private void printTz() {
-        for (TimeZoneInfo tz : mTimeZones) {
-            Log.e(TAG, "" + tz.toString());
-        }
-
-        Log.e(TAG, "Total number of tz's = " + mTimeZones.size());
-    }
-
-    // void checkForNameDups(TimeZone tz, String country, boolean dls, int
-    // style, int idx,
-    // boolean print) {
-    // if (country == null) {
-    // return;
-    // }
-    // String displayName = tz.getDisplayName(dls, style);
-    //
-    // if (print) {
-    // Log.e(TAG, "" + idx + " " + tz.getID() + " " + country + " ## " +
-    // displayName);
-    // }
-    //
-    // if (tz.useDaylightTime()) {
-    // if (displayName.matches("GMT[+-][0-9][0-9]:[0-9][0-9]")) {
-    // return;
-    // }
-    //
-    // if (displayName.length() == 3 && displayName.charAt(2) == 'T' &&
-    // (displayName.charAt(1) == 'S' || displayName.charAt(1) == 'D')) {
-    // displayName = "" + displayName.charAt(0) + 'T';
-    // } else {
-    // displayName = displayName.replace(" Daylight ",
-    // " ").replace(" Standard ", " ");
-    // }
-    // }
-    //
-    // String tzNameWithCountry = country + " ## " + displayName;
-    // Integer groupId = mCountryPlusTzName2Tzs.get(tzNameWithCountry);
-    // if (groupId == null) {
-    // mCountryPlusTzName2Tzs.put(tzNameWithCountry, idx);
-    // } else if (groupId != idx) {
-    // Log.e(TAG, "Yikes: " + tzNameWithCountry + " matches " + groupId +
-    // " and " + idx);
-    // }
-    // }
-
 }
diff --git a/src/com/android/timezonepicker/TimeZoneFilterTypeAdapter.java b/src/com/android/timezonepicker/TimeZoneFilterTypeAdapter.java
index 4cec7b4..5d0e881 100644
--- a/src/com/android/timezonepicker/TimeZoneFilterTypeAdapter.java
+++ b/src/com/android/timezonepicker/TimeZoneFilterTypeAdapter.java
@@ -256,15 +256,20 @@
             boolean first = true;
             for (String country : mTimeZoneData.mTimeZonesByCountry.keySet()) {
                 // TODO Perf - cache toLowerCase()?
-                if (country != null && country.toLowerCase().startsWith(prefixString)) {
-                    FilterTypeResult r;
-                    if (first) {
-                        r = new FilterTypeResult(true, FILTER_TYPE_COUNTRY, null, 0);
+                if (!TextUtils.isEmpty(country)) {
+                    final String lowerCaseCountry = country.toLowerCase();
+                    if (lowerCaseCountry.startsWith(prefixString)
+                            || (lowerCaseCountry.charAt(0) == prefixString.charAt(0) &&
+                            isStartingInitialsFor(prefixString, lowerCaseCountry))) {
+                        FilterTypeResult r;
+                        if (first) {
+                            r = new FilterTypeResult(true, FILTER_TYPE_COUNTRY, null, 0);
+                            filtered.add(r);
+                            first = false;
+                        }
+                        r = new FilterTypeResult(false, FILTER_TYPE_COUNTRY, country, 0);
                         filtered.add(r);
-                        first = false;
                     }
-                    r = new FilterTypeResult(false, FILTER_TYPE_COUNTRY, country, 0);
-                    filtered.add(r);
                 }
             }
 
@@ -297,6 +302,45 @@
         }
 
         /**
+         * Returns true if the prefixString is an initial for string. Note that
+         * this method will return true even if prefixString does not cover all
+         * the words. Words are separated by non-letters which includes spaces
+         * and symbols).
+         *
+         * For example:
+         * isStartingInitialsFor("UA", "United Arb Emirates") would return true
+         * isStartingInitialsFor("US", "U.S. Virgin Island") would return true
+
+         * @param prefixString
+         * @param string
+         * @return
+         */
+        private boolean isStartingInitialsFor(String prefixString, String string) {
+            final int initialLen = prefixString.length();
+            final int strLen = string.length();
+
+            int initialIdx = 0;
+            boolean wasWordBreak = true;
+            for (int i = 0; i < strLen; i++) {
+                if (!Character.isLetter(string.charAt(i))) {
+                    wasWordBreak = true;
+                    continue;
+                }
+
+                if (wasWordBreak) {
+                    if (prefixString.charAt(initialIdx++) != string.charAt(i)) {
+                        return false;
+                    }
+                    if (initialIdx == initialLen) {
+                        return true;
+                    }
+                    wasWordBreak = false;
+                }
+            }
+            return false;
+        }
+
+        /**
          * @param filtered
          * @param num
          */
diff --git a/src/com/android/timezonepicker/TimeZoneInfo.java b/src/com/android/timezonepicker/TimeZoneInfo.java
index 72ca727..c8d6eed 100644
--- a/src/com/android/timezonepicker/TimeZoneInfo.java
+++ b/src/com/android/timezonepicker/TimeZoneInfo.java
@@ -337,7 +337,11 @@
         }
 
         // Finally diff by display name
+        if (mDisplayName != null && other.mDisplayName != null)
+            return this.mDisplayName.compareTo(other.mDisplayName);
+
         return this.mTz.getDisplayName(Locale.getDefault()).compareTo(
                 other.mTz.getDisplayName(Locale.getDefault()));
+
     }
 }