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