• 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.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
onCreate(Bundle icicle)81     public void onCreate(Bundle icicle) {
82         super.onCreate(icicle);
83 
84         addPreferencesFromResource(R.xml.date_time_prefs);
85 
86         initUI();
87     }
88 
initUI()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
onResume()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
onPause()184     public void onPause() {
185         super.onPause();
186         getActivity().unregisterReceiver(mIntentReceiver);
187         getPreferenceScreen().getSharedPreferences()
188                 .unregisterOnSharedPreferenceChangeListener(this);
189     }
190 
updateTimeAndDateDisplay(Context context)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
onDateSet(DatePicker view, int year, int month, int day)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
onTimeSet(TimePicker view, int hourOfDay, int minute)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
onSharedPreferenceChanged(SharedPreferences preferences, String key)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
onCreateDialog(int id)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 
configureDatePicker(DatePicker datePicker)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
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)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
onActivityResult(int requestCode, int resultCode, Intent data)330     public void onActivityResult(int requestCode, int resultCode,
331             Intent data) {
332         updateTimeAndDateDisplay(getActivity());
333     }
334 
timeUpdated(boolean is24Hour)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 
is24Hour()343     private boolean is24Hour() {
344         return DateFormat.is24HourFormat(getActivity());
345     }
346 
set24Hour(boolean is24Hour)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 
getDateFormat()353     private String getDateFormat() {
354         return Settings.System.getString(getContentResolver(),
355                 Settings.System.DATE_FORMAT);
356     }
357 
getAutoState(String name)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 
setDate(Context context, int year, int month, int day)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 
setTime(Context context, int hourOfDay, int minute)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 
getTimeZoneText(TimeZone tz, boolean includeName)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