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