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 17 package com.android.settings; 18 19 import android.app.Activity; 20 import android.app.DatePickerDialog; 21 import android.app.Dialog; 22 import android.app.TimePickerDialog; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.SharedPreferences; 28 import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 29 import android.os.Bundle; 30 import android.os.SystemClock; 31 import android.preference.CheckBoxPreference; 32 import android.preference.ListPreference; 33 import android.preference.Preference; 34 import android.preference.PreferenceScreen; 35 import android.provider.Settings; 36 import android.provider.Settings.SettingNotFoundException; 37 import android.text.format.DateFormat; 38 import android.widget.DatePicker; 39 import android.widget.TimePicker; 40 41 import java.util.Calendar; 42 import java.util.Date; 43 import java.util.TimeZone; 44 45 public 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.System.AUTO_TIME); 85 boolean autoTimeZoneEnabled = getAutoState(Settings.System.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 mDummyDate.set(now.get(Calendar.YEAR), 11, 31, 13, 0, 0); 175 Date dummyDate = mDummyDate.getTime(); 176 mTimePref.setSummary(DateFormat.getTimeFormat(getActivity()).format(now.getTime())); 177 mTimeZone.setSummary(getTimeZoneText(now.getTimeZone())); 178 mDatePref.setSummary(shortDateFormat.format(now.getTime())); 179 mDateFormat.setSummary(shortDateFormat.format(dummyDate)); 180 } 181 182 @Override 183 public void onDateSet(DatePicker view, int year, int month, int day) { 184 setDate(year, month, day); 185 final Activity activity = getActivity(); 186 if (activity != null) { 187 updateTimeAndDateDisplay(activity); 188 } 189 } 190 191 @Override 192 public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 193 setTime(hourOfDay, minute); 194 final Activity activity = getActivity(); 195 if (activity != null) { 196 updateTimeAndDateDisplay(activity); 197 } 198 199 // We don't need to call timeUpdated() here because the TIME_CHANGED 200 // broadcast is sent by the AlarmManager as a side effect of setting the 201 // SystemClock time. 202 } 203 204 @Override 205 public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { 206 if (key.equals(KEY_DATE_FORMAT)) { 207 String format = preferences.getString(key, 208 getResources().getString(R.string.default_date_format)); 209 Settings.System.putString(getContentResolver(), 210 Settings.System.DATE_FORMAT, format); 211 updateTimeAndDateDisplay(getActivity()); 212 } else if (key.equals(KEY_AUTO_TIME)) { 213 boolean autoEnabled = preferences.getBoolean(key, true); 214 Settings.System.putInt(getContentResolver(), Settings.System.AUTO_TIME, 215 autoEnabled ? 1 : 0); 216 mTimePref.setEnabled(!autoEnabled); 217 mDatePref.setEnabled(!autoEnabled); 218 } else if (key.equals(KEY_AUTO_TIME_ZONE)) { 219 boolean autoZoneEnabled = preferences.getBoolean(key, true); 220 Settings.System.putInt( 221 getContentResolver(), Settings.System.AUTO_TIME_ZONE, autoZoneEnabled ? 1 : 0); 222 mTimeZone.setEnabled(!autoZoneEnabled); 223 } 224 } 225 226 @Override 227 public Dialog onCreateDialog(int id) { 228 Dialog d; 229 230 switch (id) { 231 case DIALOG_DATEPICKER: { 232 final Calendar calendar = Calendar.getInstance(); 233 d = new DatePickerDialog( 234 getActivity(), 235 this, 236 calendar.get(Calendar.YEAR), 237 calendar.get(Calendar.MONTH), 238 calendar.get(Calendar.DAY_OF_MONTH)); 239 break; 240 } 241 case DIALOG_TIMEPICKER: { 242 final Calendar calendar = Calendar.getInstance(); 243 d = new TimePickerDialog( 244 getActivity(), 245 this, 246 calendar.get(Calendar.HOUR_OF_DAY), 247 calendar.get(Calendar.MINUTE), 248 DateFormat.is24HourFormat(getActivity())); 249 break; 250 } 251 default: 252 d = null; 253 break; 254 } 255 256 return d; 257 } 258 259 /* 260 @Override 261 public void onPrepareDialog(int id, Dialog d) { 262 switch (id) { 263 case DIALOG_DATEPICKER: { 264 DatePickerDialog datePicker = (DatePickerDialog)d; 265 final Calendar calendar = Calendar.getInstance(); 266 datePicker.updateDate( 267 calendar.get(Calendar.YEAR), 268 calendar.get(Calendar.MONTH), 269 calendar.get(Calendar.DAY_OF_MONTH)); 270 break; 271 } 272 case DIALOG_TIMEPICKER: { 273 TimePickerDialog timePicker = (TimePickerDialog)d; 274 final Calendar calendar = Calendar.getInstance(); 275 timePicker.updateTime( 276 calendar.get(Calendar.HOUR_OF_DAY), 277 calendar.get(Calendar.MINUTE)); 278 break; 279 } 280 default: 281 break; 282 } 283 } 284 */ 285 @Override 286 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 287 if (preference == mDatePref) { 288 showDialog(DIALOG_DATEPICKER); 289 } else if (preference == mTimePref) { 290 // The 24-hour mode may have changed, so recreate the dialog 291 removeDialog(DIALOG_TIMEPICKER); 292 showDialog(DIALOG_TIMEPICKER); 293 } else if (preference == mTime24Pref) { 294 set24Hour(((CheckBoxPreference)mTime24Pref).isChecked()); 295 updateTimeAndDateDisplay(getActivity()); 296 timeUpdated(); 297 } 298 return super.onPreferenceTreeClick(preferenceScreen, preference); 299 } 300 301 @Override 302 public void onActivityResult(int requestCode, int resultCode, 303 Intent data) { 304 updateTimeAndDateDisplay(getActivity()); 305 } 306 307 private void timeUpdated() { 308 Intent timeChanged = new Intent(Intent.ACTION_TIME_CHANGED); 309 getActivity().sendBroadcast(timeChanged); 310 } 311 312 /* Get & Set values from the system settings */ 313 314 private boolean is24Hour() { 315 return DateFormat.is24HourFormat(getActivity()); 316 } 317 318 private void set24Hour(boolean is24Hour) { 319 Settings.System.putString(getContentResolver(), 320 Settings.System.TIME_12_24, 321 is24Hour? HOURS_24 : HOURS_12); 322 } 323 324 private String getDateFormat() { 325 return Settings.System.getString(getContentResolver(), 326 Settings.System.DATE_FORMAT); 327 } 328 329 private boolean getAutoState(String name) { 330 try { 331 return Settings.System.getInt(getContentResolver(), name) > 0; 332 } catch (SettingNotFoundException snfe) { 333 return false; 334 } 335 } 336 337 /* Helper routines to format timezone */ 338 339 /* package */ static void setDate(int year, int month, int day) { 340 Calendar c = Calendar.getInstance(); 341 342 c.set(Calendar.YEAR, year); 343 c.set(Calendar.MONTH, month); 344 c.set(Calendar.DAY_OF_MONTH, day); 345 long when = c.getTimeInMillis(); 346 347 if (when / 1000 < Integer.MAX_VALUE) { 348 SystemClock.setCurrentTimeMillis(when); 349 } 350 } 351 352 /* package */ static void setTime(int hourOfDay, int minute) { 353 Calendar c = Calendar.getInstance(); 354 355 c.set(Calendar.HOUR_OF_DAY, hourOfDay); 356 c.set(Calendar.MINUTE, minute); 357 c.set(Calendar.SECOND, 0); 358 c.set(Calendar.MILLISECOND, 0); 359 long when = c.getTimeInMillis(); 360 361 if (when / 1000 < Integer.MAX_VALUE) { 362 SystemClock.setCurrentTimeMillis(when); 363 } 364 } 365 366 /* package */ static String getTimeZoneText(TimeZone tz) { 367 boolean daylight = tz.inDaylightTime(new Date()); 368 StringBuilder sb = new StringBuilder(); 369 370 sb.append(formatOffset(tz.getRawOffset() + 371 (daylight ? tz.getDSTSavings() : 0))). 372 append(", "). 373 append(tz.getDisplayName(daylight, TimeZone.LONG)); 374 375 return sb.toString(); 376 } 377 378 private static char[] formatOffset(int off) { 379 off = off / 1000 / 60; 380 381 char[] buf = new char[9]; 382 buf[0] = 'G'; 383 buf[1] = 'M'; 384 buf[2] = 'T'; 385 386 if (off < 0) { 387 buf[3] = '-'; 388 off = -off; 389 } else { 390 buf[3] = '+'; 391 } 392 393 int hours = off / 60; 394 int minutes = off % 60; 395 396 buf[4] = (char) ('0' + hours / 10); 397 buf[5] = (char) ('0' + hours % 10); 398 399 buf[6] = ':'; 400 401 buf[7] = (char) ('0' + minutes / 10); 402 buf[8] = (char) ('0' + minutes % 10); 403 404 return buf; 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