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