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