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 WorldClockAdapter(Context context)51 public WorldClockAdapter(Context context) { 52 super(); 53 mContext = context; 54 loadData(context); 55 loadCitiesDb(context); 56 mInflater = LayoutInflater.from(context); 57 } 58 reloadData(Context context)59 public void reloadData(Context context) { 60 loadData(context); 61 notifyDataSetChanged(); 62 } 63 loadData(Context context)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 loadCitiesDb(Context context)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 */ addHomeCity()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 needHomeCity()108 public boolean needHomeCity() { 109 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext); 110 if (sharedPref.getBoolean(SettingsActivity.KEY_AUTO_HOME_CLOCK, false)) { 111 String homeTZ = sharedPref.getString( 112 SettingsActivity.KEY_HOME_TZ, TimeZone.getDefault().getID()); 113 final Date now = new Date(); 114 return TimeZone.getTimeZone(homeTZ).getOffset(now.getTime()) 115 != TimeZone.getDefault().getOffset(now.getTime()); 116 } else { 117 return false; 118 } 119 } 120 hasHomeCity()121 public boolean hasHomeCity() { 122 return (mCitiesList != null) && mCitiesList.length > 0 123 && ((CityObj) mCitiesList[0]).mCityId == null; 124 } 125 sortList()126 private void sortList() { 127 final Date now = new Date(); 128 129 // Sort by the Offset from GMT taking DST into account 130 // and if the same sort by City Name 131 Arrays.sort(mCitiesList, new Comparator<Object>() { 132 private int safeCityNameCompare(CityObj city1, CityObj city2) { 133 if (city1.mCityName == null && city2.mCityName == null) { 134 return 0; 135 } else if (city1.mCityName == null) { 136 return -1; 137 } else if (city2.mCityName == null) { 138 return 1; 139 } else { 140 return mCollator.compare(city1.mCityName, city2.mCityName); 141 } 142 } 143 144 @Override 145 public int compare(Object object1, Object object2) { 146 CityObj city1 = (CityObj) object1; 147 CityObj city2 = (CityObj) object2; 148 if (city1.mTimeZone == null && city2.mTimeZone == null) { 149 return safeCityNameCompare(city1, city2); 150 } else if (city1.mTimeZone == null) { 151 return -1; 152 } else if (city2.mTimeZone == null) { 153 return 1; 154 } 155 156 int gmOffset1 = TimeZone.getTimeZone(city1.mTimeZone).getOffset(now.getTime()); 157 int gmOffset2 = TimeZone.getTimeZone(city2.mTimeZone).getOffset(now.getTime()); 158 if (gmOffset1 == gmOffset2) { 159 return safeCityNameCompare(city1, city2); 160 } else { 161 return gmOffset1 - gmOffset2; 162 } 163 } 164 }); 165 } 166 167 @Override getCount()168 public int getCount() { 169 // Each item in the list holds 1 or 2 clocks 170 return (mCitiesList.length + 1)/2; 171 } 172 173 @Override getItem(int p)174 public Object getItem(int p) { 175 return null; 176 } 177 178 @Override getItemId(int p)179 public long getItemId(int p) { 180 return p; 181 } 182 183 @Override isEnabled(int p)184 public boolean isEnabled(int p) { 185 return false; 186 } 187 188 @Override getView(int position, View view, ViewGroup parent)189 public View getView(int position, View view, ViewGroup parent) { 190 // Index in cities list 191 int index = position * 2; 192 if (index < 0 || index >= mCitiesList.length) { 193 return null; 194 } 195 196 if (view == null) { 197 view = mInflater.inflate(R.layout.world_clock_list_item, parent, false); 198 } 199 // The world clock list item can hold two world clocks 200 View rightClock = view.findViewById(R.id.city_right); 201 updateView(view.findViewById(R.id.city_left), (CityObj)mCitiesList[index]); 202 if (index + 1 < mCitiesList.length) { 203 rightClock.setVisibility(View.VISIBLE); 204 updateView(rightClock, (CityObj)mCitiesList[index + 1]); 205 } else { 206 // To make sure the spacing is right , make sure that the right clock style is selected 207 // even if the clock is invisible. 208 DigitalClock dclock = (DigitalClock)(rightClock.findViewById(R.id.digital_clock)); 209 AnalogClock aclock = (AnalogClock)(rightClock.findViewById(R.id.analog_clock)); 210 if (mClockStyle.equals("analog")) { 211 dclock.setVisibility(View.GONE); 212 aclock.setVisibility(View.INVISIBLE); 213 } else { 214 dclock.setVisibility(View.INVISIBLE); 215 aclock.setVisibility(View.GONE); 216 } 217 rightClock.setVisibility(View.INVISIBLE); 218 } 219 220 return view; 221 } 222 updateView(View clock, CityObj cityObj)223 private void updateView(View clock, CityObj cityObj) { 224 View nameLayout= clock.findViewById(R.id.city_name_layout); 225 TextView name = (TextView)(nameLayout.findViewById(R.id.city_name)); 226 TextView dayOfWeek = (TextView)(nameLayout.findViewById(R.id.city_day)); 227 DigitalClock dclock = (DigitalClock)(clock.findViewById(R.id.digital_clock)); 228 AnalogClock aclock = (AnalogClock)(clock.findViewById(R.id.analog_clock)); 229 230 if (mClockStyle.equals("analog")) { 231 dclock.setVisibility(View.GONE); 232 aclock.setVisibility(View.VISIBLE); 233 aclock.setTimeZone(cityObj.mTimeZone); 234 aclock.enableSeconds(false); 235 } else { 236 dclock.setVisibility(View.VISIBLE); 237 aclock.setVisibility(View.GONE); 238 dclock.setTimeZone(cityObj.mTimeZone); 239 } 240 CityObj cityInDb = mCitiesDb.get(cityObj.mCityId); 241 // Home city or city not in DB , use data from the save selected cities list 242 name.setText(Utils.getCityName(cityObj, cityInDb)); 243 244 final Calendar now = Calendar.getInstance(); 245 now.setTimeZone(TimeZone.getDefault()); 246 int myDayOfWeek = now.get(Calendar.DAY_OF_WEEK); 247 // Get timezone from cities DB if available 248 String cityTZ = (cityInDb != null) ? cityInDb.mTimeZone : cityObj.mTimeZone; 249 now.setTimeZone(TimeZone.getTimeZone(cityTZ)); 250 int cityDayOfWeek = now.get(Calendar.DAY_OF_WEEK); 251 if (myDayOfWeek != cityDayOfWeek) { 252 dayOfWeek.setText(mContext.getString(R.string.world_day_of_week_label, 253 now.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.getDefault()))); 254 dayOfWeek.setVisibility(View.VISIBLE); 255 } else { 256 dayOfWeek.setVisibility(View.GONE); 257 } 258 } 259 } 260