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.SharedPreferences;
21b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.text.TextUtils;
22b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.util.Log;
23b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.view.LayoutInflater;
24b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.view.View;
25b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.view.ViewGroup;
26b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chanimport android.widget.AdapterView;
27b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chanimport android.widget.AdapterView.OnItemClickListener;
28b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.BaseAdapter;
29b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport android.widget.TextView;
30b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
31b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport com.android.timezonepicker.TimeZoneFilterTypeAdapter.OnSetFilterListener;
32b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport com.android.timezonepicker.TimeZonePickerView.OnTimeZoneSetListener;
33b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
34b1b7080deea42aa533c3757b585cf765c6b76732Michael Chanimport java.util.ArrayList;
351db8933b4e7e0190f59344c86e92d56607658089Michael Chanimport java.util.Iterator;
36143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chanimport java.util.LinkedHashSet;
37b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
38b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chanpublic class TimeZoneResultAdapter extends BaseAdapter implements OnItemClickListener,
39b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        OnSetFilterListener {
40b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final String TAG = "TimeZoneResultAdapter";
41a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    private static final boolean DEBUG = false;
42b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final int VIEW_TAG_TIME_ZONE = R.id.time_zone;
4396e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein    private static final int EMPTY_INDEX = -100;
44b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
45b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    /** SharedPref name and key for recent time zones */
46b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
47b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final String KEY_RECENT_TIMEZONES = "preferences_recent_timezones";
48b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
49a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    private int mLastFilterType;
50a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    private String mLastFilterString;
51a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    private int mLastFilterTime;
52a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
53a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    private boolean mHasResults = false;
54a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
55b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    /**
56b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * The delimiter we use when serializing recent timezones to shared
57b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * preferences
58b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     */
59b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final String RECENT_TIMEZONES_DELIMITER = ",";
60b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
61b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    /** The maximum number of recent timezones to save */
62b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private static final int MAX_RECENT_TIMEZONES = 3;
63b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
64b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    static class ViewHolder {
65b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        TextView timeZone;
66b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        TextView timeOffset;
67b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        TextView location;
68b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
69b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        static void setupViewHolder(View v) {
70b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            ViewHolder vh = new ViewHolder();
71b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            vh.timeZone = (TextView) v.findViewById(R.id.time_zone);
72b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            vh.timeOffset = (TextView) v.findViewById(R.id.time_offset);
73b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            vh.location = (TextView) v.findViewById(R.id.location);
74b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            v.setTag(vh);
75b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
76b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
77b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
78b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private Context mContext;
79b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private LayoutInflater mInflater;
80b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
81b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private OnTimeZoneSetListener mTimeZoneSetListener;
82b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private TimeZoneData mTimeZoneData;
83b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
84b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private int[] mFilteredTimeZoneIndices;
85b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    private int mFilteredTimeZoneLength = 0;
86b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
87b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public TimeZoneResultAdapter(Context context, TimeZoneData tzd,
88b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            com.android.timezonepicker.TimeZonePickerView.OnTimeZoneSetListener l) {
89b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        super();
90b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
91b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mContext = context;
92b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTimeZoneData = tzd;
93b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mTimeZoneSetListener = l;
94b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
95b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
96b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
97b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mFilteredTimeZoneIndices = new int[mTimeZoneData.size()];
98b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
99b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        onSetFilter(TimeZoneFilterTypeAdapter.FILTER_TYPE_NONE, null, 0);
100b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
101b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
102a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public boolean hasResults() {
103a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        return mHasResults;
104a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
105a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
106a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public int getLastFilterType() {
107a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        return mLastFilterType;
108a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
109a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
110a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public String getLastFilterString() {
111a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        return mLastFilterString;
112a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
113a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
114a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    public int getLastFilterTime() {
115a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        return mLastFilterTime;
116a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung    }
117a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
118b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    // Implements OnSetFilterListener
119b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
120b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public void onSetFilter(int filterType, String str, int time) {
121a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        if (DEBUG) {
122a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung            Log.d(TAG, "onSetFilter: " + filterType + " [" + str + "] " + time);
123a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        }
124a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
125a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mLastFilterType = filterType;
126a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mLastFilterString = str;
127a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mLastFilterTime = time;
128b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
129b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        mFilteredTimeZoneLength = 0;
130b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        int idx = 0;
131b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
132b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        switch (filterType) {
133b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            case TimeZoneFilterTypeAdapter.FILTER_TYPE_EMPTY:
13496e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein                mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = EMPTY_INDEX;
135b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                break;
136b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            case TimeZoneFilterTypeAdapter.FILTER_TYPE_NONE:
137b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                // Show the default/current value first
138b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                int defaultTzIndex = mTimeZoneData.getDefaultTimeZoneIndex();
139b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (defaultTzIndex != -1) {
140b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = defaultTzIndex;
141b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
142b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
143b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                // Show the recent selections
144b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFS_NAME,
145b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        Context.MODE_PRIVATE);
146b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                String recentsString = prefs.getString(KEY_RECENT_TIMEZONES, null);
147b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (!TextUtils.isEmpty(recentsString)) {
148b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    String[] recents = recentsString.split(RECENT_TIMEZONES_DELIMITER);
149b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    for (int i = recents.length - 1; i >= 0; i--) {
150b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        if (!TextUtils.isEmpty(recents[i])
151b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                && !recents[i].equals(mTimeZoneData.mDefaultTimeZoneId)) {
152b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            int index = mTimeZoneData.findIndexByTimeZoneIdSlow(recents[i]);
153b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            if (index != -1) {
154b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                                mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = index;
155b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                            }
156b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        }
157b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
158b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
159b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
160b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                break;
161b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            case TimeZoneFilterTypeAdapter.FILTER_TYPE_GMT:
162b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                ArrayList<Integer> indices = mTimeZoneData.getTimeZonesByOffset(time);
163b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (indices != null) {
164b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    for (Integer i : indices) {
165b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = i;
166b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
167b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
168b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                break;
169b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            case TimeZoneFilterTypeAdapter.FILTER_TYPE_COUNTRY:
170b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                ArrayList<Integer> tzIds = mTimeZoneData.mTimeZonesByCountry.get(str);
171b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (tzIds != null) {
172b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    for (Integer tzi : tzIds) {
173b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = tzi;
174b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    }
175b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
176b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                break;
177b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            case TimeZoneFilterTypeAdapter.FILTER_TYPE_STATE:
178b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                // TODO Filter by state
179b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                break;
180b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            default:
181b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                throw new IllegalArgumentException();
182b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
183a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung        mHasResults = mFilteredTimeZoneLength > 0;
184a8dd2dfa92587e5fc11e6c24da91be9e7bf3afb7James Kung
185b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        notifyDataSetChanged();
186b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
187b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
188b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    /**
189b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * Saves the given timezone ID as a recent timezone under shared
190b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * preferences. If there are already the maximum number of recent timezones
191b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * saved, it will remove the oldest and append this one.
192b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     *
193b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * @param id the ID of the timezone to save
194b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     * @see {@link #MAX_RECENT_TIMEZONES}
195b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan     */
196b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public void saveRecentTimezone(String id) {
197b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFS_NAME,
198b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                Context.MODE_PRIVATE);
199b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        String recentsString = prefs.getString(KEY_RECENT_TIMEZONES, null);
200b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (recentsString == null) {
201b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            recentsString = id;
202b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } else {
203143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan            // De-dup
204143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan            LinkedHashSet<String> recents = new LinkedHashSet<String>();
205143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan            for(String tzId : recentsString.split(RECENT_TIMEZONES_DELIMITER)) {
206143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan                if (!recents.contains(tzId) && !id.equals(tzId)) {
207143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan                    recents.add(tzId);
208b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
209b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
210b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
2111db8933b4e7e0190f59344c86e92d56607658089Michael Chan            Iterator<String> it = recents.iterator();
212b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            while (recents.size() >= MAX_RECENT_TIMEZONES) {
2131db8933b4e7e0190f59344c86e92d56607658089Michael Chan                if (!it.hasNext()) {
2141db8933b4e7e0190f59344c86e92d56607658089Michael Chan                    break;
2151db8933b4e7e0190f59344c86e92d56607658089Michael Chan                }
2161db8933b4e7e0190f59344c86e92d56607658089Michael Chan                it.next();
2171db8933b4e7e0190f59344c86e92d56607658089Michael Chan                it.remove();
218b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
219b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            recents.add(id);
220b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
221b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            StringBuilder builder = new StringBuilder();
222b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            boolean first = true;
223b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            for (String recent : recents) {
224b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                if (first) {
225b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    first = false;
226b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                } else {
227b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                    builder.append(RECENT_TIMEZONES_DELIMITER);
228b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                }
229b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan                builder.append(recent);
230b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            }
231b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            recentsString = builder.toString();
232b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
233b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
234b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        prefs.edit().putString(KEY_RECENT_TIMEZONES, recentsString).apply();
235b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
236b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
237b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
238b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public int getCount() {
239b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mFilteredTimeZoneLength;
240b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
241b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
242b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
243215ec1009ae3b52ed491fde7b2aa0a13dd4387beMichael Chan    public Object getItem(int position) {
244b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (position < 0 || position >= mFilteredTimeZoneLength) {
245b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            return null;
246b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
247b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
248b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
249b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
250b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
251b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
252b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chan    public boolean areAllItemsEnabled() {
253b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chan        return false;
254b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chan    }
255b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chan
256b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chan    @Override
257215ec1009ae3b52ed491fde7b2aa0a13dd4387beMichael Chan    public boolean isEnabled(int position) {
258215ec1009ae3b52ed491fde7b2aa0a13dd4387beMichael Chan        return mFilteredTimeZoneIndices[position] >= 0;
259215ec1009ae3b52ed491fde7b2aa0a13dd4387beMichael Chan    }
260215ec1009ae3b52ed491fde7b2aa0a13dd4387beMichael Chan
261215ec1009ae3b52ed491fde7b2aa0a13dd4387beMichael Chan    @Override
262b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public long getItemId(int position) {
263b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return mFilteredTimeZoneIndices[position];
264b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
265b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
266b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
267b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public View getView(int position, View convertView, ViewGroup parent) {
268b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        View v = convertView;
269b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
27096e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein        if (mFilteredTimeZoneIndices[position] == EMPTY_INDEX) {
27196e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein            v = mInflater.inflate(R.layout.empty_time_zone_item, null);
27296e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein            return v;
27396e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein        }
27496e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein
27596e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein        // We'll need to re-inflate the view if it was null, or if it was used as an empty item.
27696e8dde991e426d0cd44f5b4eb76118fd7374ac0Sam Blitzstein        if (v == null || v.findViewById(R.id.empty_item) != null) {
277b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            v = mInflater.inflate(R.layout.time_zone_item, null);
278b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            ViewHolder.setupViewHolder(v);
279b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
280b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
281b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        ViewHolder vh = (ViewHolder) v.getTag();
282b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
283143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan        TimeZoneInfo tzi = mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
284143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan        v.setTag(VIEW_TAG_TIME_ZONE, tzi);
285215ec1009ae3b52ed491fde7b2aa0a13dd4387beMichael Chan
286143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan        vh.timeZone.setText(tzi.mDisplayName);
287215ec1009ae3b52ed491fde7b2aa0a13dd4387beMichael Chan
288143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan        vh.timeOffset.setText(tzi.getGmtDisplayName(mContext));
289b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
290143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan        String location = tzi.mCountry;
291143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan        if (location == null) {
292143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan            vh.location.setVisibility(View.INVISIBLE);
293b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        } else {
294143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan            vh.location.setText(location);
295143a7e20a46dbd66bec4e4d7e8e0dcb693d343d3Michael Chan            vh.location.setVisibility(View.VISIBLE);
296b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
297b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
298b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return v;
299b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
300b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
301b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
302b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    public boolean hasStableIds() {
303b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        return true;
304b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
305b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan
306b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chan    // Implements OnItemClickListener
307b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    @Override
308b064db0d1a7ffcedddd691b35d57e2cdb0268883Michael Chan    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
309b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        if (mTimeZoneSetListener != null) {
310b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan            TimeZoneInfo tzi = (TimeZoneInfo) v.getTag(VIEW_TAG_TIME_ZONE);
311334894dfa40899042e20d35235624c37ffa10b45Paul Sliwowski            if (tzi != null) {
312334894dfa40899042e20d35235624c37ffa10b45Paul Sliwowski              mTimeZoneSetListener.onTimeZoneSet(tzi);
313334894dfa40899042e20d35235624c37ffa10b45Paul Sliwowski              saveRecentTimezone(tzi.mTzId);
314334894dfa40899042e20d35235624c37ffa10b45Paul Sliwowski            }
315b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan        }
316b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan    }
317b1b7080deea42aa533c3757b585cf765c6b76732Michael Chan}
318