Home | History | Annotate | Download | only in calendar
      1 /*
      2  * Copyright (C) 2007 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.calendar;
     18 
     19 import android.app.Activity;
     20 import android.app.FragmentManager;
     21 import android.app.backup.BackupManager;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.SharedPreferences;
     25 import android.content.SharedPreferences.Editor;
     26 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
     27 import android.media.Ringtone;
     28 import android.media.RingtoneManager;
     29 import android.net.Uri;
     30 import android.os.Bundle;
     31 import android.os.Vibrator;
     32 import android.preference.CheckBoxPreference;
     33 import android.preference.ListPreference;
     34 import android.preference.Preference;
     35 import android.preference.Preference.OnPreferenceChangeListener;
     36 import android.preference.Preference.OnPreferenceClickListener;
     37 import android.preference.PreferenceCategory;
     38 import android.preference.PreferenceFragment;
     39 import android.preference.PreferenceManager;
     40 import android.preference.PreferenceScreen;
     41 import android.preference.RingtonePreference;
     42 import android.provider.CalendarContract;
     43 import android.provider.CalendarContract.CalendarCache;
     44 import android.provider.SearchRecentSuggestions;
     45 import android.text.TextUtils;
     46 import android.text.format.Time;
     47 import android.widget.Toast;
     48 
     49 import com.android.calendar.alerts.AlertReceiver;
     50 import com.android.timezonepicker.TimeZoneInfo;
     51 import com.android.timezonepicker.TimeZonePickerDialog;
     52 import com.android.timezonepicker.TimeZonePickerDialog.OnTimeZoneSetListener;
     53 import com.android.timezonepicker.TimeZonePickerUtils;
     54 
     55 public class GeneralPreferences extends PreferenceFragment implements
     56         OnSharedPreferenceChangeListener, OnPreferenceChangeListener, OnTimeZoneSetListener {
     57     // The name of the shared preferences file. This name must be maintained for historical
     58     // reasons, as it's what PreferenceManager assigned the first time the file was created.
     59     static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
     60     static final String SHARED_PREFS_NAME_NO_BACKUP = "com.android.calendar_preferences_no_backup";
     61 
     62     private static final String FRAG_TAG_TIME_ZONE_PICKER = "TimeZonePicker";
     63 
     64     // Preference keys
     65     public static final String KEY_HIDE_DECLINED = "preferences_hide_declined";
     66     public static final String KEY_WEEK_START_DAY = "preferences_week_start_day";
     67     public static final String KEY_SHOW_WEEK_NUM = "preferences_show_week_num";
     68     public static final String KEY_DAYS_PER_WEEK = "preferences_days_per_week";
     69     public static final String KEY_SKIP_SETUP = "preferences_skip_setup";
     70 
     71     public static final String KEY_CLEAR_SEARCH_HISTORY = "preferences_clear_search_history";
     72 
     73     public static final String KEY_ALERTS_CATEGORY = "preferences_alerts_category";
     74     public static final String KEY_ALERTS = "preferences_alerts";
     75     public static final String KEY_ALERTS_VIBRATE = "preferences_alerts_vibrate";
     76     public static final String KEY_ALERTS_RINGTONE = "preferences_alerts_ringtone";
     77     public static final String KEY_ALERTS_POPUP = "preferences_alerts_popup";
     78 
     79     public static final String KEY_SHOW_CONTROLS = "preferences_show_controls";
     80 
     81     public static final String KEY_DEFAULT_REMINDER = "preferences_default_reminder";
     82     public static final int NO_REMINDER = -1;
     83     public static final String NO_REMINDER_STRING = "-1";
     84     public static final int REMINDER_DEFAULT_TIME = 10; // in minutes
     85 
     86     public static final String KEY_DEFAULT_CELL_HEIGHT = "preferences_default_cell_height";
     87     public static final String KEY_VERSION = "preferences_version";
     88 
     89     /** Key to SharePreference for default view (CalendarController.ViewType) */
     90     public static final String KEY_START_VIEW = "preferred_startView";
     91     /**
     92      *  Key to SharePreference for default detail view (CalendarController.ViewType)
     93      *  Typically used by widget
     94      */
     95     public static final String KEY_DETAILED_VIEW = "preferred_detailedView";
     96     public static final String KEY_DEFAULT_CALENDAR = "preference_defaultCalendar";
     97 
     98     // These must be in sync with the array preferences_week_start_day_values
     99     public static final String WEEK_START_DEFAULT = "-1";
    100     public static final String WEEK_START_SATURDAY = "7";
    101     public static final String WEEK_START_SUNDAY = "1";
    102     public static final String WEEK_START_MONDAY = "2";
    103 
    104     // These keys are kept to enable migrating users from previous versions
    105     private static final String KEY_ALERTS_TYPE = "preferences_alerts_type";
    106     private static final String ALERT_TYPE_ALERTS = "0";
    107     private static final String ALERT_TYPE_STATUS_BAR = "1";
    108     private static final String ALERT_TYPE_OFF = "2";
    109     static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled";
    110     static final String KEY_HOME_TZ = "preferences_home_tz";
    111 
    112     // Default preference values
    113     public static final int DEFAULT_START_VIEW = CalendarController.ViewType.WEEK;
    114     public static final int DEFAULT_DETAILED_VIEW = CalendarController.ViewType.DAY;
    115     public static final boolean DEFAULT_SHOW_WEEK_NUM = false;
    116     // This should match the XML file.
    117     public static final String DEFAULT_RINGTONE = "content://settings/system/notification_sound";
    118 
    119     CheckBoxPreference mAlert;
    120     CheckBoxPreference mVibrate;
    121     RingtonePreference mRingtone;
    122     CheckBoxPreference mPopup;
    123     CheckBoxPreference mUseHomeTZ;
    124     CheckBoxPreference mHideDeclined;
    125     Preference mHomeTZ;
    126     TimeZonePickerUtils mTzPickerUtils;
    127     ListPreference mWeekStart;
    128     ListPreference mDefaultReminder;
    129 
    130     private String mTimeZoneId;
    131 
    132     /** Return a properly configured SharedPreferences instance */
    133     public static SharedPreferences getSharedPreferences(Context context) {
    134         return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
    135     }
    136 
    137     /** Set the default shared preferences in the proper context */
    138     public static void setDefaultValues(Context context) {
    139         PreferenceManager.setDefaultValues(context, SHARED_PREFS_NAME, Context.MODE_PRIVATE,
    140                 R.xml.general_preferences, false);
    141     }
    142 
    143     @Override
    144     public void onCreate(Bundle icicle) {
    145         super.onCreate(icicle);
    146 
    147         final Activity activity = getActivity();
    148 
    149         // Make sure to always use the same preferences file regardless of the package name
    150         // we're running under
    151         final PreferenceManager preferenceManager = getPreferenceManager();
    152         final SharedPreferences sharedPreferences = getSharedPreferences(activity);
    153         preferenceManager.setSharedPreferencesName(SHARED_PREFS_NAME);
    154 
    155         // Load the preferences from an XML resource
    156         addPreferencesFromResource(R.xml.general_preferences);
    157 
    158         final PreferenceScreen preferenceScreen = getPreferenceScreen();
    159         mAlert = (CheckBoxPreference) preferenceScreen.findPreference(KEY_ALERTS);
    160         mVibrate = (CheckBoxPreference) preferenceScreen.findPreference(KEY_ALERTS_VIBRATE);
    161         Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
    162         if (vibrator == null || !vibrator.hasVibrator()) {
    163             PreferenceCategory mAlertGroup = (PreferenceCategory) preferenceScreen
    164                     .findPreference(KEY_ALERTS_CATEGORY);
    165             mAlertGroup.removePreference(mVibrate);
    166         }
    167 
    168         mRingtone = (RingtonePreference) preferenceScreen.findPreference(KEY_ALERTS_RINGTONE);
    169         String ringToneUri = Utils.getRingTonePreference(activity);
    170 
    171         // Set the ringToneUri to the backup-able shared pref only so that
    172         // the Ringtone dialog will open up with the correct value.
    173         final Editor editor = preferenceScreen.getEditor();
    174         editor.putString(GeneralPreferences.KEY_ALERTS_RINGTONE, ringToneUri).apply();
    175 
    176         String ringtoneDisplayString = getRingtoneTitleFromUri(activity, ringToneUri);
    177         mRingtone.setSummary(ringtoneDisplayString == null ? "" : ringtoneDisplayString);
    178 
    179         mPopup = (CheckBoxPreference) preferenceScreen.findPreference(KEY_ALERTS_POPUP);
    180         mUseHomeTZ = (CheckBoxPreference) preferenceScreen.findPreference(KEY_HOME_TZ_ENABLED);
    181         mHideDeclined = (CheckBoxPreference) preferenceScreen.findPreference(KEY_HIDE_DECLINED);
    182         mWeekStart = (ListPreference) preferenceScreen.findPreference(KEY_WEEK_START_DAY);
    183         mDefaultReminder = (ListPreference) preferenceScreen.findPreference(KEY_DEFAULT_REMINDER);
    184         mHomeTZ = preferenceScreen.findPreference(KEY_HOME_TZ);
    185         mWeekStart.setSummary(mWeekStart.getEntry());
    186         mDefaultReminder.setSummary(mDefaultReminder.getEntry());
    187 
    188         // This triggers an asynchronous call to the provider to refresh the data in shared pref
    189         mTimeZoneId = Utils.getTimeZone(activity, null);
    190 
    191         SharedPreferences prefs = CalendarUtils.getSharedPreferences(activity,
    192                 Utils.SHARED_PREFS_NAME);
    193 
    194         // Utils.getTimeZone will return the currentTimeZone instead of the one
    195         // in the shared_pref if home time zone is disabled. So if home tz is
    196         // off, we will explicitly read it.
    197         if (!prefs.getBoolean(KEY_HOME_TZ_ENABLED, false)) {
    198             mTimeZoneId = prefs.getString(KEY_HOME_TZ, Time.getCurrentTimezone());
    199         }
    200 
    201         mHomeTZ.setOnPreferenceClickListener(new OnPreferenceClickListener() {
    202             @Override
    203             public boolean onPreferenceClick(Preference preference) {
    204                 showTimezoneDialog();
    205                 return true;
    206             }
    207         });
    208 
    209         if (mTzPickerUtils == null) {
    210             mTzPickerUtils = new TimeZonePickerUtils(getActivity());
    211         }
    212         CharSequence timezoneName = mTzPickerUtils.getGmtDisplayName(getActivity(), mTimeZoneId,
    213                 System.currentTimeMillis(), false);
    214         mHomeTZ.setSummary(timezoneName != null ? timezoneName : mTimeZoneId);
    215 
    216         TimeZonePickerDialog tzpd = (TimeZonePickerDialog) activity.getFragmentManager()
    217                 .findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER);
    218         if (tzpd != null) {
    219             tzpd.setOnTimeZoneSetListener(this);
    220         }
    221 
    222         migrateOldPreferences(sharedPreferences);
    223 
    224         updateChildPreferences();
    225     }
    226 
    227     private void showTimezoneDialog() {
    228         final Activity activity = getActivity();
    229         if (activity == null) {
    230             return;
    231         }
    232 
    233         Bundle b = new Bundle();
    234         b.putLong(TimeZonePickerDialog.BUNDLE_START_TIME_MILLIS, System.currentTimeMillis());
    235         b.putString(TimeZonePickerDialog.BUNDLE_TIME_ZONE, Utils.getTimeZone(activity, null));
    236 
    237         FragmentManager fm = getActivity().getFragmentManager();
    238         TimeZonePickerDialog tzpd = (TimeZonePickerDialog) fm
    239                 .findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER);
    240         if (tzpd != null) {
    241             tzpd.dismiss();
    242         }
    243         tzpd = new TimeZonePickerDialog();
    244         tzpd.setArguments(b);
    245         tzpd.setOnTimeZoneSetListener(this);
    246         tzpd.show(fm, FRAG_TAG_TIME_ZONE_PICKER);
    247     }
    248 
    249     @Override
    250     public void onStart() {
    251         super.onStart();
    252         getPreferenceScreen().getSharedPreferences()
    253                 .registerOnSharedPreferenceChangeListener(this);
    254         setPreferenceListeners(this);
    255     }
    256 
    257     /**
    258      * Sets up all the preference change listeners to use the specified
    259      * listener.
    260      */
    261     private void setPreferenceListeners(OnPreferenceChangeListener listener) {
    262         mUseHomeTZ.setOnPreferenceChangeListener(listener);
    263         mHomeTZ.setOnPreferenceChangeListener(listener);
    264         mWeekStart.setOnPreferenceChangeListener(listener);
    265         mDefaultReminder.setOnPreferenceChangeListener(listener);
    266         mRingtone.setOnPreferenceChangeListener(listener);
    267         mHideDeclined.setOnPreferenceChangeListener(listener);
    268         mVibrate.setOnPreferenceChangeListener(listener);
    269     }
    270 
    271     @Override
    272     public void onStop() {
    273         getPreferenceScreen().getSharedPreferences()
    274                 .unregisterOnSharedPreferenceChangeListener(this);
    275         setPreferenceListeners(null);
    276         super.onStop();
    277     }
    278 
    279     @Override
    280     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    281         Activity a = getActivity();
    282         if (key.equals(KEY_ALERTS)) {
    283             updateChildPreferences();
    284             if (a != null) {
    285                 Intent intent = new Intent();
    286                 intent.setClass(a, AlertReceiver.class);
    287                 if (mAlert.isChecked()) {
    288                     intent.setAction(AlertReceiver.ACTION_DISMISS_OLD_REMINDERS);
    289                 } else {
    290                     intent.setAction(AlertReceiver.EVENT_REMINDER_APP_ACTION);
    291                 }
    292                 a.sendBroadcast(intent);
    293             }
    294         }
    295         if (a != null) {
    296             BackupManager.dataChanged(a.getPackageName());
    297         }
    298     }
    299 
    300     /**
    301      * Handles time zone preference changes
    302      */
    303     @Override
    304     public boolean onPreferenceChange(Preference preference, Object newValue) {
    305         String tz;
    306         final Activity activity = getActivity();
    307         if (preference == mUseHomeTZ) {
    308             if ((Boolean)newValue) {
    309                 tz = mTimeZoneId;
    310             } else {
    311                 tz = CalendarCache.TIMEZONE_TYPE_AUTO;
    312             }
    313             Utils.setTimeZone(activity, tz);
    314             return true;
    315         } else if (preference == mHideDeclined) {
    316             mHideDeclined.setChecked((Boolean) newValue);
    317             Intent intent = new Intent(Utils.getWidgetScheduledUpdateAction(activity));
    318             intent.setDataAndType(CalendarContract.CONTENT_URI, Utils.APPWIDGET_DATA_TYPE);
    319             activity.sendBroadcast(intent);
    320             return true;
    321         } else if (preference == mWeekStart) {
    322             mWeekStart.setValue((String) newValue);
    323             mWeekStart.setSummary(mWeekStart.getEntry());
    324         } else if (preference == mDefaultReminder) {
    325             mDefaultReminder.setValue((String) newValue);
    326             mDefaultReminder.setSummary(mDefaultReminder.getEntry());
    327         } else if (preference == mRingtone) {
    328             if (newValue instanceof String) {
    329                 Utils.setRingTonePreference(activity, (String) newValue);
    330                 String ringtone = getRingtoneTitleFromUri(activity, (String) newValue);
    331                 mRingtone.setSummary(ringtone == null ? "" : ringtone);
    332             }
    333             return true;
    334         } else if (preference == mVibrate) {
    335             mVibrate.setChecked((Boolean) newValue);
    336             return true;
    337         } else {
    338             return true;
    339         }
    340         return false;
    341     }
    342 
    343     public String getRingtoneTitleFromUri(Context context, String uri) {
    344         if (TextUtils.isEmpty(uri)) {
    345             return null;
    346         }
    347 
    348         Ringtone ring = RingtoneManager.getRingtone(getActivity(), Uri.parse(uri));
    349         if (ring != null) {
    350             return ring.getTitle(context);
    351         }
    352         return null;
    353     }
    354 
    355     /**
    356      * If necessary, upgrades previous versions of preferences to the current
    357      * set of keys and values.
    358      * @param prefs the preferences to upgrade
    359      */
    360     private void migrateOldPreferences(SharedPreferences prefs) {
    361         // If needed, migrate vibration setting from a previous version
    362 
    363         mVibrate.setChecked(Utils.getDefaultVibrate(getActivity(), prefs));
    364 
    365         // If needed, migrate the old alerts type settin
    366         if (!prefs.contains(KEY_ALERTS) && prefs.contains(KEY_ALERTS_TYPE)) {
    367             String type = prefs.getString(KEY_ALERTS_TYPE, ALERT_TYPE_STATUS_BAR);
    368             if (type.equals(ALERT_TYPE_OFF)) {
    369                 mAlert.setChecked(false);
    370                 mPopup.setChecked(false);
    371                 mPopup.setEnabled(false);
    372             } else if (type.equals(ALERT_TYPE_STATUS_BAR)) {
    373                 mAlert.setChecked(true);
    374                 mPopup.setChecked(false);
    375                 mPopup.setEnabled(true);
    376             } else if (type.equals(ALERT_TYPE_ALERTS)) {
    377                 mAlert.setChecked(true);
    378                 mPopup.setChecked(true);
    379                 mPopup.setEnabled(true);
    380             }
    381             // clear out the old setting
    382             prefs.edit().remove(KEY_ALERTS_TYPE).commit();
    383         }
    384     }
    385 
    386     /**
    387      * Keeps the dependent settings in sync with the parent preference, so for
    388      * example, when notifications are turned off, we disable the preferences
    389      * for configuring the exact notification behavior.
    390      */
    391     private void updateChildPreferences() {
    392         if (mAlert.isChecked()) {
    393             mVibrate.setEnabled(true);
    394             mRingtone.setEnabled(true);
    395             mPopup.setEnabled(true);
    396         } else {
    397             mVibrate.setEnabled(false);
    398             mRingtone.setEnabled(false);
    399             mPopup.setEnabled(false);
    400         }
    401     }
    402 
    403 
    404     @Override
    405     public boolean onPreferenceTreeClick(
    406             PreferenceScreen preferenceScreen, Preference preference) {
    407         final String key = preference.getKey();
    408         if (KEY_CLEAR_SEARCH_HISTORY.equals(key)) {
    409             SearchRecentSuggestions suggestions = new SearchRecentSuggestions(getActivity(),
    410                     Utils.getSearchAuthority(getActivity()),
    411                     CalendarRecentSuggestionsProvider.MODE);
    412             suggestions.clearHistory();
    413             Toast.makeText(getActivity(), R.string.search_history_cleared,
    414                     Toast.LENGTH_SHORT).show();
    415             return true;
    416         } else {
    417             return super.onPreferenceTreeClick(preferenceScreen, preference);
    418         }
    419     }
    420 
    421     @Override
    422     public void onTimeZoneSet(TimeZoneInfo tzi) {
    423         if (mTzPickerUtils == null) {
    424             mTzPickerUtils = new TimeZonePickerUtils(getActivity());
    425         }
    426 
    427         final CharSequence timezoneName = mTzPickerUtils.getGmtDisplayName(
    428                 getActivity(), tzi.mTzId, System.currentTimeMillis(), false);
    429         mHomeTZ.setSummary(timezoneName);
    430         Utils.setTimeZone(getActivity(), tzi.mTzId);
    431     }
    432 }
    433