TimeZoneResultAdapter.java revision 852a8427f0ba0790fa2b7fd1bddba374f03953c6
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.timezonepicker;
18
19import android.content.Context;
20import android.content.SharedPreferences;
21import android.text.TextUtils;
22import android.util.Log;
23import android.view.LayoutInflater;
24import android.view.View;
25import android.view.ViewGroup;
26import android.widget.AdapterView;
27import android.widget.AdapterView.OnItemClickListener;
28import android.widget.BaseAdapter;
29import android.widget.TextView;
30
31import com.android.timezonepicker.TimeZoneFilterTypeAdapter.OnSetFilterListener;
32import com.android.timezonepicker.TimeZonePickerView.OnTimeZoneSetListener;
33
34import java.util.ArrayList;
35import java.util.LinkedHashSet;
36
37public class TimeZoneResultAdapter extends BaseAdapter implements OnItemClickListener,
38        OnSetFilterListener {
39    private static final String TAG = "TimeZoneResultAdapter";
40    private static final int VIEW_TAG_TIME_ZONE = R.id.time_zone;
41
42    /** SharedPref name and key for recent time zones */
43    private static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
44    private static final String KEY_RECENT_TIMEZONES = "preferences_recent_timezones";
45
46    /**
47     * The delimiter we use when serializing recent timezones to shared
48     * preferences
49     */
50    private static final String RECENT_TIMEZONES_DELIMITER = ",";
51
52    /** The maximum number of recent timezones to save */
53    private static final int MAX_RECENT_TIMEZONES = 3;
54
55    static class ViewHolder {
56        TextView timeZone;
57        TextView timeOffset;
58        TextView location;
59
60        static void setupViewHolder(View v) {
61            ViewHolder vh = new ViewHolder();
62            vh.timeZone = (TextView) v.findViewById(R.id.time_zone);
63            vh.timeOffset = (TextView) v.findViewById(R.id.time_offset);
64            vh.location = (TextView) v.findViewById(R.id.location);
65            v.setTag(vh);
66        }
67    }
68
69    private Context mContext;
70    private LayoutInflater mInflater;
71
72    private OnTimeZoneSetListener mTimeZoneSetListener;
73    private TimeZoneData mTimeZoneData;
74
75    private int[] mFilteredTimeZoneIndices;
76    private int mFilteredTimeZoneLength = 0;
77
78    public TimeZoneResultAdapter(Context context, TimeZoneData tzd,
79            com.android.timezonepicker.TimeZonePickerView.OnTimeZoneSetListener l) {
80        super();
81
82        mContext = context;
83        mTimeZoneData = tzd;
84        mTimeZoneSetListener = l;
85
86        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
87
88        mFilteredTimeZoneIndices = new int[mTimeZoneData.size()];
89
90        onSetFilter(TimeZoneFilterTypeAdapter.FILTER_TYPE_NONE, null, 0);
91    }
92
93    // Implements OnSetFilterListener
94    @Override
95    public void onSetFilter(int filterType, String str, int time) {
96        Log.d(TAG, "onSetFilter: " + filterType + " [" + str + "] " + time);
97
98        mFilteredTimeZoneLength = 0;
99        int idx = 0;
100
101        switch (filterType) {
102            case TimeZoneFilterTypeAdapter.FILTER_TYPE_EMPTY:
103                break;
104            case TimeZoneFilterTypeAdapter.FILTER_TYPE_NONE:
105                // Show the default/current value first
106                int defaultTzIndex = mTimeZoneData.getDefaultTimeZoneIndex();
107                if (defaultTzIndex != -1) {
108                    mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = defaultTzIndex;
109                }
110
111                // Show the recent selections
112                SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFS_NAME,
113                        Context.MODE_PRIVATE);
114                String recentsString = prefs.getString(KEY_RECENT_TIMEZONES, null);
115                if (!TextUtils.isEmpty(recentsString)) {
116                    String[] recents = recentsString.split(RECENT_TIMEZONES_DELIMITER);
117                    for (int i = recents.length - 1; i >= 0; i--) {
118                        if (!TextUtils.isEmpty(recents[i])
119                                && !recents[i].equals(mTimeZoneData.mDefaultTimeZoneId)) {
120                            int index = mTimeZoneData.findIndexByTimeZoneIdSlow(recents[i]);
121                            if (index != -1) {
122                                mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = index;
123                            }
124                        }
125                    }
126                }
127
128                break;
129            case TimeZoneFilterTypeAdapter.FILTER_TYPE_GMT:
130                ArrayList<Integer> indices = mTimeZoneData.getTimeZonesByOffset(time);
131                if (indices != null) {
132                    for (Integer i : indices) {
133                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = i;
134                    }
135                }
136                break;
137            case TimeZoneFilterTypeAdapter.FILTER_TYPE_COUNTRY:
138                ArrayList<Integer> tzIds = mTimeZoneData.mTimeZonesByCountry.get(str);
139                if (tzIds != null) {
140                    for (Integer tzi : tzIds) {
141                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = tzi;
142                    }
143                }
144                break;
145            case TimeZoneFilterTypeAdapter.FILTER_TYPE_STATE:
146                // TODO Filter by state
147                break;
148            default:
149                throw new IllegalArgumentException();
150        }
151        notifyDataSetChanged();
152    }
153
154    /**
155     * Saves the given timezone ID as a recent timezone under shared
156     * preferences. If there are already the maximum number of recent timezones
157     * saved, it will remove the oldest and append this one.
158     *
159     * @param id the ID of the timezone to save
160     * @see {@link #MAX_RECENT_TIMEZONES}
161     */
162    public void saveRecentTimezone(String id) {
163        SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFS_NAME,
164                Context.MODE_PRIVATE);
165        String recentsString = prefs.getString(KEY_RECENT_TIMEZONES, null);
166        if (recentsString == null) {
167            recentsString = id;
168        } else {
169            // De-dup
170            LinkedHashSet<String> recents = new LinkedHashSet<String>();
171            for(String tzId : recentsString.split(RECENT_TIMEZONES_DELIMITER)) {
172                if (!recents.contains(tzId) && !id.equals(tzId)) {
173                    recents.add(tzId);
174                }
175            }
176
177            while (recents.size() >= MAX_RECENT_TIMEZONES) {
178                recents.remove(0);
179            }
180            recents.add(id);
181
182            StringBuilder builder = new StringBuilder();
183            boolean first = true;
184            for (String recent : recents) {
185                if (first) {
186                    first = false;
187                } else {
188                    builder.append(RECENT_TIMEZONES_DELIMITER);
189                }
190                builder.append(recent);
191            }
192            recentsString = builder.toString();
193        }
194
195        prefs.edit().putString(KEY_RECENT_TIMEZONES, recentsString).apply();
196    }
197
198    @Override
199    public int getCount() {
200        return mFilteredTimeZoneLength;
201    }
202
203    @Override
204    public Object getItem(int position) {
205        if (position < 0 || position >= mFilteredTimeZoneLength) {
206            return null;
207        }
208
209        return mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
210    }
211
212    @Override
213    public boolean areAllItemsEnabled() {
214        return false;
215    }
216
217    @Override
218    public boolean isEnabled(int position) {
219        return mFilteredTimeZoneIndices[position] >= 0;
220    }
221
222    @Override
223    public long getItemId(int position) {
224        return mFilteredTimeZoneIndices[position];
225    }
226
227    @Override
228    public View getView(int position, View convertView, ViewGroup parent) {
229        View v = convertView;
230
231        if (v == null) {
232            v = mInflater.inflate(R.layout.time_zone_item, null);
233            ViewHolder.setupViewHolder(v);
234        }
235
236        ViewHolder vh = (ViewHolder) v.getTag();
237
238        TimeZoneInfo tzi = mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
239        v.setTag(VIEW_TAG_TIME_ZONE, tzi);
240
241        vh.timeZone.setText(tzi.mDisplayName);
242
243        vh.timeOffset.setText(tzi.getGmtDisplayName(mContext));
244
245        String location = tzi.mCountry;
246        if (location == null) {
247            vh.location.setVisibility(View.INVISIBLE);
248        } else {
249            vh.location.setText(location);
250            vh.location.setVisibility(View.VISIBLE);
251        }
252
253        return v;
254    }
255
256    @Override
257    public boolean hasStableIds() {
258        return true;
259    }
260
261    // Implements OnItemClickListener
262    @Override
263    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
264        if (mTimeZoneSetListener != null) {
265            TimeZoneInfo tzi = (TimeZoneInfo) v.getTag(VIEW_TAG_TIME_ZONE);
266            mTimeZoneSetListener.onTimeZoneSet(tzi);
267            saveRecentTimezone(tzi.mTzId);
268        }
269    }
270}
271