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