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