| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.settings; |
| |
| import android.app.Activity; |
| import android.app.AlarmManager; |
| import android.app.DatePickerDialog; |
| import android.app.DatePickerDialog.OnDateSetListener; |
| import android.app.Dialog; |
| import android.app.TimePickerDialog; |
| import android.app.TimePickerDialog.OnTimeSetListener; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.os.Bundle; |
| import android.os.UserManager; |
| import android.provider.SearchIndexableResource; |
| import android.provider.Settings; |
| import android.provider.Settings.SettingNotFoundException; |
| import android.support.v14.preference.SwitchPreference; |
| import android.support.v7.preference.Preference; |
| import android.support.v7.preference.Preference.OnPreferenceChangeListener; |
| import android.text.format.DateFormat; |
| import android.widget.DatePicker; |
| import android.widget.TimePicker; |
| |
| import com.android.internal.logging.nano.MetricsProto.MetricsEvent; |
| import com.android.settings.dashboard.SummaryLoader; |
| import com.android.settings.search.BaseSearchIndexProvider; |
| import com.android.settings.search.Indexable; |
| import com.android.settingslib.RestrictedLockUtils; |
| import com.android.settingslib.RestrictedSwitchPreference; |
| import com.android.settingslib.datetime.ZoneGetter; |
| |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.List; |
| |
| import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; |
| |
| public class DateTimeSettings extends SettingsPreferenceFragment |
| implements OnTimeSetListener, OnDateSetListener, OnPreferenceChangeListener, Indexable { |
| |
| private static final String HOURS_12 = "12"; |
| private static final String HOURS_24 = "24"; |
| |
| // Used for showing the current date format, which looks like "12/31/2010", "2010/12/13", etc. |
| // The date value is dummy (independent of actual date). |
| private Calendar mDummyDate; |
| |
| private static final String KEY_AUTO_TIME = "auto_time"; |
| private static final String KEY_AUTO_TIME_ZONE = "auto_zone"; |
| |
| private static final int DIALOG_DATEPICKER = 0; |
| private static final int DIALOG_TIMEPICKER = 1; |
| |
| // have we been launched from the setup wizard? |
| protected static final String EXTRA_IS_FIRST_RUN = "firstRun"; |
| |
| // Minimum time is Nov 5, 2007, 0:00. |
| private static final long MIN_DATE = 1194220800000L; |
| |
| private RestrictedSwitchPreference mAutoTimePref; |
| private Preference mTimePref; |
| private Preference mTime24Pref; |
| private SwitchPreference mAutoTimeZonePref; |
| private Preference mTimeZone; |
| private Preference mDatePref; |
| |
| @Override |
| public int getMetricsCategory() { |
| return MetricsEvent.DATE_TIME; |
| } |
| |
| @Override |
| public void onCreate(Bundle icicle) { |
| super.onCreate(icicle); |
| |
| addPreferencesFromResource(R.xml.date_time_prefs); |
| |
| initUI(); |
| } |
| |
| private void initUI() { |
| boolean autoTimeEnabled = getAutoState(Settings.Global.AUTO_TIME); |
| boolean autoTimeZoneEnabled = getAutoState(Settings.Global.AUTO_TIME_ZONE); |
| |
| mAutoTimePref = (RestrictedSwitchPreference) findPreference(KEY_AUTO_TIME); |
| mAutoTimePref.setOnPreferenceChangeListener(this); |
| EnforcedAdmin admin = RestrictedLockUtils.checkIfAutoTimeRequired(getActivity()); |
| mAutoTimePref.setDisabledByAdmin(admin); |
| |
| Intent intent = getActivity().getIntent(); |
| boolean isFirstRun = intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false); |
| |
| mDummyDate = Calendar.getInstance(); |
| |
| // If device admin requires auto time device policy manager will set |
| // Settings.Global.AUTO_TIME to true. Note that this app listens to that change. |
| mAutoTimePref.setChecked(autoTimeEnabled); |
| mAutoTimeZonePref = (SwitchPreference) findPreference(KEY_AUTO_TIME_ZONE); |
| mAutoTimeZonePref.setOnPreferenceChangeListener(this); |
| // Override auto-timezone if it's a wifi-only device or if we're still in setup wizard. |
| // TODO: Remove the wifiOnly test when auto-timezone is implemented based on wifi-location. |
| if (Utils.isWifiOnly(getActivity()) || isFirstRun) { |
| getPreferenceScreen().removePreference(mAutoTimeZonePref); |
| autoTimeZoneEnabled = false; |
| } |
| mAutoTimeZonePref.setChecked(autoTimeZoneEnabled); |
| |
| mTimePref = findPreference("time"); |
| mTime24Pref = findPreference("24 hour"); |
| mTimeZone = findPreference("timezone"); |
| mDatePref = findPreference("date"); |
| if (isFirstRun) { |
| getPreferenceScreen().removePreference(mTime24Pref); |
| } |
| |
| mTimePref.setEnabled(!autoTimeEnabled); |
| mDatePref.setEnabled(!autoTimeEnabled); |
| mTimeZone.setEnabled(!autoTimeZoneEnabled); |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| |
| ((SwitchPreference)mTime24Pref).setChecked(is24Hour()); |
| |
| // Register for time ticks and other reasons for time change |
| IntentFilter filter = new IntentFilter(); |
| filter.addAction(Intent.ACTION_TIME_TICK); |
| filter.addAction(Intent.ACTION_TIME_CHANGED); |
| filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); |
| getActivity().registerReceiver(mIntentReceiver, filter, null, null); |
| |
| updateTimeAndDateDisplay(getActivity()); |
| } |
| |
| @Override |
| public void onPause() { |
| super.onPause(); |
| getActivity().unregisterReceiver(mIntentReceiver); |
| } |
| |
| public void updateTimeAndDateDisplay(Context context) { |
| final Calendar now = Calendar.getInstance(); |
| mDummyDate.setTimeZone(now.getTimeZone()); |
| // We use December 31st because it's unambiguous when demonstrating the date format. |
| // We use 13:00 so we can demonstrate the 12/24 hour options. |
| mDummyDate.set(now.get(Calendar.YEAR), 11, 31, 13, 0, 0); |
| Date dummyDate = mDummyDate.getTime(); |
| mDatePref.setSummary(DateFormat.getLongDateFormat(context).format(now.getTime())); |
| mTimePref.setSummary(DateFormat.getTimeFormat(getActivity()).format(now.getTime())); |
| mTimeZone.setSummary(ZoneGetter.getTimeZoneOffsetAndName(context, |
| now.getTimeZone(), now.getTime())); |
| mTime24Pref.setSummary(DateFormat.getTimeFormat(getActivity()).format(dummyDate)); |
| } |
| |
| @Override |
| public void onDateSet(DatePicker view, int year, int month, int day) { |
| final Activity activity = getActivity(); |
| if (activity != null) { |
| setDate(activity, year, month, day); |
| updateTimeAndDateDisplay(activity); |
| } |
| } |
| |
| @Override |
| public void onTimeSet(TimePicker view, int hourOfDay, int minute) { |
| final Activity activity = getActivity(); |
| if (activity != null) { |
| setTime(activity, hourOfDay, minute); |
| updateTimeAndDateDisplay(activity); |
| } |
| |
| // We don't need to call timeUpdated() here because the TIME_CHANGED |
| // broadcast is sent by the AlarmManager as a side effect of setting the |
| // SystemClock time. |
| } |
| |
| @Override |
| public boolean onPreferenceChange(Preference preference, Object newValue) { |
| if (preference.getKey().equals(KEY_AUTO_TIME)) { |
| boolean autoEnabled = (Boolean) newValue; |
| Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME, |
| autoEnabled ? 1 : 0); |
| mTimePref.setEnabled(!autoEnabled); |
| mDatePref.setEnabled(!autoEnabled); |
| } else if (preference.getKey().equals(KEY_AUTO_TIME_ZONE)) { |
| boolean autoZoneEnabled = (Boolean) newValue; |
| Settings.Global.putInt( |
| getContentResolver(), Settings.Global.AUTO_TIME_ZONE, autoZoneEnabled ? 1 : 0); |
| mTimeZone.setEnabled(!autoZoneEnabled); |
| } |
| return true; |
| } |
| |
| @Override |
| public Dialog onCreateDialog(int id) { |
| final Calendar calendar = Calendar.getInstance(); |
| switch (id) { |
| case DIALOG_DATEPICKER: |
| DatePickerDialog d = new DatePickerDialog( |
| getActivity(), |
| this, |
| calendar.get(Calendar.YEAR), |
| calendar.get(Calendar.MONTH), |
| calendar.get(Calendar.DAY_OF_MONTH)); |
| configureDatePicker(d.getDatePicker()); |
| return d; |
| case DIALOG_TIMEPICKER: |
| return new TimePickerDialog( |
| getActivity(), |
| this, |
| calendar.get(Calendar.HOUR_OF_DAY), |
| calendar.get(Calendar.MINUTE), |
| DateFormat.is24HourFormat(getActivity())); |
| default: |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| @Override |
| public int getDialogMetricsCategory(int dialogId) { |
| switch (dialogId) { |
| case DIALOG_DATEPICKER: |
| return MetricsEvent.DIALOG_DATE_PICKER; |
| case DIALOG_TIMEPICKER: |
| return MetricsEvent.DIALOG_TIME_PICKER; |
| default: |
| return 0; |
| } |
| } |
| |
| static void configureDatePicker(DatePicker datePicker) { |
| // The system clock can't represent dates outside this range. |
| Calendar t = Calendar.getInstance(); |
| t.clear(); |
| t.set(1970, Calendar.JANUARY, 1); |
| datePicker.setMinDate(t.getTimeInMillis()); |
| t.clear(); |
| t.set(2037, Calendar.DECEMBER, 31); |
| datePicker.setMaxDate(t.getTimeInMillis()); |
| } |
| |
| /* |
| @Override |
| public void onPrepareDialog(int id, Dialog d) { |
| switch (id) { |
| case DIALOG_DATEPICKER: { |
| DatePickerDialog datePicker = (DatePickerDialog)d; |
| final Calendar calendar = Calendar.getInstance(); |
| datePicker.updateDate( |
| calendar.get(Calendar.YEAR), |
| calendar.get(Calendar.MONTH), |
| calendar.get(Calendar.DAY_OF_MONTH)); |
| break; |
| } |
| case DIALOG_TIMEPICKER: { |
| TimePickerDialog timePicker = (TimePickerDialog)d; |
| final Calendar calendar = Calendar.getInstance(); |
| timePicker.updateTime( |
| calendar.get(Calendar.HOUR_OF_DAY), |
| calendar.get(Calendar.MINUTE)); |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| */ |
| @Override |
| public boolean onPreferenceTreeClick(Preference preference) { |
| if (preference == mDatePref) { |
| showDialog(DIALOG_DATEPICKER); |
| } else if (preference == mTimePref) { |
| // The 24-hour mode may have changed, so recreate the dialog |
| removeDialog(DIALOG_TIMEPICKER); |
| showDialog(DIALOG_TIMEPICKER); |
| } else if (preference == mTime24Pref) { |
| final boolean is24Hour = ((SwitchPreference)mTime24Pref).isChecked(); |
| set24Hour(is24Hour); |
| updateTimeAndDateDisplay(getActivity()); |
| timeUpdated(is24Hour); |
| } |
| return super.onPreferenceTreeClick(preference); |
| } |
| |
| @Override |
| public void onActivityResult(int requestCode, int resultCode, |
| Intent data) { |
| updateTimeAndDateDisplay(getActivity()); |
| } |
| |
| private void timeUpdated(boolean is24Hour) { |
| Intent timeChanged = new Intent(Intent.ACTION_TIME_CHANGED); |
| timeChanged.putExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, is24Hour); |
| getActivity().sendBroadcast(timeChanged); |
| } |
| |
| /* Get & Set values from the system settings */ |
| |
| private boolean is24Hour() { |
| return DateFormat.is24HourFormat(getActivity()); |
| } |
| |
| private void set24Hour(boolean is24Hour) { |
| Settings.System.putString(getContentResolver(), |
| Settings.System.TIME_12_24, |
| is24Hour? HOURS_24 : HOURS_12); |
| } |
| |
| private boolean getAutoState(String name) { |
| try { |
| return Settings.Global.getInt(getContentResolver(), name) > 0; |
| } catch (SettingNotFoundException snfe) { |
| return false; |
| } |
| } |
| |
| /* package */ static void setDate(Context context, int year, int month, int day) { |
| Calendar c = Calendar.getInstance(); |
| |
| c.set(Calendar.YEAR, year); |
| c.set(Calendar.MONTH, month); |
| c.set(Calendar.DAY_OF_MONTH, day); |
| long when = Math.max(c.getTimeInMillis(), MIN_DATE); |
| |
| if (when / 1000 < Integer.MAX_VALUE) { |
| ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); |
| } |
| } |
| |
| /* package */ static void setTime(Context context, int hourOfDay, int minute) { |
| Calendar c = Calendar.getInstance(); |
| |
| c.set(Calendar.HOUR_OF_DAY, hourOfDay); |
| c.set(Calendar.MINUTE, minute); |
| c.set(Calendar.SECOND, 0); |
| c.set(Calendar.MILLISECOND, 0); |
| long when = Math.max(c.getTimeInMillis(), MIN_DATE); |
| |
| if (when / 1000 < Integer.MAX_VALUE) { |
| ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); |
| } |
| } |
| |
| private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| final Activity activity = getActivity(); |
| if (activity != null) { |
| updateTimeAndDateDisplay(activity); |
| } |
| } |
| }; |
| |
| private static class SummaryProvider implements SummaryLoader.SummaryProvider { |
| |
| private final Context mContext; |
| private final SummaryLoader mSummaryLoader; |
| |
| public SummaryProvider(Context context, SummaryLoader summaryLoader) { |
| mContext = context; |
| mSummaryLoader = summaryLoader; |
| } |
| |
| @Override |
| public void setListening(boolean listening) { |
| if (listening) { |
| final Calendar now = Calendar.getInstance(); |
| mSummaryLoader.setSummary(this, ZoneGetter.getTimeZoneOffsetAndName(mContext, |
| now.getTimeZone(), now.getTime())); |
| } |
| } |
| } |
| |
| public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY |
| = new SummaryLoader.SummaryProviderFactory() { |
| @Override |
| public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, |
| SummaryLoader summaryLoader) { |
| return new SummaryProvider(activity, summaryLoader); |
| } |
| }; |
| |
| public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = |
| new DateTimeSearchIndexProvider(); |
| |
| private static class DateTimeSearchIndexProvider extends BaseSearchIndexProvider { |
| |
| @Override |
| public List<SearchIndexableResource> getXmlResourcesToIndex( |
| Context context, boolean enabled) { |
| List<SearchIndexableResource> result = new ArrayList<>(); |
| // Remove data/time settings from search in demo mode |
| if (UserManager.isDeviceInDemoMode(context)) { |
| return result; |
| } |
| |
| SearchIndexableResource sir = new SearchIndexableResource(context); |
| sir.xmlResId = R.xml.date_time_prefs; |
| result.add(sir); |
| |
| return result; |
| } |
| } |
| } |