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