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