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