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