1b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan/*
2b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * Copyright (C) 2013 The Android Open Source Project
3b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *
4b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * Licensed under the Apache License, Version 2.0 (the "License");
5b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * you may not use this file except in compliance with the License.
6b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * You may obtain a copy of the License at
7b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *
8b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *      http://www.apache.org/licenses/LICENSE-2.0
9b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan *
10b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * Unless required by applicable law or agreed to in writing, software
11b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * distributed under the License is distributed on an "AS IS" BASIS,
12b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * See the License for the specific language governing permissions and
14b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan * limitations under the License.
15b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan */
16b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
17b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanpackage com.android.timezonepicker;
18b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
19b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.content.Context;
20b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.content.res.AssetManager;
211989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chanimport android.content.res.Resources;
22b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.text.format.DateFormat;
23b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.text.format.DateUtils;
24b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.util.Log;
25b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.util.SparseArray;
26b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
27b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.io.BufferedReader;
28b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.io.IOException;
29b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.io.InputStream;
30b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.io.InputStreamReader;
31b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.ArrayList;
32b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.Collections;
33b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.Date;
34b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.HashMap;
35b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.HashSet;
36b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.LinkedHashMap;
37b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.Locale;
38b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.TimeZone;
39b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
40b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanpublic class TimeZoneData {
41b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final String TAG = "TimeZoneData";
42b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final boolean DEBUG = false;
43b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final int OFFSET_ARRAY_OFFSET = 20;
44b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
4562e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein    private static final String PALESTINE_COUNTRY_CODE = "PS";
4662e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein
4762e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein
48b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    ArrayList<TimeZoneInfo> mTimeZones;
49b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    LinkedHashMap<String, ArrayList<Integer>> mTimeZonesByCountry;
50b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    HashSet<String> mTimeZoneNames = new HashSet<String>();
51b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
52b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private long mTimeMillis;
53b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private HashMap<String, String> mCountryCodeToNameMap = new HashMap<String, String>();
54b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
55b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public String mDefaultTimeZoneId;
56b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public static boolean is24HourFormat;
57b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private TimeZoneInfo mDefaultTimeZoneInfo;
58b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private String mAlternateDefaultTimeZoneId;
59b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private String mDefaultTimeZoneCountry;
601989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan    private HashMap<String, TimeZoneInfo> mTimeZonesById;
611989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan    private boolean[] mHasTimeZonesInHrOffset = new boolean[40];
621989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan    SparseArray<ArrayList<Integer>> mTimeZonesByOffsets;
631989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan    private Context mContext;
6462e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein    private String mPalestineDisplayName;
65b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
66b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public TimeZoneData(Context context, String defaultTimeZoneId, long timeMillis) {
671989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        mContext = context;
68b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        is24HourFormat = TimeZoneInfo.is24HourFormat = DateFormat.is24HourFormat(context);
69b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mDefaultTimeZoneId = mAlternateDefaultTimeZoneId = defaultTimeZoneId;
70b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        long now = System.currentTimeMillis();
71b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
72b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (timeMillis == 0) {
73b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mTimeMillis = now;
74b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } else {
75b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mTimeMillis = timeMillis;
76b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
7762e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein
7862e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein        mPalestineDisplayName = context.getResources().getString(R.string.palestine_display_name);
7962e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein
80b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        loadTzs(context);
811989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan
82b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        Log.i(TAG, "Time to load time zones (ms): " + (System.currentTimeMillis() - now));
83b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
84b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // now = System.currentTimeMillis();
85b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // printTz();
86b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // Log.i(TAG, "Time to print time zones (ms): " +
87b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // (System.currentTimeMillis() - now));
88b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
89b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
90b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public void setTime(long timeMillis) {
91b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTimeMillis = timeMillis;
92b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
93b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
94b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public TimeZoneInfo get(int position) {
95b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mTimeZones.get(position);
96b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
97b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
98b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int size() {
99b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mTimeZones.size();
100b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
101b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
102b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int getDefaultTimeZoneIndex() {
103b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mTimeZones.indexOf(mDefaultTimeZoneInfo);
104b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
105b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
106b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // TODO speed this up
107b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int findIndexByTimeZoneIdSlow(String timeZoneId) {
108b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int idx = 0;
109b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        for (TimeZoneInfo tzi : mTimeZones) {
110b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (timeZoneId.equals(tzi.mTzId)) {
111b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                return idx;
112b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
113b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            idx++;
114b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
115b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return -1;
116b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
117b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
118b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    void loadTzs(Context context) {
119b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTimeZones = new ArrayList<TimeZoneInfo>();
120b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        HashSet<String> processedTimeZones = loadTzsInZoneTab(context);
121b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        String[] tzIds = TimeZone.getAvailableIDs();
122b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
123b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (DEBUG) {
124b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            Log.e(TAG, "Available time zones: " + tzIds.length);
125b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
126b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
127b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        for (String tzId : tzIds) {
128b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (processedTimeZones.contains(tzId)) {
129b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                continue;
130b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
131b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
1321989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            /*
1333d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan             * Dropping non-GMT tzs without a country code. They are not really
1343d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan             * needed and they are dups but missing proper country codes. e.g.
1353d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan             * WET CET MST7MDT PST8PDT Asia/Khandyga Asia/Ust-Nera EST
1361989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan             */
1371989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            if (!tzId.startsWith("Etc/GMT")) {
1381989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                continue;
1391989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            }
1401989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan
141b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            final TimeZone tz = TimeZone.getTimeZone(tzId);
142b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (tz == null) {
143b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                Log.e(TAG, "Timezone not found: " + tzId);
144b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                continue;
145b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
146b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
147b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            TimeZoneInfo tzInfo = new TimeZoneInfo(tz, null);
148b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
149b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (getIdenticalTimeZoneInTheCountry(tzInfo) == -1) {
150b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (DEBUG) {
151b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    Log.e(TAG, "# Adding time zone from getAvailId: " + tzInfo.toString());
152b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
153b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                mTimeZones.add(tzInfo);
154b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            } else {
155b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (DEBUG) {
156b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    Log.e(TAG,
157b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            "# Dropping identical time zone from getAvailId: " + tzInfo.toString());
158b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
159b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                continue;
160b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
161b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            //
162b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // TODO check for dups
163b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // checkForNameDups(tz, tzInfo.mCountry, false /* dls */,
164b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // TimeZone.SHORT, groupIdx, !found);
165b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // checkForNameDups(tz, tzInfo.mCountry, false /* dls */,
166b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // TimeZone.LONG, groupIdx, !found);
167b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // if (tz.useDaylightTime()) {
168b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // checkForNameDups(tz, tzInfo.mCountry, true /* dls */,
169b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // TimeZone.SHORT, groupIdx,
170b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // !found);
171b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // checkForNameDups(tz, tzInfo.mCountry, true /* dls */,
172b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // TimeZone.LONG, groupIdx,
173b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // !found);
174b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // }
175b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
176b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
177b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        // Don't change the order of mTimeZones after this sort
178b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        Collections.sort(mTimeZones);
179b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
180b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTimeZonesByCountry = new LinkedHashMap<String, ArrayList<Integer>>();
181b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTimeZonesByOffsets = new SparseArray<ArrayList<Integer>>(mHasTimeZonesInHrOffset.length);
1821989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        mTimeZonesById = new HashMap<String, TimeZoneInfo>(mTimeZones.size());
1831989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        for (TimeZoneInfo tz : mTimeZones) {
1841989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            // /////////////////////
1851989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            // Lookup map for id -> tz
1861989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            mTimeZonesById.put(tz.mTzId, tz);
1871989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        }
1881989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        populateDisplayNameOverrides(mContext.getResources());
189b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
190b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        Date date = new Date(mTimeMillis);
191b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        Locale defaultLocal = Locale.getDefault();
192b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
193b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int idx = 0;
194b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        for (TimeZoneInfo tz : mTimeZones) {
1951989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            // /////////////////////
1961989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            // Populate display name
1971989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            if (tz.mDisplayName == null) {
1981989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                tz.mDisplayName = tz.mTz.getDisplayName(tz.mTz.inDaylightTime(date),
1991989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                        TimeZone.LONG, defaultLocal);
2001989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            }
201b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
202b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // /////////////////////
203b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // Grouping tz's by country for search by country
204b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            ArrayList<Integer> group = mTimeZonesByCountry.get(tz.mCountry);
205b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (group == null) {
206b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                group = new ArrayList<Integer>();
207b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                mTimeZonesByCountry.put(tz.mCountry, group);
208b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
209b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
210b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            group.add(idx);
211b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
212b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // /////////////////////
213b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // Grouping tz's by GMT offsets
214b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            indexByOffsets(idx, tz);
215b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
216b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            // Skip all the GMT+xx:xx style display names from search
217b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (!tz.mDisplayName.endsWith(":00")) {
218b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                mTimeZoneNames.add(tz.mDisplayName);
219b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            } else if (DEBUG) {
220b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                Log.e(TAG, "# Hiding from pretty name search: " +
221b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        tz.mDisplayName);
222b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
223b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
224b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            idx++;
225b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
2263d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan
2273d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan        // printTimeZones();
2283d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan    }
2293d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan
2303d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan    private void printTimeZones() {
2313d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan        TimeZoneInfo last = null;
2323d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan        boolean first = true;
2333d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan        for (TimeZoneInfo tz : mTimeZones) {
2343d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            // All
2353d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            if (false) {
2363d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                Log.e("ALL", tz.toString());
2373d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            }
2383d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan
2393d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            // GMT
2403d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            if (true) {
2413d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                String name = tz.mTz.getDisplayName();
2423d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                if (name.startsWith("GMT") && !tz.mTzId.startsWith("Etc/GMT")) {
2433d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    Log.e("GMT", tz.toString());
2443d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                }
2453d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            }
2463d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan
2473d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            // Dups
2483d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            if (true && last != null) {
2493d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                if (last.compareTo(tz) == 0) {
2503d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    if (first) {
2513d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                        Log.e("SAME", last.toString());
2523d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                        first = false;
2533d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    }
2543d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    Log.e("SAME", tz.toString());
2553d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                } else {
2563d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                    first = true;
2573d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan                }
2583d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            }
2593d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan            last = tz;
2603d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan        }
2613d4445bb2a85048a735f21f7ec3ee9f9af6cee22Michael Chan        Log.e(TAG, "Total number of tz's = " + mTimeZones.size());
262b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
263b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
2641989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan    private void populateDisplayNameOverrides(Resources resources) {
2651989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        String[] ids = resources.getStringArray(R.array.timezone_rename_ids);
2661989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        String[] labels = resources.getStringArray(R.array.timezone_rename_labels);
2671989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan
2681989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        int length = ids.length;
2691989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        if (ids.length != labels.length) {
2701989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            Log.e(TAG, "timezone_rename_ids len=" + ids.length + " timezone_rename_labels len="
2711989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                    + labels.length);
2721989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            length = Math.min(ids.length, labels.length);
2731989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        }
2741989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan
2751989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        for (int i = 0; i < length; i++) {
2761989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan            TimeZoneInfo tzi = mTimeZonesById.get(ids[i]);
27796e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein            if (tzi != null) {
27896e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein                tzi.mDisplayName = labels[i];
27996e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein            } else {
28096e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein                Log.e(TAG, "Could not find timezone with label: "+labels[i]);
28196e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein            }
2821989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan        }
2831989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan    }
284b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
285b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public boolean hasTimeZonesInHrOffset(int offsetHr) {
286b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int index = OFFSET_ARRAY_OFFSET + offsetHr;
287b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (index >= mHasTimeZonesInHrOffset.length || index < 0) {
288b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            return false;
289b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
290b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mHasTimeZonesInHrOffset[index];
291b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
292b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
293b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private void indexByOffsets(int idx, TimeZoneInfo tzi) {
294b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int offsetMillis = tzi.getNowOffsetMillis();
295b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int index = OFFSET_ARRAY_OFFSET + (int) (offsetMillis / DateUtils.HOUR_IN_MILLIS);
296b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mHasTimeZonesInHrOffset[index] = true;
297b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
298b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        ArrayList<Integer> group = mTimeZonesByOffsets.get(index);
299b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (group == null) {
300b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            group = new ArrayList<Integer>();
301b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            mTimeZonesByOffsets.put(index, group);
302b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
303b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        group.add(idx);
304b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
305b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
306b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public ArrayList<Integer> getTimeZonesByOffset(int offsetHr) {
307b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int index = OFFSET_ARRAY_OFFSET + offsetHr;
308b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (index >= mHasTimeZonesInHrOffset.length || index < 0) {
309b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            return null;
310b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
311b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mTimeZonesByOffsets.get(index);
312b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
313b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
314b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private HashSet<String> loadTzsInZoneTab(Context context) {
315b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        HashSet<String> processedTimeZones = new HashSet<String>();
316b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        AssetManager am = context.getAssets();
317b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        InputStream is = null;
318b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
319b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        /*
320b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * The 'backward' file contain mappings between new and old time zone
321b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * ids. We will explicitly ignore the old ones.
322b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         */
323b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        try {
324b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            is = am.open("backward");
325b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
326b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            String line;
327b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
328b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            while ((line = reader.readLine()) != null) {
329b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                // Skip comment lines
330b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (!line.startsWith("#") && line.length() > 0) {
331b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // 0: "Link"
332b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // 1: New tz id
333b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // Last: Old tz id
334b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    String[] fields = line.split("\t+");
335b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    String newTzId = fields[1];
336b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    String oldTzId = fields[fields.length - 1];
337b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
338b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    final TimeZone tz = TimeZone.getTimeZone(newTzId);
339b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (tz == null) {
340b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        Log.e(TAG, "Timezone not found: " + newTzId);
341b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        continue;
342b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
343b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
344b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    processedTimeZones.add(oldTzId);
345b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
346b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (DEBUG) {
347b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        Log.e(TAG, "# Dropping identical time zone from backward: " + oldTzId);
348b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
349b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
350b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // Remember the cooler/newer time zone id
351b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (mDefaultTimeZoneId != null && mDefaultTimeZoneId.equals(oldTzId)) {
352b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        mAlternateDefaultTimeZoneId = newTzId;
353b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
354b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
355b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
356b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } catch (IOException ex) {
357b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            Log.e(TAG, "Failed to read 'backward' file.");
358b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } finally {
359b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            try {
360b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (is != null) {
361b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    is.close();
362b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
363b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            } catch (IOException ignored) {
364b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
365b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
366b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
367b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        /*
368b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * zone.tab contains a list of time zones and country code. They are
369b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * "sorted first by country, then an order within the country that (1)
370b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * makes some geographical sense, and (2) puts the most populous zones
371b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         * first, where that does not contradict (1)."
372b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan         */
373b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        try {
374b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            String lang = Locale.getDefault().getLanguage();
375b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            is = am.open("zone.tab");
376b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
377b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            String line;
378b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            while ((line = reader.readLine()) != null) {
379b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (!line.startsWith("#")) { // Skip comment lines
380b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // 0: country code
381b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // 1: coordinates
382b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // 2: time zone id
383b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // 3: comments
384b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    final String[] fields = line.split("\t");
385b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    final String timeZoneId = fields[2];
386b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    final String countryCode = fields[0];
387b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    final TimeZone tz = TimeZone.getTimeZone(timeZoneId);
388b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (tz == null) {
389b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        Log.e(TAG, "Timezone not found: " + timeZoneId);
390b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        continue;
391b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
392b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
3931989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                    /*
3941989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                     * Dropping non-GMT tzs without a country code. They are not
3951989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                     * really needed and they are dups but missing proper
3961989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                     * country codes. e.g. WET CET MST7MDT PST8PDT Asia/Khandyga
3971989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                     * Asia/Ust-Nera EST
3981989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                     */
3991989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                    if (countryCode == null && !timeZoneId.startsWith("Etc/GMT")) {
4001989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                        processedTimeZones.add(timeZoneId);
4011989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                        continue;
4021989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                    }
4031989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan
404b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // Remember the mapping between the country code and display
405b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // name
4061989c63ae3f98b5088e27564cd397ef5e8affaeaMichael Chan                    String country = mCountryCodeToNameMap.get(countryCode);
407b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (country == null) {
408b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan                        country = getCountryNames(lang, countryCode);
409b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        mCountryCodeToNameMap.put(countryCode, country);
410b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
411b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
412b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // TODO Don't like this here but need to get the country of
413b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // the default tz.
414b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
415b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // Find the country of the default tz
416b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (mDefaultTimeZoneId != null && mDefaultTimeZoneCountry == null
417b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            && timeZoneId.equals(mAlternateDefaultTimeZoneId)) {
418b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        mDefaultTimeZoneCountry = country;
419b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        TimeZone defaultTz = TimeZone.getTimeZone(mDefaultTimeZoneId);
420b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        if (defaultTz != null) {
421b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            mDefaultTimeZoneInfo = new TimeZoneInfo(defaultTz, country);
422b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
423b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            int tzToOverride = getIdenticalTimeZoneInTheCountry(mDefaultTimeZoneInfo);
424b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            if (tzToOverride == -1) {
425b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                if (DEBUG) {
426b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                    Log.e(TAG, "Adding default time zone: "
427b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                            + mDefaultTimeZoneInfo.toString());
428b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                }
429b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                mTimeZones.add(mDefaultTimeZoneInfo);
430b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            } else {
431b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                mTimeZones.add(tzToOverride, mDefaultTimeZoneInfo);
432b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                if (DEBUG) {
433b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                    TimeZoneInfo tzInfoToOverride = mTimeZones.get(tzToOverride);
434b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                    String tzIdToOverride = tzInfoToOverride.mTzId;
435b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                    Log.e(TAG, "Replaced by default tz: "
436b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                            + tzInfoToOverride.toString());
437b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                    Log.e(TAG, "Adding default time zone: "
438b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                            + mDefaultTimeZoneInfo.toString());
439b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                }
440b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            }
441b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        }
442b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
443b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
444b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // Add to the list of time zones if the time zone is unique
445b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    // in the given country.
446b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    TimeZoneInfo timeZoneInfo = new TimeZoneInfo(tz, country);
447b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    int identicalTzIdx = getIdenticalTimeZoneInTheCountry(timeZoneInfo);
448b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (identicalTzIdx == -1) {
449b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        if (DEBUG) {
450b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            Log.e(TAG, "# Adding time zone: " + timeZoneId + " ## " +
451b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                    tz.getDisplayName());
452b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        }
453b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        mTimeZones.add(timeZoneInfo);
454b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    } else {
455b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        if (DEBUG) {
456b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            Log.e(TAG, "# Dropping identical time zone: " + timeZoneId + " ## " +
457b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                    tz.getDisplayName());
458b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        }
459b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
460b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    processedTimeZones.add(timeZoneId);
461b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
462b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
463b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
464b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } catch (IOException ex) {
465b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            Log.e(TAG, "Failed to read 'zone.tab'.");
466b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } finally {
467b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            try {
468b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (is != null) {
469b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    is.close();
470b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
471b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            } catch (IOException ignored) {
472b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
473b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
474b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
475b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return processedTimeZones;
476b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
477b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
478b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan    private static Locale mBackupCountryLocale;
479b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan    private static String[] mBackupCountryCodes;
480b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan    private static String[] mBackupCountryNames;
481b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan
482b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan    private String getCountryNames(String lang, String countryCode) {
483b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan        final Locale defaultLocale = Locale.getDefault();
48462e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein        String countryDisplayName;
48562e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein        if (PALESTINE_COUNTRY_CODE.equalsIgnoreCase(countryCode)) {
48662e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein            countryDisplayName = mPalestineDisplayName;
48762e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein        } else {
48862e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein            countryDisplayName = new Locale(lang, countryCode).getDisplayCountry(defaultLocale);
48962e91b1a6e5decfbe7206a381fed5ff9bb08785bSam Blitzstein        }
490b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan
491b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan        if (!countryCode.equals(countryDisplayName)) {
492b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan            return countryDisplayName;
493b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan        }
494b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan
495b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan        if (mBackupCountryCodes == null || !defaultLocale.equals(mBackupCountryLocale)) {
496b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan            mBackupCountryLocale = defaultLocale;
497b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan            mBackupCountryCodes = mContext.getResources().getStringArray(
498b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan                    R.array.backup_country_codes);
499b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan            mBackupCountryNames = mContext.getResources().getStringArray(
500b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan                    R.array.backup_country_names);
501b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan        }
502b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan
503b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan        int length = Math.min(mBackupCountryCodes.length, mBackupCountryNames.length);
504b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan
505b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan        for (int i = 0; i < length; i++) {
506b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan            if (mBackupCountryCodes[i].equals(countryCode)) {
507b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan                return mBackupCountryNames[i];
508b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan            }
509b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan        }
510b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan
511b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan        return countryCode;
512b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan    }
513b506b1dddd4007997bbe6773cb0ebced27ba96dfMichael Chan
514b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private int getIdenticalTimeZoneInTheCountry(TimeZoneInfo timeZoneInfo) {
515b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int idx = 0;
516b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        for (TimeZoneInfo tzi : mTimeZones) {
517b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            if (tzi.hasSameRules(timeZoneInfo)) {
518b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (tzi.mCountry == null) {
519b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    if (timeZoneInfo.mCountry == null) {
520b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        return idx;
521b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
522b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                } else if (tzi.mCountry.equals(timeZoneInfo.mCountry)) {
523b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    return idx;
524b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
525b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
526b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            ++idx;
527b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
528b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return -1;
529b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
530b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan}
531