DateTimeSettings.java revision 797d620084df296b1d1d3e3c03d519fdf916f2d3
1/* 2 * Copyright (C) 2008 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 17package com.android.settings; 18 19import android.app.Activity; 20import android.app.DatePickerDialog; 21import android.app.Dialog; 22import android.app.TimePickerDialog; 23import android.content.BroadcastReceiver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.content.SharedPreferences; 28import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 29import android.os.Bundle; 30import android.os.SystemClock; 31import android.preference.CheckBoxPreference; 32import android.preference.ListPreference; 33import android.preference.Preference; 34import android.preference.PreferenceScreen; 35import android.provider.Settings; 36import android.provider.Settings.SettingNotFoundException; 37import android.text.format.DateFormat; 38import android.widget.DatePicker; 39import android.widget.TimePicker; 40 41import java.util.Calendar; 42import java.util.Date; 43import java.util.TimeZone; 44 45public class DateTimeSettings extends SettingsPreferenceFragment 46 implements OnSharedPreferenceChangeListener, 47 TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener { 48 49 private static final String HOURS_12 = "12"; 50 private static final String HOURS_24 = "24"; 51 52 // Used for showing the current date format, which looks like "12/31/2010", "2010/12/13", etc. 53 // The date value is dummy (independent of actual date). 54 private Calendar mDummyDate; 55 56 private static final String KEY_DATE_FORMAT = "date_format"; 57 private static final String KEY_AUTO_TIME = "auto_time"; 58 private static final String KEY_AUTO_TIME_ZONE = "auto_zone"; 59 60 private static final int DIALOG_DATEPICKER = 0; 61 private static final int DIALOG_TIMEPICKER = 1; 62 63 // have we been launched from the setup wizard? 64 protected static final String EXTRA_IS_FIRST_RUN = "firstRun"; 65 66 private CheckBoxPreference mAutoTimePref; 67 private Preference mTimePref; 68 private Preference mTime24Pref; 69 private CheckBoxPreference mAutoTimeZonePref; 70 private Preference mTimeZone; 71 private Preference mDatePref; 72 private ListPreference mDateFormat; 73 74 @Override 75 public void onCreate(Bundle icicle) { 76 super.onCreate(icicle); 77 78 addPreferencesFromResource(R.xml.date_time_prefs); 79 80 initUI(); 81 } 82 83 private void initUI() { 84 boolean autoTimeEnabled = getAutoState(Settings.Global.AUTO_TIME); 85 boolean autoTimeZoneEnabled = getAutoState(Settings.Global.AUTO_TIME_ZONE); 86 87 Intent intent = getActivity().getIntent(); 88 boolean isFirstRun = intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false); 89 90 mDummyDate = Calendar.getInstance(); 91 92 mAutoTimePref = (CheckBoxPreference) findPreference(KEY_AUTO_TIME); 93 mAutoTimePref.setChecked(autoTimeEnabled); 94 mAutoTimeZonePref = (CheckBoxPreference) findPreference(KEY_AUTO_TIME_ZONE); 95 // Override auto-timezone if it's a wifi-only device or if we're still in setup wizard. 96 // TODO: Remove the wifiOnly test when auto-timezone is implemented based on wifi-location. 97 if (Utils.isWifiOnly(getActivity()) || isFirstRun) { 98 getPreferenceScreen().removePreference(mAutoTimeZonePref); 99 autoTimeZoneEnabled = false; 100 } 101 mAutoTimeZonePref.setChecked(autoTimeZoneEnabled); 102 103 mTimePref = findPreference("time"); 104 mTime24Pref = findPreference("24 hour"); 105 mTimeZone = findPreference("timezone"); 106 mDatePref = findPreference("date"); 107 mDateFormat = (ListPreference) findPreference(KEY_DATE_FORMAT); 108 if (isFirstRun) { 109 getPreferenceScreen().removePreference(mTime24Pref); 110 getPreferenceScreen().removePreference(mDateFormat); 111 } 112 113 String [] dateFormats = getResources().getStringArray(R.array.date_format_values); 114 String [] formattedDates = new String[dateFormats.length]; 115 String currentFormat = getDateFormat(); 116 // Initialize if DATE_FORMAT is not set in the system settings 117 // This can happen after a factory reset (or data wipe) 118 if (currentFormat == null) { 119 currentFormat = ""; 120 } 121 122 // Prevents duplicated values on date format selector. 123 mDummyDate.set(mDummyDate.get(Calendar.YEAR), mDummyDate.DECEMBER, 31, 13, 0, 0); 124 125 for (int i = 0; i < formattedDates.length; i++) { 126 String formatted = 127 DateFormat.getDateFormatForSetting(getActivity(), dateFormats[i]) 128 .format(mDummyDate.getTime()); 129 130 if (dateFormats[i].length() == 0) { 131 formattedDates[i] = getResources(). 132 getString(R.string.normal_date_format, formatted); 133 } else { 134 formattedDates[i] = formatted; 135 } 136 } 137 138 mDateFormat.setEntries(formattedDates); 139 mDateFormat.setEntryValues(R.array.date_format_values); 140 mDateFormat.setValue(currentFormat); 141 142 mTimePref.setEnabled(!autoTimeEnabled); 143 mDatePref.setEnabled(!autoTimeEnabled); 144 mTimeZone.setEnabled(!autoTimeZoneEnabled); 145 } 146 147 @Override 148 public void onResume() { 149 super.onResume(); 150 151 getPreferenceScreen().getSharedPreferences() 152 .registerOnSharedPreferenceChangeListener(this); 153 154 ((CheckBoxPreference)mTime24Pref).setChecked(is24Hour()); 155 156 // Register for time ticks and other reasons for time change 157 IntentFilter filter = new IntentFilter(); 158 filter.addAction(Intent.ACTION_TIME_TICK); 159 filter.addAction(Intent.ACTION_TIME_CHANGED); 160 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 161 getActivity().registerReceiver(mIntentReceiver, filter, null, null); 162 163 updateTimeAndDateDisplay(getActivity()); 164 } 165 166 @Override 167 public void onPause() { 168 super.onPause(); 169 getActivity().unregisterReceiver(mIntentReceiver); 170 getPreferenceScreen().getSharedPreferences() 171 .unregisterOnSharedPreferenceChangeListener(this); 172 } 173 174 public void updateTimeAndDateDisplay(Context context) { 175 java.text.DateFormat shortDateFormat = DateFormat.getDateFormat(context); 176 final Calendar now = Calendar.getInstance(); 177 mDummyDate.setTimeZone(now.getTimeZone()); 178 // We use December 31st because it's unambiguous when demonstrating the date format. 179 // We use 13:00 so we can demonstrate the 12/24 hour options. 180 mDummyDate.set(now.get(Calendar.YEAR), 11, 31, 13, 0, 0); 181 Date dummyDate = mDummyDate.getTime(); 182 mTimePref.setSummary(DateFormat.getTimeFormat(getActivity()).format(now.getTime())); 183 mTimeZone.setSummary(getTimeZoneText(now.getTimeZone())); 184 mDatePref.setSummary(shortDateFormat.format(now.getTime())); 185 mDateFormat.setSummary(shortDateFormat.format(dummyDate)); 186 mTime24Pref.setSummary(DateFormat.getTimeFormat(getActivity()).format(dummyDate)); 187 } 188 189 @Override 190 public void onDateSet(DatePicker view, int year, int month, int day) { 191 setDate(year, month, day); 192 final Activity activity = getActivity(); 193 if (activity != null) { 194 updateTimeAndDateDisplay(activity); 195 } 196 } 197 198 @Override 199 public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 200 setTime(hourOfDay, minute); 201 final Activity activity = getActivity(); 202 if (activity != null) { 203 updateTimeAndDateDisplay(activity); 204 } 205 206 // We don't need to call timeUpdated() here because the TIME_CHANGED 207 // broadcast is sent by the AlarmManager as a side effect of setting the 208 // SystemClock time. 209 } 210 211 @Override 212 public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { 213 if (key.equals(KEY_DATE_FORMAT)) { 214 String format = preferences.getString(key, 215 getResources().getString(R.string.default_date_format)); 216 Settings.System.putString(getContentResolver(), 217 Settings.System.DATE_FORMAT, format); 218 updateTimeAndDateDisplay(getActivity()); 219 } else if (key.equals(KEY_AUTO_TIME)) { 220 boolean autoEnabled = preferences.getBoolean(key, true); 221 Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME, 222 autoEnabled ? 1 : 0); 223 mTimePref.setEnabled(!autoEnabled); 224 mDatePref.setEnabled(!autoEnabled); 225 } else if (key.equals(KEY_AUTO_TIME_ZONE)) { 226 boolean autoZoneEnabled = preferences.getBoolean(key, true); 227 Settings.Global.putInt( 228 getContentResolver(), Settings.Global.AUTO_TIME_ZONE, autoZoneEnabled ? 1 : 0); 229 mTimeZone.setEnabled(!autoZoneEnabled); 230 } 231 } 232 233 @Override 234 public Dialog onCreateDialog(int id) { 235 Dialog d; 236 237 switch (id) { 238 case DIALOG_DATEPICKER: { 239 final Calendar calendar = Calendar.getInstance(); 240 d = new DatePickerDialog( 241 getActivity(), 242 this, 243 calendar.get(Calendar.YEAR), 244 calendar.get(Calendar.MONTH), 245 calendar.get(Calendar.DAY_OF_MONTH)); 246 break; 247 } 248 case DIALOG_TIMEPICKER: { 249 final Calendar calendar = Calendar.getInstance(); 250 d = new TimePickerDialog( 251 getActivity(), 252 this, 253 calendar.get(Calendar.HOUR_OF_DAY), 254 calendar.get(Calendar.MINUTE), 255 DateFormat.is24HourFormat(getActivity())); 256 break; 257 } 258 default: 259 d = null; 260 break; 261 } 262 263 return d; 264 } 265 266 /* 267 @Override 268 public void onPrepareDialog(int id, Dialog d) { 269 switch (id) { 270 case DIALOG_DATEPICKER: { 271 DatePickerDialog datePicker = (DatePickerDialog)d; 272 final Calendar calendar = Calendar.getInstance(); 273 datePicker.updateDate( 274 calendar.get(Calendar.YEAR), 275 calendar.get(Calendar.MONTH), 276 calendar.get(Calendar.DAY_OF_MONTH)); 277 break; 278 } 279 case DIALOG_TIMEPICKER: { 280 TimePickerDialog timePicker = (TimePickerDialog)d; 281 final Calendar calendar = Calendar.getInstance(); 282 timePicker.updateTime( 283 calendar.get(Calendar.HOUR_OF_DAY), 284 calendar.get(Calendar.MINUTE)); 285 break; 286 } 287 default: 288 break; 289 } 290 } 291 */ 292 @Override 293 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 294 if (preference == mDatePref) { 295 showDialog(DIALOG_DATEPICKER); 296 } else if (preference == mTimePref) { 297 // The 24-hour mode may have changed, so recreate the dialog 298 removeDialog(DIALOG_TIMEPICKER); 299 showDialog(DIALOG_TIMEPICKER); 300 } else if (preference == mTime24Pref) { 301 set24Hour(((CheckBoxPreference)mTime24Pref).isChecked()); 302 updateTimeAndDateDisplay(getActivity()); 303 timeUpdated(); 304 } 305 return super.onPreferenceTreeClick(preferenceScreen, preference); 306 } 307 308 @Override 309 public void onActivityResult(int requestCode, int resultCode, 310 Intent data) { 311 updateTimeAndDateDisplay(getActivity()); 312 } 313 314 private void timeUpdated() { 315 Intent timeChanged = new Intent(Intent.ACTION_TIME_CHANGED); 316 getActivity().sendBroadcast(timeChanged); 317 } 318 319 /* Get & Set values from the system settings */ 320 321 private boolean is24Hour() { 322 return DateFormat.is24HourFormat(getActivity()); 323 } 324 325 private void set24Hour(boolean is24Hour) { 326 Settings.System.putString(getContentResolver(), 327 Settings.System.TIME_12_24, 328 is24Hour? HOURS_24 : HOURS_12); 329 } 330 331 private String getDateFormat() { 332 return Settings.System.getString(getContentResolver(), 333 Settings.System.DATE_FORMAT); 334 } 335 336 private boolean getAutoState(String name) { 337 try { 338 return Settings.Global.getInt(getContentResolver(), name) > 0; 339 } catch (SettingNotFoundException snfe) { 340 return false; 341 } 342 } 343 344 /* package */ static void setDate(int year, int month, int day) { 345 Calendar c = Calendar.getInstance(); 346 347 c.set(Calendar.YEAR, year); 348 c.set(Calendar.MONTH, month); 349 c.set(Calendar.DAY_OF_MONTH, day); 350 long when = c.getTimeInMillis(); 351 352 if (when / 1000 < Integer.MAX_VALUE) { 353 SystemClock.setCurrentTimeMillis(when); 354 } 355 } 356 357 /* package */ static void setTime(int hourOfDay, int minute) { 358 Calendar c = Calendar.getInstance(); 359 360 c.set(Calendar.HOUR_OF_DAY, hourOfDay); 361 c.set(Calendar.MINUTE, minute); 362 c.set(Calendar.SECOND, 0); 363 c.set(Calendar.MILLISECOND, 0); 364 long when = c.getTimeInMillis(); 365 366 if (when / 1000 < Integer.MAX_VALUE) { 367 SystemClock.setCurrentTimeMillis(when); 368 } 369 } 370 371 /* Helper routines to format timezone */ 372 373 /* package */ static String getTimeZoneText(TimeZone tz) { 374 // Similar to new SimpleDateFormat("'GMT'Z, zzzz").format(new Date()), but 375 // we want "GMT-03:00" rather than "GMT-0300". 376 Date now = new Date(); 377 return formatOffset(new StringBuilder(), tz, now). 378 append(", "). 379 append(tz.getDisplayName(tz.inDaylightTime(now), TimeZone.LONG)).toString(); 380 } 381 382 private static StringBuilder formatOffset(StringBuilder sb, TimeZone tz, Date d) { 383 int off = tz.getOffset(d.getTime()) / 1000 / 60; 384 385 sb.append("GMT"); 386 if (off < 0) { 387 sb.append('-'); 388 off = -off; 389 } else { 390 sb.append('+'); 391 } 392 393 int hours = off / 60; 394 int minutes = off % 60; 395 396 sb.append((char) ('0' + hours / 10)); 397 sb.append((char) ('0' + hours % 10)); 398 399 sb.append(':'); 400 401 sb.append((char) ('0' + minutes / 10)); 402 sb.append((char) ('0' + minutes % 10)); 403 404 return sb; 405 } 406 407 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 408 @Override 409 public void onReceive(Context context, Intent intent) { 410 final Activity activity = getActivity(); 411 if (activity != null) { 412 updateTimeAndDateDisplay(activity); 413 } 414 } 415 }; 416} 417