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.app.admin.DevicePolicyManager; 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.Preference; 33import android.preference.PreferenceScreen; 34import android.preference.SwitchPreference; 35import android.provider.Settings; 36import android.provider.Settings.SettingNotFoundException; 37import android.text.format.DateFormat; 38import android.widget.DatePicker; 39import android.widget.TimePicker; 40 41import com.android.internal.logging.MetricsLogger; 42import com.android.settingslib.datetime.ZoneGetter; 43 44import java.util.Calendar; 45import java.util.Date; 46 47public 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_AUTO_TIME = "auto_time"; 59 private static final String KEY_AUTO_TIME_ZONE = "auto_zone"; 60 61 private static final int DIALOG_DATEPICKER = 0; 62 private static final int DIALOG_TIMEPICKER = 1; 63 64 // have we been launched from the setup wizard? 65 protected static final String EXTRA_IS_FIRST_RUN = "firstRun"; 66 67 private SwitchPreference mAutoTimePref; 68 private Preference mTimePref; 69 private Preference mTime24Pref; 70 private SwitchPreference mAutoTimeZonePref; 71 private Preference mTimeZone; 72 private Preference mDatePref; 73 74 @Override 75 protected int getMetricsCategory() { 76 return MetricsLogger.DATE_TIME; 77 } 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 mAutoTimePref = (SwitchPreference) findPreference(KEY_AUTO_TIME); 93 94 DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context 95 .DEVICE_POLICY_SERVICE); 96 if (dpm.getAutoTimeRequired()) { 97 mAutoTimePref.setEnabled(false); 98 99 // If Settings.Global.AUTO_TIME is false it will be set to true 100 // by the device policy manager very soon. 101 // Note that this app listens to that change. 102 } 103 104 Intent intent = getActivity().getIntent(); 105 boolean isFirstRun = intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false); 106 107 mDummyDate = Calendar.getInstance(); 108 109 mAutoTimePref.setChecked(autoTimeEnabled); 110 mAutoTimeZonePref = (SwitchPreference) findPreference(KEY_AUTO_TIME_ZONE); 111 // Override auto-timezone if it's a wifi-only device or if we're still in setup wizard. 112 // TODO: Remove the wifiOnly test when auto-timezone is implemented based on wifi-location. 113 if (Utils.isWifiOnly(getActivity()) || isFirstRun) { 114 getPreferenceScreen().removePreference(mAutoTimeZonePref); 115 autoTimeZoneEnabled = false; 116 } 117 mAutoTimeZonePref.setChecked(autoTimeZoneEnabled); 118 119 mTimePref = findPreference("time"); 120 mTime24Pref = findPreference("24 hour"); 121 mTimeZone = findPreference("timezone"); 122 mDatePref = findPreference("date"); 123 if (isFirstRun) { 124 getPreferenceScreen().removePreference(mTime24Pref); 125 } 126 127 mTimePref.setEnabled(!autoTimeEnabled); 128 mDatePref.setEnabled(!autoTimeEnabled); 129 mTimeZone.setEnabled(!autoTimeZoneEnabled); 130 } 131 132 @Override 133 public void onResume() { 134 super.onResume(); 135 136 getPreferenceScreen().getSharedPreferences() 137 .registerOnSharedPreferenceChangeListener(this); 138 139 ((SwitchPreference)mTime24Pref).setChecked(is24Hour()); 140 141 // Register for time ticks and other reasons for time change 142 IntentFilter filter = new IntentFilter(); 143 filter.addAction(Intent.ACTION_TIME_TICK); 144 filter.addAction(Intent.ACTION_TIME_CHANGED); 145 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 146 getActivity().registerReceiver(mIntentReceiver, filter, null, null); 147 148 updateTimeAndDateDisplay(getActivity()); 149 } 150 151 @Override 152 public void onPause() { 153 super.onPause(); 154 getActivity().unregisterReceiver(mIntentReceiver); 155 getPreferenceScreen().getSharedPreferences() 156 .unregisterOnSharedPreferenceChangeListener(this); 157 } 158 159 public void updateTimeAndDateDisplay(Context context) { 160 final Calendar now = Calendar.getInstance(); 161 mDummyDate.setTimeZone(now.getTimeZone()); 162 // We use December 31st because it's unambiguous when demonstrating the date format. 163 // We use 13:00 so we can demonstrate the 12/24 hour options. 164 mDummyDate.set(now.get(Calendar.YEAR), 11, 31, 13, 0, 0); 165 Date dummyDate = mDummyDate.getTime(); 166 mDatePref.setSummary(DateFormat.getLongDateFormat(context).format(now.getTime())); 167 mTimePref.setSummary(DateFormat.getTimeFormat(getActivity()).format(now.getTime())); 168 mTimeZone.setSummary(ZoneGetter.getTimeZoneOffsetAndName(now.getTimeZone(), now.getTime())); 169 mTime24Pref.setSummary(DateFormat.getTimeFormat(getActivity()).format(dummyDate)); 170 } 171 172 @Override 173 public void onDateSet(DatePicker view, int year, int month, int day) { 174 final Activity activity = getActivity(); 175 if (activity != null) { 176 setDate(activity, year, month, day); 177 updateTimeAndDateDisplay(activity); 178 } 179 } 180 181 @Override 182 public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 183 final Activity activity = getActivity(); 184 if (activity != null) { 185 setTime(activity, hourOfDay, minute); 186 updateTimeAndDateDisplay(activity); 187 } 188 189 // We don't need to call timeUpdated() here because the TIME_CHANGED 190 // broadcast is sent by the AlarmManager as a side effect of setting the 191 // SystemClock time. 192 } 193 194 @Override 195 public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { 196 if (key.equals(KEY_AUTO_TIME)) { 197 boolean autoEnabled = preferences.getBoolean(key, true); 198 Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME, 199 autoEnabled ? 1 : 0); 200 mTimePref.setEnabled(!autoEnabled); 201 mDatePref.setEnabled(!autoEnabled); 202 } else if (key.equals(KEY_AUTO_TIME_ZONE)) { 203 boolean autoZoneEnabled = preferences.getBoolean(key, true); 204 Settings.Global.putInt( 205 getContentResolver(), Settings.Global.AUTO_TIME_ZONE, autoZoneEnabled ? 1 : 0); 206 mTimeZone.setEnabled(!autoZoneEnabled); 207 } 208 } 209 210 @Override 211 public Dialog onCreateDialog(int id) { 212 final Calendar calendar = Calendar.getInstance(); 213 switch (id) { 214 case DIALOG_DATEPICKER: 215 DatePickerDialog d = new DatePickerDialog( 216 getActivity(), 217 this, 218 calendar.get(Calendar.YEAR), 219 calendar.get(Calendar.MONTH), 220 calendar.get(Calendar.DAY_OF_MONTH)); 221 configureDatePicker(d.getDatePicker()); 222 return d; 223 case DIALOG_TIMEPICKER: 224 return new TimePickerDialog( 225 getActivity(), 226 this, 227 calendar.get(Calendar.HOUR_OF_DAY), 228 calendar.get(Calendar.MINUTE), 229 DateFormat.is24HourFormat(getActivity())); 230 default: 231 throw new IllegalArgumentException(); 232 } 233 } 234 235 static void configureDatePicker(DatePicker datePicker) { 236 // The system clock can't represent dates outside this range. 237 Calendar t = Calendar.getInstance(); 238 t.clear(); 239 t.set(1970, Calendar.JANUARY, 1); 240 datePicker.setMinDate(t.getTimeInMillis()); 241 t.clear(); 242 t.set(2037, Calendar.DECEMBER, 31); 243 datePicker.setMaxDate(t.getTimeInMillis()); 244 } 245 246 /* 247 @Override 248 public void onPrepareDialog(int id, Dialog d) { 249 switch (id) { 250 case DIALOG_DATEPICKER: { 251 DatePickerDialog datePicker = (DatePickerDialog)d; 252 final Calendar calendar = Calendar.getInstance(); 253 datePicker.updateDate( 254 calendar.get(Calendar.YEAR), 255 calendar.get(Calendar.MONTH), 256 calendar.get(Calendar.DAY_OF_MONTH)); 257 break; 258 } 259 case DIALOG_TIMEPICKER: { 260 TimePickerDialog timePicker = (TimePickerDialog)d; 261 final Calendar calendar = Calendar.getInstance(); 262 timePicker.updateTime( 263 calendar.get(Calendar.HOUR_OF_DAY), 264 calendar.get(Calendar.MINUTE)); 265 break; 266 } 267 default: 268 break; 269 } 270 } 271 */ 272 @Override 273 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 274 if (preference == mDatePref) { 275 showDialog(DIALOG_DATEPICKER); 276 } else if (preference == mTimePref) { 277 // The 24-hour mode may have changed, so recreate the dialog 278 removeDialog(DIALOG_TIMEPICKER); 279 showDialog(DIALOG_TIMEPICKER); 280 } else if (preference == mTime24Pref) { 281 final boolean is24Hour = ((SwitchPreference)mTime24Pref).isChecked(); 282 set24Hour(is24Hour); 283 updateTimeAndDateDisplay(getActivity()); 284 timeUpdated(is24Hour); 285 } 286 return super.onPreferenceTreeClick(preferenceScreen, preference); 287 } 288 289 @Override 290 public void onActivityResult(int requestCode, int resultCode, 291 Intent data) { 292 updateTimeAndDateDisplay(getActivity()); 293 } 294 295 private void timeUpdated(boolean is24Hour) { 296 Intent timeChanged = new Intent(Intent.ACTION_TIME_CHANGED); 297 timeChanged.putExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, is24Hour); 298 getActivity().sendBroadcast(timeChanged); 299 } 300 301 /* Get & Set values from the system settings */ 302 303 private boolean is24Hour() { 304 return DateFormat.is24HourFormat(getActivity()); 305 } 306 307 private void set24Hour(boolean is24Hour) { 308 Settings.System.putString(getContentResolver(), 309 Settings.System.TIME_12_24, 310 is24Hour? HOURS_24 : HOURS_12); 311 } 312 313 private boolean getAutoState(String name) { 314 try { 315 return Settings.Global.getInt(getContentResolver(), name) > 0; 316 } catch (SettingNotFoundException snfe) { 317 return false; 318 } 319 } 320 321 /* package */ static void setDate(Context context, int year, int month, int day) { 322 Calendar c = Calendar.getInstance(); 323 324 c.set(Calendar.YEAR, year); 325 c.set(Calendar.MONTH, month); 326 c.set(Calendar.DAY_OF_MONTH, day); 327 long when = c.getTimeInMillis(); 328 329 if (when / 1000 < Integer.MAX_VALUE) { 330 ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); 331 } 332 } 333 334 /* package */ static void setTime(Context context, int hourOfDay, int minute) { 335 Calendar c = Calendar.getInstance(); 336 337 c.set(Calendar.HOUR_OF_DAY, hourOfDay); 338 c.set(Calendar.MINUTE, minute); 339 c.set(Calendar.SECOND, 0); 340 c.set(Calendar.MILLISECOND, 0); 341 long when = c.getTimeInMillis(); 342 343 if (when / 1000 < Integer.MAX_VALUE) { 344 ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); 345 } 346 } 347 348 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 349 @Override 350 public void onReceive(Context context, Intent intent) { 351 final Activity activity = getActivity(); 352 if (activity != null) { 353 updateTimeAndDateDisplay(activity); 354 } 355 } 356 }; 357} 358