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