• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     private 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);
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         // The world clock list item can hold two world clocks
215         View rightClock = view.findViewById(R.id.city_right);
216         updateView(view.findViewById(R.id.city_left), (CityObj)mCitiesList[index]);
217         if (rightClock != null) {
218             // rightClock may be null (landscape phone layout has only one clock per row) so only
219             // process it if it exists.
220             if (index + 1 < mCitiesList.length) {
221                 rightClock.setVisibility(View.VISIBLE);
222                 updateView(rightClock, (CityObj)mCitiesList[index + 1]);
223             } else {
224                 // To make sure the spacing is right , make sure that the right clock style is
225                 // selected even if the clock is invisible.
226                 View dclock = rightClock.findViewById(R.id.digital_clock);
227                 View aclock = rightClock.findViewById(R.id.analog_clock);
228                 if (mClockStyle.equals("analog")) {
229                     dclock.setVisibility(View.GONE);
230                     aclock.setVisibility(View.INVISIBLE);
231                 } else {
232                     dclock.setVisibility(View.INVISIBLE);
233                     aclock.setVisibility(View.GONE);
234                 }
235                 // If there's only the one item, center it. If there are other items in the list,
236                 // keep it side-aligned.
237                 if (getCount() == 1) {
238                     rightClock.setVisibility(View.GONE);
239                 } else {
240                     rightClock.setVisibility(View.INVISIBLE);
241                 }
242             }
243         }
244 
245         return view;
246     }
247 
updateView(View clock, CityObj cityObj)248     private void updateView(View clock, CityObj cityObj) {
249         View nameLayout= clock.findViewById(R.id.city_name_layout);
250         TextView name = (TextView)(nameLayout.findViewById(R.id.city_name));
251         TextView dayOfWeek = (TextView)(nameLayout.findViewById(R.id.city_day));
252         TextClock dclock = (TextClock)(clock.findViewById(R.id.digital_clock));
253         AnalogClock aclock = (AnalogClock)(clock.findViewById(R.id.analog_clock));
254         View separator = clock.findViewById(R.id.separator);
255 
256         if (mClockStyle.equals("analog")) {
257             dclock.setVisibility(View.GONE);
258             separator.setVisibility(View.GONE);
259             aclock.setVisibility(View.VISIBLE);
260             aclock.setTimeZone(cityObj.mTimeZone);
261             aclock.enableSeconds(false);
262         } else {
263             dclock.setVisibility(View.VISIBLE);
264             separator.setVisibility(View.VISIBLE);
265             aclock.setVisibility(View.GONE);
266             dclock.setTimeZone(cityObj.mTimeZone);
267             Utils.setTimeFormat(dclock,
268                     (int)mContext.getResources().getDimension(R.dimen.label_font_size));
269         }
270         CityObj cityInDb = mCitiesDb.get(cityObj.mCityId);
271         // Home city or city not in DB , use data from the save selected cities list
272         name.setText(Utils.getCityName(cityObj, cityInDb));
273 
274         final Calendar now = Calendar.getInstance();
275         now.setTimeZone(TimeZone.getDefault());
276         int myDayOfWeek = now.get(Calendar.DAY_OF_WEEK);
277         // Get timezone from cities DB if available
278         String cityTZ = (cityInDb != null) ? cityInDb.mTimeZone : cityObj.mTimeZone;
279         now.setTimeZone(TimeZone.getTimeZone(cityTZ));
280         int cityDayOfWeek = now.get(Calendar.DAY_OF_WEEK);
281         if (myDayOfWeek != cityDayOfWeek) {
282             dayOfWeek.setText(mContext.getString(R.string.world_day_of_week_label,
283                     now.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.getDefault())));
284             dayOfWeek.setVisibility(View.VISIBLE);
285         } else {
286             dayOfWeek.setVisibility(View.GONE);
287         }
288     }
289 }
290