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