• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
getMetricsCategory()86     protected int getMetricsCategory() {
87         return MetricsEvent.DATE_TIME;
88     }
89 
90     @Override
onCreate(Bundle icicle)91     public void onCreate(Bundle icicle) {
92         super.onCreate(icicle);
93 
94         addPreferencesFromResource(R.xml.date_time_prefs);
95 
96         initUI();
97     }
98 
initUI()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
onResume()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
onPause()156     public void onPause() {
157         super.onPause();
158         getActivity().unregisterReceiver(mIntentReceiver);
159     }
160 
updateTimeAndDateDisplay(Context context)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
onDateSet(DatePicker view, int year, int month, int day)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
onTimeSet(TimePicker view, int hourOfDay, int minute)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
onPreferenceChange(Preference preference, Object newValue)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
onCreateDialog(int id)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 
configureDatePicker(DatePicker datePicker)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
onPreferenceTreeClick(Preference preference)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
onActivityResult(int requestCode, int resultCode, Intent data)293     public void onActivityResult(int requestCode, int resultCode,
294             Intent data) {
295         updateTimeAndDateDisplay(getActivity());
296     }
297 
timeUpdated(boolean is24Hour)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 
is24Hour()306     private boolean is24Hour() {
307         return DateFormat.is24HourFormat(getActivity());
308     }
309 
set24Hour(boolean is24Hour)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 
getAutoState(String name)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 
setDate(Context context, int year, int month, int day)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 
setTime(Context context, int hourOfDay, int minute)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 
SummaryProvider(Context context, SummaryLoader summaryLoader)366         public SummaryProvider(Context context, SummaryLoader summaryLoader) {
367             mContext = context;
368             mSummaryLoader = summaryLoader;
369         }
370 
371         @Override
setListening(boolean listening)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
getXmlResourcesToIndex( Context context, boolean enabled)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