DateTimeSettings.java revision f1c085899dd3d9142392b9ab7841c0e9502526a3
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 for (int i = 0; i < formattedDates.length; i++) { 122 String formatted = 123 DateFormat.getDateFormatForSetting(getActivity(), dateFormats[i]) 124 .format(mDummyDate.getTime()); 125 126 if (dateFormats[i].length() == 0) { 127 formattedDates[i] = getResources(). 128 getString(R.string.normal_date_format, formatted); 129 } else { 130 formattedDates[i] = formatted; 131 } 132 } 133 134 mDateFormat.setEntries(formattedDates); 135 mDateFormat.setEntryValues(R.array.date_format_values); 136 mDateFormat.setValue(currentFormat); 137 138 mTimePref.setEnabled(!autoTimeEnabled); 139 mDatePref.setEnabled(!autoTimeEnabled); 140 mTimeZone.setEnabled(!autoTimeZoneEnabled); 141 } 142 143 @Override 144 public void onResume() { 145 super.onResume(); 146 147 getPreferenceScreen().getSharedPreferences() 148 .registerOnSharedPreferenceChangeListener(this); 149 150 ((CheckBoxPreference)mTime24Pref).setChecked(is24Hour()); 151 152 // Register for time ticks and other reasons for time change 153 IntentFilter filter = new IntentFilter(); 154 filter.addAction(Intent.ACTION_TIME_TICK); 155 filter.addAction(Intent.ACTION_TIME_CHANGED); 156 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 157 getActivity().registerReceiver(mIntentReceiver, filter, null, null); 158 159 updateTimeAndDateDisplay(getActivity()); 160 } 161 162 @Override 163 public void onPause() { 164 super.onPause(); 165 getActivity().unregisterReceiver(mIntentReceiver); 166 getPreferenceScreen().getSharedPreferences() 167 .unregisterOnSharedPreferenceChangeListener(this); 168 } 169 170 public void updateTimeAndDateDisplay(Context context) { 171 java.text.DateFormat shortDateFormat = DateFormat.getDateFormat(context); 172 final Calendar now = Calendar.getInstance(); 173 mDummyDate.setTimeZone(now.getTimeZone()); 174 // We use December 31st because it's unambiguous when demonstrating the date format. 175 // We use 13:00 so we can demonstrate the 12/24 hour options. 176 mDummyDate.set(now.get(Calendar.YEAR), 11, 31, 13, 0, 0); 177 Date dummyDate = mDummyDate.getTime(); 178 mTimePref.setSummary(DateFormat.getTimeFormat(getActivity()).format(now.getTime())); 179 mTimeZone.setSummary(getTimeZoneText(now.getTimeZone())); 180 mDatePref.setSummary(shortDateFormat.format(now.getTime())); 181 mDateFormat.setSummary(shortDateFormat.format(dummyDate)); 182 mTime24Pref.setSummary(DateFormat.getTimeFormat(getActivity()).format(dummyDate)); 183 } 184 185 @Override 186 public void onDateSet(DatePicker view, int year, int month, int day) { 187 setDate(year, month, day); 188 final Activity activity = getActivity(); 189 if (activity != null) { 190 updateTimeAndDateDisplay(activity); 191 } 192 } 193 194 @Override 195 public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 196 setTime(hourOfDay, minute); 197 final Activity activity = getActivity(); 198 if (activity != null) { 199 updateTimeAndDateDisplay(activity); 200 } 201 202 // We don't need to call timeUpdated() here because the TIME_CHANGED 203 // broadcast is sent by the AlarmManager as a side effect of setting the 204 // SystemClock time. 205 } 206 207 @Override 208 public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { 209 if (key.equals(KEY_DATE_FORMAT)) { 210 String format = preferences.getString(key, 211 getResources().getString(R.string.default_date_format)); 212 Settings.System.putString(getContentResolver(), 213 Settings.System.DATE_FORMAT, format); 214 updateTimeAndDateDisplay(getActivity()); 215 } else if (key.equals(KEY_AUTO_TIME)) { 216 boolean autoEnabled = preferences.getBoolean(key, true); 217 Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME, 218 autoEnabled ? 1 : 0); 219 mTimePref.setEnabled(!autoEnabled); 220 mDatePref.setEnabled(!autoEnabled); 221 } else if (key.equals(KEY_AUTO_TIME_ZONE)) { 222 boolean autoZoneEnabled = preferences.getBoolean(key, true); 223 Settings.Global.putInt( 224 getContentResolver(), Settings.Global.AUTO_TIME_ZONE, autoZoneEnabled ? 1 : 0); 225 mTimeZone.setEnabled(!autoZoneEnabled); 226 } 227 } 228 229 @Override 230 public Dialog onCreateDialog(int id) { 231 Dialog d; 232 233 switch (id) { 234 case DIALOG_DATEPICKER: { 235 final Calendar calendar = Calendar.getInstance(); 236 d = new DatePickerDialog( 237 getActivity(), 238 this, 239 calendar.get(Calendar.YEAR), 240 calendar.get(Calendar.MONTH), 241 calendar.get(Calendar.DAY_OF_MONTH)); 242 break; 243 } 244 case DIALOG_TIMEPICKER: { 245 final Calendar calendar = Calendar.getInstance(); 246 d = new TimePickerDialog( 247 getActivity(), 248 this, 249 calendar.get(Calendar.HOUR_OF_DAY), 250 calendar.get(Calendar.MINUTE), 251 DateFormat.is24HourFormat(getActivity())); 252 break; 253 } 254 default: 255 d = null; 256 break; 257 } 258 259 return d; 260 } 261 262 /* 263 @Override 264 public void onPrepareDialog(int id, Dialog d) { 265 switch (id) { 266 case DIALOG_DATEPICKER: { 267 DatePickerDialog datePicker = (DatePickerDialog)d; 268 final Calendar calendar = Calendar.getInstance(); 269 datePicker.updateDate( 270 calendar.get(Calendar.YEAR), 271 calendar.get(Calendar.MONTH), 272 calendar.get(Calendar.DAY_OF_MONTH)); 273 break; 274 } 275 case DIALOG_TIMEPICKER: { 276 TimePickerDialog timePicker = (TimePickerDialog)d; 277 final Calendar calendar = Calendar.getInstance(); 278 timePicker.updateTime( 279 calendar.get(Calendar.HOUR_OF_DAY), 280 calendar.get(Calendar.MINUTE)); 281 break; 282 } 283 default: 284 break; 285 } 286 } 287 */ 288 @Override 289 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 290 if (preference == mDatePref) { 291 showDialog(DIALOG_DATEPICKER); 292 } else if (preference == mTimePref) { 293 // The 24-hour mode may have changed, so recreate the dialog 294 removeDialog(DIALOG_TIMEPICKER); 295 showDialog(DIALOG_TIMEPICKER); 296 } else if (preference == mTime24Pref) { 297 set24Hour(((CheckBoxPreference)mTime24Pref).isChecked()); 298 updateTimeAndDateDisplay(getActivity()); 299 timeUpdated(); 300 } 301 return super.onPreferenceTreeClick(preferenceScreen, preference); 302 } 303 304 @Override 305 public void onActivityResult(int requestCode, int resultCode, 306 Intent data) { 307 updateTimeAndDateDisplay(getActivity()); 308 } 309 310 private void timeUpdated() { 311 Intent timeChanged = new Intent(Intent.ACTION_TIME_CHANGED); 312 getActivity().sendBroadcast(timeChanged); 313 } 314 315 /* Get & Set values from the system settings */ 316 317 private boolean is24Hour() { 318 return DateFormat.is24HourFormat(getActivity()); 319 } 320 321 private void set24Hour(boolean is24Hour) { 322 Settings.System.putString(getContentResolver(), 323 Settings.System.TIME_12_24, 324 is24Hour? HOURS_24 : HOURS_12); 325 } 326 327 private String getDateFormat() { 328 return Settings.System.getString(getContentResolver(), 329 Settings.System.DATE_FORMAT); 330 } 331 332 private boolean getAutoState(String name) { 333 try { 334 return Settings.Global.getInt(getContentResolver(), name) > 0; 335 } catch (SettingNotFoundException snfe) { 336 return false; 337 } 338 } 339 340 /* package */ static void setDate(int year, int month, int day) { 341 Calendar c = Calendar.getInstance(); 342 343 c.set(Calendar.YEAR, year); 344 c.set(Calendar.MONTH, month); 345 c.set(Calendar.DAY_OF_MONTH, day); 346 long when = c.getTimeInMillis(); 347 348 if (when / 1000 < Integer.MAX_VALUE) { 349 SystemClock.setCurrentTimeMillis(when); 350 } 351 } 352 353 /* package */ static void setTime(int hourOfDay, int minute) { 354 Calendar c = Calendar.getInstance(); 355 356 c.set(Calendar.HOUR_OF_DAY, hourOfDay); 357 c.set(Calendar.MINUTE, minute); 358 c.set(Calendar.SECOND, 0); 359 c.set(Calendar.MILLISECOND, 0); 360 long when = c.getTimeInMillis(); 361 362 if (when / 1000 < Integer.MAX_VALUE) { 363 SystemClock.setCurrentTimeMillis(when); 364 } 365 } 366 367 /* Helper routines to format timezone */ 368 369 /* package */ static String getTimeZoneText(TimeZone tz) { 370 // Similar to new SimpleDateFormat("'GMT'Z, zzzz").format(new Date()), but 371 // we want "GMT-03:00" rather than "GMT-0300". 372 Date now = new Date(); 373 return formatOffset(new StringBuilder(), tz, now). 374 append(", "). 375 append(tz.getDisplayName(tz.inDaylightTime(now), TimeZone.LONG)).toString(); 376 } 377 378 private static StringBuilder formatOffset(StringBuilder sb, TimeZone tz, Date d) { 379 int off = tz.getOffset(d.getTime()) / 1000 / 60; 380 381 sb.append("GMT"); 382 if (off < 0) { 383 sb.append('-'); 384 off = -off; 385 } else { 386 sb.append('+'); 387 } 388 389 int hours = off / 60; 390 int minutes = off % 60; 391 392 sb.append((char) ('0' + hours / 10)); 393 sb.append((char) ('0' + hours % 10)); 394 395 sb.append(':'); 396 397 sb.append((char) ('0' + minutes / 10)); 398 sb.append((char) ('0' + minutes % 10)); 399 400 return sb; 401 } 402 403 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 404 @Override 405 public void onReceive(Context context, Intent intent) { 406 final Activity activity = getActivity(); 407 if (activity != null) { 408 updateTimeAndDateDisplay(activity); 409 } 410 } 411 }; 412} 413