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