1 /* 2 * Copyright (C) 2012 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 17 package com.android.deskclock.worldclock; 18 19 import android.content.Context; 20 import android.content.SharedPreferences; 21 import android.preference.PreferenceManager; 22 import android.view.LayoutInflater; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.widget.BaseAdapter; 26 import android.widget.TextClock; 27 import android.widget.TextView; 28 29 import com.android.deskclock.AnalogClock; 30 import com.android.deskclock.R; 31 import com.android.deskclock.SettingsActivity; 32 import com.android.deskclock.Utils; 33 34 import java.text.Collator; 35 import java.util.Arrays; 36 import java.util.Calendar; 37 import java.util.Comparator; 38 import java.util.Date; 39 import java.util.HashMap; 40 import java.util.Locale; 41 import java.util.TimeZone; 42 43 public class WorldClockAdapter extends BaseAdapter { 44 protected Object [] mCitiesList; 45 private final LayoutInflater mInflater; 46 private final Context mContext; 47 private String mClockStyle; 48 private final Collator mCollator = Collator.getInstance(); 49 protected HashMap<String, CityObj> mCitiesDb = new HashMap<String, CityObj>(); 50 protected int mClocksPerRow; 51 WorldClockAdapter(Context context)52 public WorldClockAdapter(Context context) { 53 super(); 54 mContext = context; 55 loadData(context); 56 loadCitiesDb(context); 57 mInflater = LayoutInflater.from(context); 58 mClocksPerRow = context.getResources().getInteger(R.integer.world_clocks_per_row); 59 } 60 reloadData(Context context)61 public void reloadData(Context context) { 62 loadData(context); 63 notifyDataSetChanged(); 64 } 65 loadData(Context context)66 public void loadData(Context context) { 67 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); 68 mClockStyle = prefs.getString(SettingsActivity.KEY_CLOCK_STYLE, 69 mContext.getResources().getString(R.string.default_clock_style)); 70 mCitiesList = Cities.readCitiesFromSharedPrefs(prefs).values().toArray(); 71 sortList(); 72 mCitiesList = addHomeCity(); 73 } 74 loadCitiesDb(Context context)75 public void loadCitiesDb(Context context) { 76 mCitiesDb.clear(); 77 // Read the cities DB so that the names and timezones will be taken from the DB 78 // and not from the selected list so that change of locale or changes in the DB will 79 // be reflected. 80 CityObj[] cities = Utils.loadCitiesFromXml(context); 81 if (cities != null) { 82 for (int i = 0; i < cities.length; i ++) { 83 mCitiesDb.put(cities[i].mCityId, cities [i]); 84 } 85 } 86 } 87 88 /*** 89 * Adds the home city as the first item of the adapter if the feature is on and the device time 90 * zone is different from the home time zone that was set by the user. 91 * return the list of cities. 92 */ addHomeCity()93 private Object[] addHomeCity() { 94 if (needHomeCity()) { 95 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext); 96 String homeTZ = sharedPref.getString(SettingsActivity.KEY_HOME_TZ, ""); 97 CityObj c = new CityObj( 98 mContext.getResources().getString(R.string.home_label), homeTZ, null, null); 99 Object[] temp = new Object[mCitiesList.length + 1]; 100 temp[0] = c; 101 for (int i = 0; i < mCitiesList.length; i++) { 102 temp[i + 1] = mCitiesList[i]; 103 } 104 return temp; 105 } else { 106 return mCitiesList; 107 } 108 } 109 updateHomeLabel(Context context)110 public void updateHomeLabel(Context context) { 111 // Update the "home" label if the home time zone clock is shown 112 if (needHomeCity() && mCitiesList.length > 0) { 113 ((CityObj) mCitiesList[0]).mCityName = 114 context.getResources().getString(R.string.home_label); 115 } 116 } 117 needHomeCity()118 public boolean needHomeCity() { 119 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext); 120 if (sharedPref.getBoolean(SettingsActivity.KEY_AUTO_HOME_CLOCK, false)) { 121 String homeTZ = sharedPref.getString( 122 SettingsActivity.KEY_HOME_TZ, TimeZone.getDefault().getID()); 123 final Date now = new Date(); 124 return TimeZone.getTimeZone(homeTZ).getOffset(now.getTime()) 125 != TimeZone.getDefault().getOffset(now.getTime()); 126 } else { 127 return false; 128 } 129 } 130 hasHomeCity()131 public boolean hasHomeCity() { 132 return (mCitiesList != null) && mCitiesList.length > 0 133 && ((CityObj) mCitiesList[0]).mCityId == null; 134 } 135 sortList()136 private void sortList() { 137 final Date now = new Date(); 138 139 // Sort by the Offset from GMT taking DST into account 140 // and if the same sort by City Name 141 Arrays.sort(mCitiesList, new Comparator<Object>() { 142 private int safeCityNameCompare(CityObj city1, CityObj city2) { 143 if (city1.mCityName == null && city2.mCityName == null) { 144 return 0; 145 } else if (city1.mCityName == null) { 146 return -1; 147 } else if (city2.mCityName == null) { 148 return 1; 149 } else { 150 return mCollator.compare(city1.mCityName, city2.mCityName); 151 } 152 } 153 154 @Override 155 public int compare(Object object1, Object object2) { 156 CityObj city1 = (CityObj) object1; 157 CityObj city2 = (CityObj) object2; 158 if (city1.mTimeZone == null && city2.mTimeZone == null) { 159 return safeCityNameCompare(city1, city2); 160 } else if (city1.mTimeZone == null) { 161 return -1; 162 } else if (city2.mTimeZone == null) { 163 return 1; 164 } 165 166 int gmOffset1 = TimeZone.getTimeZone(city1.mTimeZone).getOffset(now.getTime()); 167 int gmOffset2 = TimeZone.getTimeZone(city2.mTimeZone).getOffset(now.getTime()); 168 if (gmOffset1 == gmOffset2) { 169 return safeCityNameCompare(city1, city2); 170 } else { 171 return gmOffset1 - gmOffset2; 172 } 173 } 174 }); 175 } 176 177 @Override getCount()178 public int getCount() { 179 if (mClocksPerRow == 1) { 180 // In the special case where we have only 1 clock per view. 181 return mCitiesList.length; 182 } 183 184 // Otherwise, each item in the list holds 1 or 2 clocks 185 return (mCitiesList.length + 1)/2; 186 } 187 188 @Override getItem(int p)189 public Object getItem(int p) { 190 return null; 191 } 192 193 @Override getItemId(int p)194 public long getItemId(int p) { 195 return p; 196 } 197 198 @Override isEnabled(int p)199 public boolean isEnabled(int p) { 200 return false; 201 } 202 203 @Override getView(int position, View view, ViewGroup parent)204 public View getView(int position, View view, ViewGroup parent) { 205 // Index in cities list 206 int index = position * mClocksPerRow; 207 if (index < 0 || index >= mCitiesList.length) { 208 return null; 209 } 210 211 if (view == null) { 212 view = mInflater.inflate(R.layout.world_clock_list_item, parent, false); 213 } 214 updateView(view.findViewById(R.id.city_left), (CityObj)mCitiesList[index]); 215 return view; 216 } 217 updateView(View clock, CityObj cityObj)218 private void updateView(View clock, CityObj cityObj) { 219 TextView name = (TextView)(clock.findViewById(R.id.city_name)); 220 TextView dayOfWeek = (TextView)(clock.findViewById(R.id.city_day)); 221 TextClock dclock = (TextClock)(clock.findViewById(R.id.digital_clock)); 222 AnalogClock aclock = (AnalogClock)(clock.findViewById(R.id.analog_clock)); 223 224 if (mClockStyle.equals("analog")) { 225 dclock.setVisibility(View.GONE); 226 aclock.setVisibility(View.VISIBLE); 227 aclock.setTimeZone(cityObj.mTimeZone); 228 aclock.enableSeconds(false); 229 } else { 230 dclock.setVisibility(View.VISIBLE); 231 aclock.setVisibility(View.GONE); 232 dclock.setTimeZone(cityObj.mTimeZone); 233 Utils.setTimeFormat(mContext, dclock, 234 mContext.getResources().getDimensionPixelSize(R.dimen.label_font_size)); 235 } 236 CityObj cityInDb = mCitiesDb.get(cityObj.mCityId); 237 // Home city or city not in DB , use data from the save selected cities list 238 name.setText(Utils.getCityName(cityObj, cityInDb)); 239 240 final Calendar now = Calendar.getInstance(); 241 now.setTimeZone(TimeZone.getDefault()); 242 int myDayOfWeek = now.get(Calendar.DAY_OF_WEEK); 243 // Get timezone from cities DB if available 244 String cityTZ = (cityInDb != null) ? cityInDb.mTimeZone : cityObj.mTimeZone; 245 now.setTimeZone(TimeZone.getTimeZone(cityTZ)); 246 int cityDayOfWeek = now.get(Calendar.DAY_OF_WEEK); 247 if (myDayOfWeek != cityDayOfWeek) { 248 dayOfWeek.setText(mContext.getString(R.string.world_day_of_week_label, 249 now.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.getDefault()))); 250 dayOfWeek.setVisibility(View.VISIBLE); 251 } else { 252 dayOfWeek.setVisibility(View.GONE); 253 } 254 } 255 } 256