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