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