TimeZoneResultAdapter.java revision b1b7080deea42aa533c3757b585cf765c6b76732
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.View.OnClickListener;
26import android.view.ViewGroup;
27import android.widget.BaseAdapter;
28import android.widget.TextView;
29
30import com.android.timezonepicker.TimeZoneFilterTypeAdapter.OnSetFilterListener;
31import com.android.timezonepicker.TimeZonePickerView.OnTimeZoneSetListener;
32
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.Iterator;
36import java.util.List;
37
38public class TimeZoneResultAdapter extends BaseAdapter implements OnClickListener,
39        OnSetFilterListener {
40    private static final String TAG = "TimeZoneResultAdapter";
41    private static final int VIEW_TAG_TIME_ZONE = R.id.time_zone;
42
43    /** SharedPref name and key for recent time zones */
44    private static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
45    private static final String KEY_RECENT_TIMEZONES = "preferences_recent_timezones";
46
47    /**
48     * The delimiter we use when serializing recent timezones to shared
49     * preferences
50     */
51    private static final String RECENT_TIMEZONES_DELIMITER = ",";
52
53    /** The maximum number of recent timezones to save */
54    private static final int MAX_RECENT_TIMEZONES = 3;
55
56    static class ViewHolder {
57        TextView timeZone;
58        TextView timeOffset;
59        TextView location;
60
61        static void setupViewHolder(View v) {
62            ViewHolder vh = new ViewHolder();
63            vh.timeZone = (TextView) v.findViewById(R.id.time_zone);
64            vh.timeOffset = (TextView) v.findViewById(R.id.time_offset);
65            vh.location = (TextView) v.findViewById(R.id.location);
66            v.setTag(vh);
67        }
68    }
69
70    private Context mContext;
71    private LayoutInflater mInflater;
72
73    private OnTimeZoneSetListener mTimeZoneSetListener;
74    private TimeZoneData mTimeZoneData;
75
76    private int[] mFilteredTimeZoneIndices;
77    private int mFilteredTimeZoneLength = 0;
78    private int mFilterType;
79
80    public TimeZoneResultAdapter(Context context, TimeZoneData tzd,
81            com.android.timezonepicker.TimeZonePickerView.OnTimeZoneSetListener l) {
82        super();
83
84        mContext = context;
85        mTimeZoneData = tzd;
86        mTimeZoneSetListener = l;
87
88        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
89
90        mFilteredTimeZoneIndices = new int[mTimeZoneData.size()];
91
92        onSetFilter(TimeZoneFilterTypeAdapter.FILTER_TYPE_NONE, null, 0);
93    }
94
95    // Implements OnSetFilterListener
96    @Override
97    public void onSetFilter(int filterType, String str, int time) {
98        Log.d(TAG, "onSetFilter: " + filterType + " [" + str + "] " + time);
99
100        mFilterType = filterType;
101        mFilteredTimeZoneLength = 0;
102        int idx = 0;
103
104        switch (filterType) {
105            case TimeZoneFilterTypeAdapter.FILTER_TYPE_EMPTY:
106                break;
107            case TimeZoneFilterTypeAdapter.FILTER_TYPE_NONE:
108                // Show the default/current value first
109                int defaultTzIndex = mTimeZoneData.getDefaultTimeZoneIndex();
110                if (defaultTzIndex != -1) {
111                    mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = defaultTzIndex;
112                }
113
114                // Show the recent selections
115                SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFS_NAME,
116                        Context.MODE_PRIVATE);
117                String recentsString = prefs.getString(KEY_RECENT_TIMEZONES, null);
118                if (!TextUtils.isEmpty(recentsString)) {
119                    String[] recents = recentsString.split(RECENT_TIMEZONES_DELIMITER);
120                    for (int i = recents.length - 1; i >= 0; i--) {
121                        if (!TextUtils.isEmpty(recents[i])
122                                && !recents[i].equals(mTimeZoneData.mDefaultTimeZoneId)) {
123                            int index = mTimeZoneData.findIndexByTimeZoneIdSlow(recents[i]);
124                            if (index != -1) {
125                                mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = index;
126                            }
127                        }
128                    }
129                }
130
131                break;
132            case TimeZoneFilterTypeAdapter.FILTER_TYPE_GMT:
133                ArrayList<Integer> indices = mTimeZoneData.getTimeZonesByOffset(time);
134                if (indices != null) {
135                    for (Integer i : indices) {
136                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = i;
137                    }
138                }
139                break;
140            case TimeZoneFilterTypeAdapter.FILTER_TYPE_TIME:
141                // TODO Filter by time properly
142                for (TimeZoneInfo tzi : mTimeZoneData.mTimeZones) {
143                    if (str.equalsIgnoreCase(tzi.getGmtDisplayName(mContext))) {
144                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = idx;
145                    }
146                    idx++;
147                }
148                break;
149            case TimeZoneFilterTypeAdapter.FILTER_TYPE_TIME_ZONE:
150                for (TimeZoneInfo tzi : mTimeZoneData.mTimeZones) {
151                    if (str.equalsIgnoreCase(tzi.mDisplayName)) {
152                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = idx;
153                    }
154                    idx++;
155                }
156                break;
157            case TimeZoneFilterTypeAdapter.FILTER_TYPE_COUNTRY:
158                ArrayList<Integer> tzIds = mTimeZoneData.mTimeZonesByCountry.get(str);
159                if (tzIds != null) {
160                    for (Integer tzi : tzIds) {
161                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = tzi;
162                    }
163                }
164                break;
165            case TimeZoneFilterTypeAdapter.FILTER_TYPE_STATE:
166                // TODO Filter by state
167                break;
168            default:
169                throw new IllegalArgumentException();
170        }
171        notifyDataSetChanged();
172    }
173
174    /**
175     * Saves the given timezone ID as a recent timezone under shared
176     * preferences. If there are already the maximum number of recent timezones
177     * saved, it will remove the oldest and append this one.
178     *
179     * @param id the ID of the timezone to save
180     * @see {@link #MAX_RECENT_TIMEZONES}
181     */
182    public void saveRecentTimezone(String id) {
183        SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFS_NAME,
184                Context.MODE_PRIVATE);
185        String recentsString = prefs.getString(KEY_RECENT_TIMEZONES, null);
186        if (recentsString == null) {
187            recentsString = id;
188        } else {
189            List<String> recents = new ArrayList<String>(
190                    Arrays.asList(recentsString.split(RECENT_TIMEZONES_DELIMITER)));
191            Iterator<String> it = recents.iterator();
192            while(it.hasNext()) {
193                String tz = it.next();
194                if (id.equals(tz)) {
195                    it.remove();
196                }
197            }
198
199            while (recents.size() >= MAX_RECENT_TIMEZONES) {
200                recents.remove(0);
201            }
202            recents.add(id);
203
204            StringBuilder builder = new StringBuilder();
205            boolean first = true;
206            for (String recent : recents) {
207                if (first) {
208                    first = false;
209                } else {
210                    builder.append(RECENT_TIMEZONES_DELIMITER);
211                }
212                builder.append(recent);
213            }
214            recentsString = builder.toString();
215        }
216
217        prefs.edit().putString(KEY_RECENT_TIMEZONES, recentsString).apply();
218    }
219
220    @Override
221    public int getCount() {
222        return mFilteredTimeZoneLength;
223    }
224
225    @Override
226    public TimeZoneInfo getItem(int position) {
227        if (position < 0 || position >= mFilteredTimeZoneLength) {
228            return null;
229        }
230
231        return mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
232    }
233
234    @Override
235    public long getItemId(int position) {
236        return mFilteredTimeZoneIndices[position];
237    }
238
239    @Override
240    public View getView(int position, View convertView, ViewGroup parent) {
241        View v = convertView;
242
243        if (v == null) {
244            v = mInflater.inflate(R.layout.time_zone_item, null);
245            v.setOnClickListener(this);
246            ViewHolder.setupViewHolder(v);
247        }
248
249        TimeZoneInfo tzi = mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
250        v.setTag(VIEW_TAG_TIME_ZONE, tzi);
251
252        ViewHolder vh = (ViewHolder) v.getTag();
253        vh.timeOffset.setText(tzi.getGmtDisplayName(mContext));
254
255        vh.timeZone.setText(tzi.mDisplayName);
256
257        String location = tzi.mCountry;
258        if (location == null) {
259            vh.location.setVisibility(View.INVISIBLE);
260        } else {
261            vh.location.setText(location);
262            vh.location.setVisibility(View.VISIBLE);
263        }
264
265        return v;
266    }
267
268    @Override
269    public boolean hasStableIds() {
270        return true;
271    }
272
273    // Implements OnClickListener
274    @Override
275    public void onClick(View v) {
276        if (mTimeZoneSetListener != null) {
277            TimeZoneInfo tzi = (TimeZoneInfo) v.getTag(VIEW_TAG_TIME_ZONE);
278            mTimeZoneSetListener.onTimeZoneSet(tzi);
279            saveRecentTimezone(tzi.mTzId);
280        }
281    }
282
283}
284