Home | History | Annotate | Download | only in worldclock
      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