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
17package com.android.settings;
18
19import android.app.Dialog;
20import android.app.DatePickerDialog;
21import android.app.TimePickerDialog;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.SharedPreferences;
27import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
28import android.os.Bundle;
29import android.os.SystemClock;
30import android.preference.CheckBoxPreference;
31import android.preference.ListPreference;
32import android.preference.Preference;
33import android.preference.PreferenceActivity;
34import android.preference.PreferenceScreen;
35import android.provider.Settings;
36import android.provider.Settings.SettingNotFoundException;
37import android.text.format.DateFormat;
38import android.widget.DatePicker;
39import android.widget.TimePicker;
40
41import java.util.Calendar;
42import java.util.Date;
43import java.util.TimeZone;
44
45public class DateTimeSettings
46        extends PreferenceActivity
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    private Calendar mDummyDate;
54    private static final String KEY_DATE_FORMAT = "date_format";
55    private static final String KEY_AUTO_TIME = "auto_time";
56
57    private static final int DIALOG_DATEPICKER = 0;
58    private static final int DIALOG_TIMEPICKER = 1;
59
60    private CheckBoxPreference mAutoPref;
61    private Preference mTimePref;
62    private Preference mTime24Pref;
63    private Preference mTimeZone;
64    private Preference mDatePref;
65    private ListPreference mDateFormat;
66
67    @Override
68    protected void onCreate(Bundle icicle) {
69        super.onCreate(icicle);
70
71        addPreferencesFromResource(R.xml.date_time_prefs);
72
73        initUI();
74    }
75
76    private void initUI() {
77        boolean autoEnabled = getAutoState();
78
79        mDummyDate = Calendar.getInstance();
80        mDummyDate.set(mDummyDate.get(Calendar.YEAR), 11, 31, 13, 0, 0);
81
82        mAutoPref = (CheckBoxPreference) findPreference(KEY_AUTO_TIME);
83        mAutoPref.setChecked(autoEnabled);
84        mTimePref = findPreference("time");
85        mTime24Pref = findPreference("24 hour");
86        mTimeZone = findPreference("timezone");
87        mDatePref = findPreference("date");
88        mDateFormat = (ListPreference) findPreference(KEY_DATE_FORMAT);
89
90        String [] dateFormats = getResources().getStringArray(R.array.date_format_values);
91        String [] formattedDates = new String[dateFormats.length];
92        String currentFormat = getDateFormat();
93        // Initialize if DATE_FORMAT is not set in the system settings
94        // This can happen after a factory reset (or data wipe)
95        if (currentFormat == null) {
96            currentFormat = "";
97        }
98        for (int i = 0; i < formattedDates.length; i++) {
99            String formatted =
100                DateFormat.getDateFormatForSetting(this, dateFormats[i]).
101                    format(mDummyDate.getTime());
102
103            if (dateFormats[i].length() == 0) {
104                formattedDates[i] = getResources().
105                    getString(R.string.normal_date_format, formatted);
106            } else {
107                formattedDates[i] = formatted;
108            }
109        }
110
111        mDateFormat.setEntries(formattedDates);
112        mDateFormat.setEntryValues(R.array.date_format_values);
113        mDateFormat.setValue(currentFormat);
114
115        mTimePref.setEnabled(!autoEnabled);
116        mDatePref.setEnabled(!autoEnabled);
117        mTimeZone.setEnabled(!autoEnabled);
118    }
119
120
121    @Override
122    protected void onResume() {
123        super.onResume();
124
125        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
126
127        ((CheckBoxPreference)mTime24Pref).setChecked(is24Hour());
128
129        // Register for time ticks and other reasons for time change
130        IntentFilter filter = new IntentFilter();
131        filter.addAction(Intent.ACTION_TIME_TICK);
132        filter.addAction(Intent.ACTION_TIME_CHANGED);
133        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
134        registerReceiver(mIntentReceiver, filter, null, null);
135
136        updateTimeAndDateDisplay();
137    }
138
139    @Override
140    protected void onPause() {
141        super.onPause();
142        unregisterReceiver(mIntentReceiver);
143        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
144    }
145
146    private void updateTimeAndDateDisplay() {
147        java.text.DateFormat shortDateFormat = DateFormat.getDateFormat(this);
148        Date now = Calendar.getInstance().getTime();
149        Date dummyDate = mDummyDate.getTime();
150        mTimePref.setSummary(DateFormat.getTimeFormat(this).format(now));
151        mTimeZone.setSummary(getTimeZoneText());
152        mDatePref.setSummary(shortDateFormat.format(now));
153        mDateFormat.setSummary(shortDateFormat.format(dummyDate));
154    }
155
156    public void onDateSet(DatePicker view, int year, int month, int day) {
157        Calendar c = Calendar.getInstance();
158
159        c.set(Calendar.YEAR, year);
160        c.set(Calendar.MONTH, month);
161        c.set(Calendar.DAY_OF_MONTH, day);
162        long when = c.getTimeInMillis();
163
164        if (when / 1000 < Integer.MAX_VALUE) {
165            SystemClock.setCurrentTimeMillis(when);
166        }
167        updateTimeAndDateDisplay();
168    }
169
170    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
171        Calendar c = Calendar.getInstance();
172
173        c.set(Calendar.HOUR_OF_DAY, hourOfDay);
174        c.set(Calendar.MINUTE, minute);
175        long when = c.getTimeInMillis();
176
177        if (when / 1000 < Integer.MAX_VALUE) {
178            SystemClock.setCurrentTimeMillis(when);
179        }
180        updateTimeAndDateDisplay();
181
182        // We don't need to call timeUpdated() here because the TIME_CHANGED
183        // broadcast is sent by the AlarmManager as a side effect of setting the
184        // SystemClock time.
185    }
186
187    public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
188        if (key.equals(KEY_DATE_FORMAT)) {
189            String format = preferences.getString(key,
190                    getResources().getString(R.string.default_date_format));
191            Settings.System.putString(getContentResolver(),
192                    Settings.System.DATE_FORMAT, format);
193            updateTimeAndDateDisplay();
194        } else if (key.equals(KEY_AUTO_TIME)) {
195            boolean autoEnabled = preferences.getBoolean(key, true);
196            Settings.System.putInt(getContentResolver(),
197                    Settings.System.AUTO_TIME,
198                    autoEnabled ? 1 : 0);
199            mTimePref.setEnabled(!autoEnabled);
200            mDatePref.setEnabled(!autoEnabled);
201            mTimeZone.setEnabled(!autoEnabled);
202        }
203    }
204
205    @Override
206    public Dialog onCreateDialog(int id) {
207        Dialog d;
208
209        switch (id) {
210        case DIALOG_DATEPICKER: {
211            final Calendar calendar = Calendar.getInstance();
212            d = new DatePickerDialog(
213                this,
214                this,
215                calendar.get(Calendar.YEAR),
216                calendar.get(Calendar.MONTH),
217                calendar.get(Calendar.DAY_OF_MONTH));
218            d.setTitle(getResources().getString(R.string.date_time_changeDate_text));
219            break;
220        }
221        case DIALOG_TIMEPICKER: {
222            final Calendar calendar = Calendar.getInstance();
223            d = new TimePickerDialog(
224                    this,
225                    this,
226                    calendar.get(Calendar.HOUR_OF_DAY),
227                    calendar.get(Calendar.MINUTE),
228                    DateFormat.is24HourFormat(this));
229            d.setTitle(getResources().getString(R.string.date_time_changeTime_text));
230            break;
231        }
232        default:
233            d = null;
234            break;
235        }
236
237        return d;
238    }
239
240    @Override
241    public void onPrepareDialog(int id, Dialog d) {
242        switch (id) {
243        case DIALOG_DATEPICKER: {
244            DatePickerDialog datePicker = (DatePickerDialog)d;
245            final Calendar calendar = Calendar.getInstance();
246            datePicker.updateDate(
247                    calendar.get(Calendar.YEAR),
248                    calendar.get(Calendar.MONTH),
249                    calendar.get(Calendar.DAY_OF_MONTH));
250            break;
251        }
252        case DIALOG_TIMEPICKER: {
253            TimePickerDialog timePicker = (TimePickerDialog)d;
254            final Calendar calendar = Calendar.getInstance();
255            timePicker.updateTime(
256                    calendar.get(Calendar.HOUR_OF_DAY),
257                    calendar.get(Calendar.MINUTE));
258            break;
259        }
260        default:
261            break;
262        }
263    }
264
265    @Override
266    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
267        if (preference == mDatePref) {
268            showDialog(DIALOG_DATEPICKER);
269        } else if (preference == mTimePref) {
270            // The 24-hour mode may have changed, so recreate the dialog
271            removeDialog(DIALOG_TIMEPICKER);
272            showDialog(DIALOG_TIMEPICKER);
273        } else if (preference == mTime24Pref) {
274            set24Hour(((CheckBoxPreference)mTime24Pref).isChecked());
275            updateTimeAndDateDisplay();
276            timeUpdated();
277        } else if (preference == mTimeZone) {
278            Intent intent = new Intent();
279            intent.setClass(this, ZoneList.class);
280            startActivityForResult(intent, 0);
281        }
282        return false;
283    }
284
285    @Override
286    protected void onActivityResult(int requestCode, int resultCode,
287            Intent data) {
288        updateTimeAndDateDisplay();
289    }
290
291    private void timeUpdated() {
292        Intent timeChanged = new Intent(Intent.ACTION_TIME_CHANGED);
293        sendBroadcast(timeChanged);
294    }
295
296    /*  Get & Set values from the system settings  */
297
298    private boolean is24Hour() {
299        return DateFormat.is24HourFormat(this);
300    }
301
302    private void set24Hour(boolean is24Hour) {
303        Settings.System.putString(getContentResolver(),
304                Settings.System.TIME_12_24,
305                is24Hour? HOURS_24 : HOURS_12);
306    }
307
308    private String getDateFormat() {
309        return Settings.System.getString(getContentResolver(),
310                Settings.System.DATE_FORMAT);
311    }
312
313    private boolean getAutoState() {
314        try {
315            return Settings.System.getInt(getContentResolver(),
316                Settings.System.AUTO_TIME) > 0;
317        } catch (SettingNotFoundException snfe) {
318            return true;
319        }
320    }
321
322    private void setDateFormat(String format) {
323        if (format.length() == 0) {
324            format = null;
325        }
326
327        Settings.System.putString(getContentResolver(), Settings.System.DATE_FORMAT, format);
328    }
329
330    /*  Helper routines to format timezone */
331
332    private String getTimeZoneText() {
333        TimeZone    tz = java.util.Calendar.getInstance().getTimeZone();
334        boolean daylight = tz.inDaylightTime(new Date());
335        StringBuilder sb = new StringBuilder();
336
337        sb.append(formatOffset(tz.getRawOffset() +
338                               (daylight ? tz.getDSTSavings() : 0))).
339            append(", ").
340            append(tz.getDisplayName(daylight, TimeZone.LONG));
341
342        return sb.toString();
343    }
344
345    private char[] formatOffset(int off) {
346        off = off / 1000 / 60;
347
348        char[] buf = new char[9];
349        buf[0] = 'G';
350        buf[1] = 'M';
351        buf[2] = 'T';
352
353        if (off < 0) {
354            buf[3] = '-';
355            off = -off;
356        } else {
357            buf[3] = '+';
358        }
359
360        int hours = off / 60;
361        int minutes = off % 60;
362
363        buf[4] = (char) ('0' + hours / 10);
364        buf[5] = (char) ('0' + hours % 10);
365
366        buf[6] = ':';
367
368        buf[7] = (char) ('0' + minutes / 10);
369        buf[8] = (char) ('0' + minutes % 10);
370
371        return buf;
372    }
373
374    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
375        @Override
376        public void onReceive(Context context, Intent intent) {
377            updateTimeAndDateDisplay();
378        }
379    };
380}
381