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