/* * Copyright (C) 2007 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.calendar; import android.app.Activity; import android.app.FragmentManager; import android.app.backup.BackupManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.os.Bundle; import android.os.Vibrator; import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; import android.preference.RingtonePreference; import android.provider.CalendarContract; import android.provider.CalendarContract.CalendarCache; import android.provider.SearchRecentSuggestions; import android.text.TextUtils; import android.text.format.Time; import android.widget.Toast; import com.android.calendar.alerts.AlertReceiver; import com.android.timezonepicker.TimeZoneInfo; import com.android.timezonepicker.TimeZonePickerDialog; import com.android.timezonepicker.TimeZonePickerDialog.OnTimeZoneSetListener; import com.android.timezonepicker.TimeZonePickerUtils; public class GeneralPreferences extends PreferenceFragment implements OnSharedPreferenceChangeListener, OnPreferenceChangeListener, OnTimeZoneSetListener { // The name of the shared preferences file. This name must be maintained for historical // reasons, as it's what PreferenceManager assigned the first time the file was created. static final String SHARED_PREFS_NAME = "com.android.calendar_preferences"; static final String SHARED_PREFS_NAME_NO_BACKUP = "com.android.calendar_preferences_no_backup"; private static final String FRAG_TAG_TIME_ZONE_PICKER = "TimeZonePicker"; // Preference keys public static final String KEY_HIDE_DECLINED = "preferences_hide_declined"; public static final String KEY_WEEK_START_DAY = "preferences_week_start_day"; public static final String KEY_SHOW_WEEK_NUM = "preferences_show_week_num"; public static final String KEY_DAYS_PER_WEEK = "preferences_days_per_week"; public static final String KEY_SKIP_SETUP = "preferences_skip_setup"; public static final String KEY_CLEAR_SEARCH_HISTORY = "preferences_clear_search_history"; public static final String KEY_ALERTS_CATEGORY = "preferences_alerts_category"; public static final String KEY_ALERTS = "preferences_alerts"; public static final String KEY_ALERTS_VIBRATE = "preferences_alerts_vibrate"; public static final String KEY_ALERTS_RINGTONE = "preferences_alerts_ringtone"; public static final String KEY_ALERTS_POPUP = "preferences_alerts_popup"; public static final String KEY_SHOW_CONTROLS = "preferences_show_controls"; public static final String KEY_DEFAULT_REMINDER = "preferences_default_reminder"; public static final int NO_REMINDER = -1; public static final String NO_REMINDER_STRING = "-1"; public static final int REMINDER_DEFAULT_TIME = 10; // in minutes public static final String KEY_DEFAULT_CELL_HEIGHT = "preferences_default_cell_height"; public static final String KEY_VERSION = "preferences_version"; /** Key to SharePreference for default view (CalendarController.ViewType) */ public static final String KEY_START_VIEW = "preferred_startView"; /** * Key to SharePreference for default detail view (CalendarController.ViewType) * Typically used by widget */ public static final String KEY_DETAILED_VIEW = "preferred_detailedView"; public static final String KEY_DEFAULT_CALENDAR = "preference_defaultCalendar"; // These must be in sync with the array preferences_week_start_day_values public static final String WEEK_START_DEFAULT = "-1"; public static final String WEEK_START_SATURDAY = "7"; public static final String WEEK_START_SUNDAY = "1"; public static final String WEEK_START_MONDAY = "2"; // These keys are kept to enable migrating users from previous versions private static final String KEY_ALERTS_TYPE = "preferences_alerts_type"; private static final String ALERT_TYPE_ALERTS = "0"; private static final String ALERT_TYPE_STATUS_BAR = "1"; private static final String ALERT_TYPE_OFF = "2"; static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled"; static final String KEY_HOME_TZ = "preferences_home_tz"; // Default preference values public static final int DEFAULT_START_VIEW = CalendarController.ViewType.WEEK; public static final int DEFAULT_DETAILED_VIEW = CalendarController.ViewType.DAY; public static final boolean DEFAULT_SHOW_WEEK_NUM = false; // This should match the XML file. public static final String DEFAULT_RINGTONE = "content://settings/system/notification_sound"; CheckBoxPreference mAlert; CheckBoxPreference mVibrate; RingtonePreference mRingtone; CheckBoxPreference mPopup; CheckBoxPreference mUseHomeTZ; CheckBoxPreference mHideDeclined; Preference mHomeTZ; TimeZonePickerUtils mTzPickerUtils; ListPreference mWeekStart; ListPreference mDefaultReminder; private String mTimeZoneId; /** Return a properly configured SharedPreferences instance */ public static SharedPreferences getSharedPreferences(Context context) { return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE); } /** Set the default shared preferences in the proper context */ public static void setDefaultValues(Context context) { PreferenceManager.setDefaultValues(context, SHARED_PREFS_NAME, Context.MODE_PRIVATE, R.xml.general_preferences, false); } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); final Activity activity = getActivity(); // Make sure to always use the same preferences file regardless of the package name // we're running under final PreferenceManager preferenceManager = getPreferenceManager(); final SharedPreferences sharedPreferences = getSharedPreferences(activity); preferenceManager.setSharedPreferencesName(SHARED_PREFS_NAME); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.general_preferences); final PreferenceScreen preferenceScreen = getPreferenceScreen(); mAlert = (CheckBoxPreference) preferenceScreen.findPreference(KEY_ALERTS); mVibrate = (CheckBoxPreference) preferenceScreen.findPreference(KEY_ALERTS_VIBRATE); Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); if (vibrator == null || !vibrator.hasVibrator()) { PreferenceCategory mAlertGroup = (PreferenceCategory) preferenceScreen .findPreference(KEY_ALERTS_CATEGORY); mAlertGroup.removePreference(mVibrate); } mRingtone = (RingtonePreference) preferenceScreen.findPreference(KEY_ALERTS_RINGTONE); String ringToneUri = Utils.getRingTonePreference(activity); // Set the ringToneUri to the backup-able shared pref only so that // the Ringtone dialog will open up with the correct value. final Editor editor = preferenceScreen.getEditor(); editor.putString(GeneralPreferences.KEY_ALERTS_RINGTONE, ringToneUri).apply(); String ringtoneDisplayString = getRingtoneTitleFromUri(activity, ringToneUri); mRingtone.setSummary(ringtoneDisplayString == null ? "" : ringtoneDisplayString); mPopup = (CheckBoxPreference) preferenceScreen.findPreference(KEY_ALERTS_POPUP); mUseHomeTZ = (CheckBoxPreference) preferenceScreen.findPreference(KEY_HOME_TZ_ENABLED); mHideDeclined = (CheckBoxPreference) preferenceScreen.findPreference(KEY_HIDE_DECLINED); mWeekStart = (ListPreference) preferenceScreen.findPreference(KEY_WEEK_START_DAY); mDefaultReminder = (ListPreference) preferenceScreen.findPreference(KEY_DEFAULT_REMINDER); mHomeTZ = preferenceScreen.findPreference(KEY_HOME_TZ); mWeekStart.setSummary(mWeekStart.getEntry()); mDefaultReminder.setSummary(mDefaultReminder.getEntry()); // This triggers an asynchronous call to the provider to refresh the data in shared pref mTimeZoneId = Utils.getTimeZone(activity, null); SharedPreferences prefs = CalendarUtils.getSharedPreferences(activity, Utils.SHARED_PREFS_NAME); // Utils.getTimeZone will return the currentTimeZone instead of the one // in the shared_pref if home time zone is disabled. So if home tz is // off, we will explicitly read it. if (!prefs.getBoolean(KEY_HOME_TZ_ENABLED, false)) { mTimeZoneId = prefs.getString(KEY_HOME_TZ, Time.getCurrentTimezone()); } mHomeTZ.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { showTimezoneDialog(); return true; } }); if (mTzPickerUtils == null) { mTzPickerUtils = new TimeZonePickerUtils(getActivity()); } CharSequence timezoneName = mTzPickerUtils.getGmtDisplayName(getActivity(), mTimeZoneId, System.currentTimeMillis(), false); mHomeTZ.setSummary(timezoneName != null ? timezoneName : mTimeZoneId); TimeZonePickerDialog tzpd = (TimeZonePickerDialog) activity.getFragmentManager() .findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER); if (tzpd != null) { tzpd.setOnTimeZoneSetListener(this); } migrateOldPreferences(sharedPreferences); updateChildPreferences(); } private void showTimezoneDialog() { final Activity activity = getActivity(); if (activity == null) { return; } Bundle b = new Bundle(); b.putLong(TimeZonePickerDialog.BUNDLE_START_TIME_MILLIS, System.currentTimeMillis()); b.putString(TimeZonePickerDialog.BUNDLE_TIME_ZONE, Utils.getTimeZone(activity, null)); FragmentManager fm = getActivity().getFragmentManager(); TimeZonePickerDialog tzpd = (TimeZonePickerDialog) fm .findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER); if (tzpd != null) { tzpd.dismiss(); } tzpd = new TimeZonePickerDialog(); tzpd.setArguments(b); tzpd.setOnTimeZoneSetListener(this); tzpd.show(fm, FRAG_TAG_TIME_ZONE_PICKER); } @Override public void onStart() { super.onStart(); getPreferenceScreen().getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); setPreferenceListeners(this); } /** * Sets up all the preference change listeners to use the specified * listener. */ private void setPreferenceListeners(OnPreferenceChangeListener listener) { mUseHomeTZ.setOnPreferenceChangeListener(listener); mHomeTZ.setOnPreferenceChangeListener(listener); mWeekStart.setOnPreferenceChangeListener(listener); mDefaultReminder.setOnPreferenceChangeListener(listener); mRingtone.setOnPreferenceChangeListener(listener); mHideDeclined.setOnPreferenceChangeListener(listener); mVibrate.setOnPreferenceChangeListener(listener); } @Override public void onStop() { getPreferenceScreen().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); setPreferenceListeners(null); super.onStop(); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { Activity a = getActivity(); if (key.equals(KEY_ALERTS)) { updateChildPreferences(); if (a != null) { Intent intent = new Intent(); intent.setClass(a, AlertReceiver.class); if (mAlert.isChecked()) { intent.setAction(AlertReceiver.ACTION_DISMISS_OLD_REMINDERS); } else { intent.setAction(AlertReceiver.EVENT_REMINDER_APP_ACTION); } a.sendBroadcast(intent); } } if (a != null) { BackupManager.dataChanged(a.getPackageName()); } } /** * Handles time zone preference changes */ @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String tz; final Activity activity = getActivity(); if (preference == mUseHomeTZ) { if ((Boolean)newValue) { tz = mTimeZoneId; } else { tz = CalendarCache.TIMEZONE_TYPE_AUTO; } Utils.setTimeZone(activity, tz); return true; } else if (preference == mHideDeclined) { mHideDeclined.setChecked((Boolean) newValue); Intent intent = new Intent(Utils.getWidgetScheduledUpdateAction(activity)); intent.setDataAndType(CalendarContract.CONTENT_URI, Utils.APPWIDGET_DATA_TYPE); activity.sendBroadcast(intent); return true; } else if (preference == mWeekStart) { mWeekStart.setValue((String) newValue); mWeekStart.setSummary(mWeekStart.getEntry()); } else if (preference == mDefaultReminder) { mDefaultReminder.setValue((String) newValue); mDefaultReminder.setSummary(mDefaultReminder.getEntry()); } else if (preference == mRingtone) { if (newValue instanceof String) { Utils.setRingTonePreference(activity, (String) newValue); String ringtone = getRingtoneTitleFromUri(activity, (String) newValue); mRingtone.setSummary(ringtone == null ? "" : ringtone); } return true; } else if (preference == mVibrate) { mVibrate.setChecked((Boolean) newValue); return true; } else { return true; } return false; } public String getRingtoneTitleFromUri(Context context, String uri) { if (TextUtils.isEmpty(uri)) { return null; } Ringtone ring = RingtoneManager.getRingtone(getActivity(), Uri.parse(uri)); if (ring != null) { return ring.getTitle(context); } return null; } /** * If necessary, upgrades previous versions of preferences to the current * set of keys and values. * @param prefs the preferences to upgrade */ private void migrateOldPreferences(SharedPreferences prefs) { // If needed, migrate vibration setting from a previous version mVibrate.setChecked(Utils.getDefaultVibrate(getActivity(), prefs)); // If needed, migrate the old alerts type settin if (!prefs.contains(KEY_ALERTS) && prefs.contains(KEY_ALERTS_TYPE)) { String type = prefs.getString(KEY_ALERTS_TYPE, ALERT_TYPE_STATUS_BAR); if (type.equals(ALERT_TYPE_OFF)) { mAlert.setChecked(false); mPopup.setChecked(false); mPopup.setEnabled(false); } else if (type.equals(ALERT_TYPE_STATUS_BAR)) { mAlert.setChecked(true); mPopup.setChecked(false); mPopup.setEnabled(true); } else if (type.equals(ALERT_TYPE_ALERTS)) { mAlert.setChecked(true); mPopup.setChecked(true); mPopup.setEnabled(true); } // clear out the old setting prefs.edit().remove(KEY_ALERTS_TYPE).commit(); } } /** * Keeps the dependent settings in sync with the parent preference, so for * example, when notifications are turned off, we disable the preferences * for configuring the exact notification behavior. */ private void updateChildPreferences() { if (mAlert.isChecked()) { mVibrate.setEnabled(true); mRingtone.setEnabled(true); mPopup.setEnabled(true); } else { mVibrate.setEnabled(false); mRingtone.setEnabled(false); mPopup.setEnabled(false); } } @Override public boolean onPreferenceTreeClick( PreferenceScreen preferenceScreen, Preference preference) { final String key = preference.getKey(); if (KEY_CLEAR_SEARCH_HISTORY.equals(key)) { SearchRecentSuggestions suggestions = new SearchRecentSuggestions(getActivity(), Utils.getSearchAuthority(getActivity()), CalendarRecentSuggestionsProvider.MODE); suggestions.clearHistory(); Toast.makeText(getActivity(), R.string.search_history_cleared, Toast.LENGTH_SHORT).show(); return true; } else { return super.onPreferenceTreeClick(preferenceScreen, preference); } } @Override public void onTimeZoneSet(TimeZoneInfo tzi) { if (mTzPickerUtils == null) { mTzPickerUtils = new TimeZonePickerUtils(getActivity()); } final CharSequence timezoneName = mTzPickerUtils.getGmtDisplayName( getActivity(), tzi.mTzId, System.currentTimeMillis(), false); mHomeTZ.setSummary(timezoneName); Utils.setTimeZone(getActivity(), tzi.mTzId); } }