TimeZoneResultAdapter.java revision 0717b65fee21de6a321e42c9f3852f8b622c3215
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 make this faster
142                long now = System.currentTimeMillis();
143                for (TimeZoneInfo tzi : mTimeZoneData.mTimeZones) {
144                    int localHr = tzi.getLocalHr(now);
145                    boolean match = localHr == time;
146                    if (!match && !TimeZoneData.is24HourFormat) {
147                        // PM + noon cases
148                        if((time + 12 == localHr) || (time == 12 && localHr == 0)) {
149                            match = true;
150                        }
151                    }
152                    if (match) {
153                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = idx;
154                    }
155                    idx++;
156                }
157                break;
158            case TimeZoneFilterTypeAdapter.FILTER_TYPE_TIME_ZONE:
159                for (TimeZoneInfo tzi : mTimeZoneData.mTimeZones) {
160                    if (str.equalsIgnoreCase(tzi.mDisplayName)) {
161                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = idx;
162                    }
163                    idx++;
164                }
165                break;
166            case TimeZoneFilterTypeAdapter.FILTER_TYPE_COUNTRY:
167                ArrayList<Integer> tzIds = mTimeZoneData.mTimeZonesByCountry.get(str);
168                if (tzIds != null) {
169                    for (Integer tzi : tzIds) {
170                        mFilteredTimeZoneIndices[mFilteredTimeZoneLength++] = tzi;
171                    }
172                }
173                break;
174            case TimeZoneFilterTypeAdapter.FILTER_TYPE_STATE:
175                // TODO Filter by state
176                break;
177            default:
178                throw new IllegalArgumentException();
179        }
180        notifyDataSetChanged();
181    }
182
183    /**
184     * Saves the given timezone ID as a recent timezone under shared
185     * preferences. If there are already the maximum number of recent timezones
186     * saved, it will remove the oldest and append this one.
187     *
188     * @param id the ID of the timezone to save
189     * @see {@link #MAX_RECENT_TIMEZONES}
190     */
191    public void saveRecentTimezone(String id) {
192        SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFS_NAME,
193                Context.MODE_PRIVATE);
194        String recentsString = prefs.getString(KEY_RECENT_TIMEZONES, null);
195        if (recentsString == null) {
196            recentsString = id;
197        } else {
198            List<String> recents = new ArrayList<String>(
199                    Arrays.asList(recentsString.split(RECENT_TIMEZONES_DELIMITER)));
200            Iterator<String> it = recents.iterator();
201            while(it.hasNext()) {
202                String tz = it.next();
203                if (id.equals(tz)) {
204                    it.remove();
205                }
206            }
207
208            while (recents.size() >= MAX_RECENT_TIMEZONES) {
209                recents.remove(0);
210            }
211            recents.add(id);
212
213            StringBuilder builder = new StringBuilder();
214            boolean first = true;
215            for (String recent : recents) {
216                if (first) {
217                    first = false;
218                } else {
219                    builder.append(RECENT_TIMEZONES_DELIMITER);
220                }
221                builder.append(recent);
222            }
223            recentsString = builder.toString();
224        }
225
226        prefs.edit().putString(KEY_RECENT_TIMEZONES, recentsString).apply();
227    }
228
229    @Override
230    public int getCount() {
231        return mFilteredTimeZoneLength;
232    }
233
234    @Override
235    public TimeZoneInfo getItem(int position) {
236        if (position < 0 || position >= mFilteredTimeZoneLength) {
237            return null;
238        }
239
240        return mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
241    }
242
243    @Override
244    public long getItemId(int position) {
245        return mFilteredTimeZoneIndices[position];
246    }
247
248    @Override
249    public View getView(int position, View convertView, ViewGroup parent) {
250        View v = convertView;
251
252        if (v == null) {
253            v = mInflater.inflate(R.layout.time_zone_item, null);
254            v.setOnClickListener(this);
255            ViewHolder.setupViewHolder(v);
256        }
257
258        TimeZoneInfo tzi = mTimeZoneData.get(mFilteredTimeZoneIndices[position]);
259        v.setTag(VIEW_TAG_TIME_ZONE, tzi);
260
261        ViewHolder vh = (ViewHolder) v.getTag();
262        vh.timeOffset.setText(tzi.getGmtDisplayName(mContext));
263
264        vh.timeZone.setText(tzi.mDisplayName);
265
266        String location = tzi.mCountry;
267        if (location == null) {
268            vh.location.setVisibility(View.INVISIBLE);
269        } else {
270            vh.location.setText(location);
271            vh.location.setVisibility(View.VISIBLE);
272        }
273
274        return v;
275    }
276
277    @Override
278    public boolean hasStableIds() {
279        return true;
280    }
281
282    // Implements OnClickListener
283    @Override
284    public void onClick(View v) {
285        if (mTimeZoneSetListener != null) {
286            TimeZoneInfo tzi = (TimeZoneInfo) v.getTag(VIEW_TAG_TIME_ZONE);
287            mTimeZoneSetListener.onTimeZoneSet(tzi);
288            saveRecentTimezone(tzi.mTzId);
289        }
290    }
291
292}
293