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.app.ActionBar;
     20 import android.app.Activity;
     21 import android.content.ActivityNotFoundException;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.res.Resources;
     25 import android.os.Bundle;
     26 import android.preference.PreferenceManager;
     27 import android.text.format.DateFormat;
     28 import android.view.LayoutInflater;
     29 import android.view.Menu;
     30 import android.view.MenuItem;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.BaseAdapter;
     34 import android.widget.CheckBox;
     35 import android.widget.CompoundButton;
     36 import android.widget.CompoundButton.OnCheckedChangeListener;
     37 import android.widget.ListView;
     38 import android.widget.SectionIndexer;
     39 import android.widget.TextView;
     40 
     41 import com.android.deskclock.Alarms;
     42 import com.android.deskclock.DeskClock;
     43 import com.android.deskclock.Log;
     44 import com.android.deskclock.R;
     45 import com.android.deskclock.SettingsActivity;
     46 import com.android.deskclock.Utils;
     47 
     48 import java.text.Collator;
     49 import java.util.ArrayList;
     50 import java.util.Arrays;
     51 import java.util.Calendar;
     52 import java.util.Comparator;
     53 import java.util.HashMap;
     54 import java.util.TimeZone;
     55 
     56 /**
     57  * Cities chooser for the world clock
     58  */
     59 public class CitiesActivity extends Activity implements OnCheckedChangeListener, View.OnClickListener {
     60 
     61     /** This must be false for production.  If true, turns on logging,
     62         test code, etc. */
     63     static final boolean DEBUG = false;
     64     static final String TAG = "CitiesActivity";
     65 
     66     private LayoutInflater mFactory;
     67     private ListView mCitiesList;
     68     private CityAdapter mAdapter;
     69     private HashMap<String, CityObj> mUserSelectedCities;
     70     private Calendar mCalendar;
     71     private final Collator mCollator = Collator.getInstance();
     72 
     73 
     74 /***
     75 * Adapter for a list of cities with the respected time zone.
     76 * The Adapter sorts the list alphabetically and create an indexer.
     77 ***/
     78 
     79     private class CityAdapter extends BaseAdapter implements SectionIndexer {
     80         private static final String DELETED_ENTRY = "C0";
     81         private Object [] mAllTheCitiesList;                      // full list of the cities
     82         private final HashMap<String, CityObj> mSelectedCitiesList; // Selected cities by the use
     83         private final LayoutInflater mInflater;
     84         private boolean mIs24HoursMode;                            // AM/PM or 24 hours mode
     85         private Object [] mSectionHeaders;
     86         private Object [] mSectionPositions;
     87 
     88         public CityAdapter(
     89                 Context context,  HashMap<String, CityObj> selectedList, LayoutInflater factory) {
     90             super();
     91             loadCitiesDataBase(context);
     92             mSelectedCitiesList = selectedList;
     93             mInflater = factory;
     94             mCalendar = Calendar.getInstance();
     95             mCalendar.setTimeInMillis(System.currentTimeMillis());
     96             set24HoursMode(context);
     97         }
     98 
     99         @Override
    100         public int getCount() {
    101             return mAllTheCitiesList.length;
    102         }
    103 
    104         @Override
    105         public Object getItem(int p) {
    106             if (p >=0 && p < mAllTheCitiesList.length) {
    107                 return mAllTheCitiesList [p];
    108             }
    109             return null;
    110         }
    111 
    112         @Override
    113         public long getItemId(int p) {
    114             return p;
    115         }
    116 
    117         @Override
    118         public boolean isEnabled(int p) {
    119             return ((CityObj)mAllTheCitiesList[p]).mCityId != null;
    120         }
    121 
    122         @Override
    123         public View getView(int position, View view, ViewGroup parent) {
    124             if (position < 0 || position >=  mAllTheCitiesList.length) {
    125                 return null;
    126             }
    127             CityObj c = (CityObj)mAllTheCitiesList [position];
    128             // Header view (A CityObj with nothing but the first letter as the name
    129             if (c.mCityId == null) {
    130                 if (view == null || view.findViewById(R.id.header) == null) {
    131                     view =  mInflater.inflate(R.layout.city_list_header, parent, false);
    132                 }
    133                 TextView header = (TextView)view.findViewById(R.id.header);
    134                 header.setText(c.mCityName);
    135             } else { // City view
    136                 // Make sure to recycle a City view only
    137                 if (view == null || view.findViewById(R.id.city_name) == null) {
    138                     view = mInflater.inflate(R.layout.city_list_item, parent, false);
    139                 }
    140                 view.setOnClickListener(CitiesActivity.this);
    141                 TextView name = (TextView)view.findViewById(R.id.city_name);
    142                 TextView tz = (TextView)view.findViewById(R.id.city_time);
    143                 CheckBox cb = (CheckBox)view.findViewById(R.id.city_onoff);
    144                 cb.setTag(c);
    145                 cb.setChecked(mSelectedCitiesList.containsKey(c.mCityId));
    146                 cb.setOnCheckedChangeListener(CitiesActivity.this);
    147                 mCalendar.setTimeZone(TimeZone.getTimeZone(c.mTimeZone));
    148                 tz.setText(DateFormat.format(mIs24HoursMode ? "k:mm" : "h:mmaa", mCalendar));
    149                 name.setText(c.mCityName);
    150             }
    151             return view;
    152         }
    153 
    154         public void set24HoursMode(Context c) {
    155             mIs24HoursMode = Alarms.get24HourMode(c);
    156             notifyDataSetChanged();
    157         }
    158 
    159         private void loadCitiesDataBase(Context c) {
    160             Resources r = c.getResources();
    161             // Read strings array of name,timezone, id
    162             // make sure the list are the same length
    163             String [] cities = r.getStringArray(R.array.cities_names);
    164             String [] timezones = r.getStringArray(R.array.cities_tz);
    165             String [] ids = r.getStringArray(R.array.cities_id);
    166             if (cities.length != timezones.length || ids.length != cities.length) {
    167                 Log.wtf("City lists sizes are not the same, cannot use the data");
    168                 return;
    169              }
    170              CityObj[] tempList = new CityObj [cities.length];
    171              for (int i = 0; i < cities.length; i++) {
    172                 tempList[i] = new CityObj(cities[i], timezones[i], ids[i]);
    173              }
    174              // Sort alphabetically
    175             Arrays.sort(tempList, new Comparator<CityObj> () {
    176                 @Override
    177                 public int compare(CityObj c1, CityObj c2) {
    178                     return mCollator.compare(c1.mCityName, c2.mCityName);
    179                 }
    180             });
    181             //Create section indexer and add headers to the cities list
    182             String val = null;
    183             ArrayList<String> sections = new ArrayList<String> ();
    184             ArrayList<Integer> positions = new ArrayList<Integer> ();
    185             ArrayList<CityObj> items = new ArrayList<CityObj>();
    186             int count = 0;
    187             for (int i = 0; i < tempList.length; i++) {
    188                 CityObj city = tempList[i];
    189                 if (city.mCityId.equals(DELETED_ENTRY)) {
    190                     continue;
    191                 }
    192                 if (!city.mCityName.substring(0, 1).equals(val)) {
    193                     val = city.mCityName.substring(0, 1);
    194                     sections.add((new String(val)).toUpperCase());
    195                     positions.add(count);
    196                     // Add a header
    197                     items.add(new CityObj(val, null, null));
    198                     count++;
    199                 }
    200                 items.add(city);
    201                 count++;
    202             }
    203             mSectionHeaders = sections.toArray();
    204             mSectionPositions = positions.toArray();
    205             mAllTheCitiesList = items.toArray();
    206          }
    207 
    208         @Override
    209         public int getPositionForSection(int section) {
    210             return (Integer) mSectionPositions[section];
    211         }
    212 
    213         @Override
    214         public int getSectionForPosition(int p) {
    215             for (int i = 0; i < mSectionPositions.length - 1; i++) {
    216                 if (p >= (Integer)mSectionPositions[i] && p < (Integer)mSectionPositions[i + 1]) {
    217                     return i;
    218                 }
    219             }
    220             if (p >= (Integer)mSectionPositions[mSectionPositions.length - 1]) {
    221                 return mSectionPositions.length - 1;
    222             }
    223             return 0;
    224         }
    225 
    226         @Override
    227         public Object[] getSections() {
    228             return mSectionHeaders;
    229         }
    230     }
    231 
    232 
    233     @Override
    234     protected void onCreate(Bundle icicle) {
    235         super.onCreate(icicle);
    236         mFactory = LayoutInflater.from(this);
    237         updateLayout();
    238     }
    239 
    240     private void updateLayout() {
    241         setContentView(R.layout.cities_activity);
    242         mCitiesList = (ListView) findViewById(R.id.cities_list);
    243         mCitiesList.setFastScrollAlwaysVisible(true);
    244         mCitiesList.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
    245         mCitiesList.setFastScrollEnabled(true);
    246         mUserSelectedCities = Cities.readCitiesFromSharedPrefs(
    247                 PreferenceManager.getDefaultSharedPreferences(this));
    248         mAdapter = new CityAdapter(this, mUserSelectedCities, mFactory);
    249         mCitiesList.setAdapter(mAdapter);
    250         ActionBar actionBar = getActionBar();
    251         if (actionBar != null) {
    252             actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
    253         }
    254     }
    255 
    256     @Override
    257     public void onResume() {
    258         super.onResume();
    259         if (mAdapter != null) {
    260             mAdapter.set24HoursMode(this);
    261         }
    262     }
    263 
    264 
    265     @Override
    266     public void onPause() {
    267         super.onPause();
    268         Cities.saveCitiesToSharedPrefs(PreferenceManager.getDefaultSharedPreferences(this),
    269                 mUserSelectedCities);
    270         Intent i = new Intent(Cities.WORLDCLOCK_UPDATE_INTENT);
    271         sendBroadcast(i);
    272     }
    273 
    274     @Override
    275     public boolean onOptionsItemSelected(MenuItem item) {
    276         switch (item.getItemId()) {
    277             case R.id.menu_item_settings:
    278                 startActivity(new Intent(this, SettingsActivity.class));
    279                 return true;
    280             case R.id.menu_item_help:
    281                 Intent i = item.getIntent();
    282                 if (i != null) {
    283                     try {
    284                         startActivity(i);
    285                     } catch (ActivityNotFoundException e) {
    286                         // No activity found to match the intent - ignore
    287                     }
    288                 }
    289                 return true;
    290             case android.R.id.home:
    291                 Intent intent = new Intent(this, DeskClock.class);
    292                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    293                 startActivity(intent);
    294                 return true;
    295             default:
    296                 break;
    297         }
    298         return super.onOptionsItemSelected(item);
    299     }
    300 
    301     @Override
    302     public boolean onCreateOptionsMenu(Menu menu) {
    303         getMenuInflater().inflate(R.menu.cities_menu, menu);
    304         MenuItem help = menu.findItem(R.id.menu_item_help);
    305         if (help != null) {
    306             Utils.prepareHelpMenuItem(this, help);
    307         }
    308         return super.onCreateOptionsMenu(menu);
    309     }
    310 
    311     @Override
    312     public void onCheckedChanged(CompoundButton b, boolean checked) {
    313         CityObj c = (CityObj)b.getTag();
    314         if (checked) {
    315             mUserSelectedCities.put(c.mCityId, c);
    316         } else {
    317             mUserSelectedCities.remove(c.mCityId);
    318         }
    319     }
    320 
    321     @Override
    322     public void onClick(View v) {
    323         CompoundButton b = (CompoundButton)v.findViewById(R.id.city_onoff);
    324         boolean checked = b.isChecked();
    325         onCheckedChanged(b, checked);
    326         b.setChecked(!checked);
    327     }
    328 }
    329