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 CheckBoxPreference mPopup; 122 CheckBoxPreference mUseHomeTZ; 123 CheckBoxPreference mHideDeclined; 124 Preference mHomeTZ; 125 TimeZonePickerUtils mTzPickerUtils; 126 ListPreference mWeekStart; 127 ListPreference mDefaultReminder; 128 129 private String mTimeZoneId; 130 131 /** Return a properly configured SharedPreferences instance */ getSharedPreferences(Context context)132 public static SharedPreferences getSharedPreferences(Context context) { 133 return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE); 134 } 135 136 /** Set the default shared preferences in the proper context */ setDefaultValues(Context context)137 public static void setDefaultValues(Context context) { 138 PreferenceManager.setDefaultValues(context, SHARED_PREFS_NAME, Context.MODE_PRIVATE, 139 R.xml.general_preferences, false); 140 } 141 142 @Override onCreate(Bundle icicle)143 public void onCreate(Bundle icicle) { 144 super.onCreate(icicle); 145 146 final Activity activity = getActivity(); 147 148 // Make sure to always use the same preferences file regardless of the package name 149 // we're running under 150 final PreferenceManager preferenceManager = getPreferenceManager(); 151 final SharedPreferences sharedPreferences = getSharedPreferences(activity); 152 preferenceManager.setSharedPreferencesName(SHARED_PREFS_NAME); 153 154 // Load the preferences from an XML resource 155 addPreferencesFromResource(R.xml.general_preferences); 156 157 final PreferenceScreen preferenceScreen = getPreferenceScreen(); 158 mAlert = (CheckBoxPreference) preferenceScreen.findPreference(KEY_ALERTS); 159 mVibrate = (CheckBoxPreference) preferenceScreen.findPreference(KEY_ALERTS_VIBRATE); 160 Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); 161 if (vibrator == null || !vibrator.hasVibrator()) { 162 PreferenceCategory mAlertGroup = (PreferenceCategory) preferenceScreen 163 .findPreference(KEY_ALERTS_CATEGORY); 164 mAlertGroup.removePreference(mVibrate); 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 // This triggers an asynchronous call to the provider to refresh the data in shared pref 177 mTimeZoneId = Utils.getTimeZone(activity, null); 178 179 SharedPreferences prefs = CalendarUtils.getSharedPreferences(activity, 180 Utils.SHARED_PREFS_NAME); 181 182 // Utils.getTimeZone will return the currentTimeZone instead of the one 183 // in the shared_pref if home time zone is disabled. So if home tz is 184 // off, we will explicitly read it. 185 if (!prefs.getBoolean(KEY_HOME_TZ_ENABLED, false)) { 186 mTimeZoneId = prefs.getString(KEY_HOME_TZ, Time.getCurrentTimezone()); 187 } 188 189 mHomeTZ.setOnPreferenceClickListener(new OnPreferenceClickListener() { 190 @Override 191 public boolean onPreferenceClick(Preference preference) { 192 showTimezoneDialog(); 193 return true; 194 } 195 }); 196 197 if (mTzPickerUtils == null) { 198 mTzPickerUtils = new TimeZonePickerUtils(getActivity()); 199 } 200 CharSequence timezoneName = mTzPickerUtils.getGmtDisplayName(getActivity(), mTimeZoneId, 201 System.currentTimeMillis(), false); 202 mHomeTZ.setSummary(timezoneName != null ? timezoneName : mTimeZoneId); 203 204 TimeZonePickerDialog tzpd = (TimeZonePickerDialog) activity.getFragmentManager() 205 .findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER); 206 if (tzpd != null) { 207 tzpd.setOnTimeZoneSetListener(this); 208 } 209 210 migrateOldPreferences(sharedPreferences); 211 212 updateChildPreferences(); 213 } 214 showTimezoneDialog()215 private void showTimezoneDialog() { 216 final Activity activity = getActivity(); 217 if (activity == null) { 218 return; 219 } 220 221 Bundle b = new Bundle(); 222 b.putLong(TimeZonePickerDialog.BUNDLE_START_TIME_MILLIS, System.currentTimeMillis()); 223 b.putString(TimeZonePickerDialog.BUNDLE_TIME_ZONE, Utils.getTimeZone(activity, null)); 224 225 FragmentManager fm = getActivity().getFragmentManager(); 226 TimeZonePickerDialog tzpd = (TimeZonePickerDialog) fm 227 .findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER); 228 if (tzpd != null) { 229 tzpd.dismiss(); 230 } 231 tzpd = new TimeZonePickerDialog(); 232 tzpd.setArguments(b); 233 tzpd.setOnTimeZoneSetListener(this); 234 tzpd.show(fm, FRAG_TAG_TIME_ZONE_PICKER); 235 } 236 237 @Override onStart()238 public void onStart() { 239 super.onStart(); 240 getPreferenceScreen().getSharedPreferences() 241 .registerOnSharedPreferenceChangeListener(this); 242 setPreferenceListeners(this); 243 } 244 245 /** 246 * Sets up all the preference change listeners to use the specified 247 * listener. 248 */ setPreferenceListeners(OnPreferenceChangeListener listener)249 private void setPreferenceListeners(OnPreferenceChangeListener listener) { 250 mUseHomeTZ.setOnPreferenceChangeListener(listener); 251 mHomeTZ.setOnPreferenceChangeListener(listener); 252 mWeekStart.setOnPreferenceChangeListener(listener); 253 mDefaultReminder.setOnPreferenceChangeListener(listener); 254 mHideDeclined.setOnPreferenceChangeListener(listener); 255 mVibrate.setOnPreferenceChangeListener(listener); 256 } 257 258 @Override onStop()259 public void onStop() { 260 getPreferenceScreen().getSharedPreferences() 261 .unregisterOnSharedPreferenceChangeListener(this); 262 setPreferenceListeners(null); 263 super.onStop(); 264 } 265 266 @Override onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)267 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 268 Activity a = getActivity(); 269 if (key.equals(KEY_ALERTS)) { 270 updateChildPreferences(); 271 if (a != null) { 272 Intent intent = new Intent(); 273 intent.setClass(a, AlertReceiver.class); 274 if (mAlert.isChecked()) { 275 intent.setAction(AlertReceiver.ACTION_DISMISS_OLD_REMINDERS); 276 } else { 277 intent.setAction(AlertReceiver.EVENT_REMINDER_APP_ACTION); 278 } 279 a.sendBroadcast(intent); 280 } 281 } 282 if (a != null) { 283 BackupManager.dataChanged(a.getPackageName()); 284 } 285 } 286 287 /** 288 * Handles time zone preference changes 289 */ 290 @Override onPreferenceChange(Preference preference, Object newValue)291 public boolean onPreferenceChange(Preference preference, Object newValue) { 292 String tz; 293 final Activity activity = getActivity(); 294 if (preference == mUseHomeTZ) { 295 if ((Boolean)newValue) { 296 tz = mTimeZoneId; 297 } else { 298 tz = CalendarCache.TIMEZONE_TYPE_AUTO; 299 } 300 Utils.setTimeZone(activity, tz); 301 return true; 302 } else if (preference == mHideDeclined) { 303 mHideDeclined.setChecked((Boolean) newValue); 304 Intent intent = new Intent(Utils.getWidgetScheduledUpdateAction(activity)); 305 intent.setDataAndType(CalendarContract.CONTENT_URI, Utils.APPWIDGET_DATA_TYPE); 306 activity.sendBroadcast(intent); 307 return true; 308 } else if (preference == mWeekStart) { 309 mWeekStart.setValue((String) newValue); 310 mWeekStart.setSummary(mWeekStart.getEntry()); 311 } else if (preference == mDefaultReminder) { 312 mDefaultReminder.setValue((String) newValue); 313 mDefaultReminder.setSummary(mDefaultReminder.getEntry()); 314 } else if (preference == mVibrate) { 315 mVibrate.setChecked((Boolean) newValue); 316 return true; 317 } else { 318 return true; 319 } 320 return false; 321 } 322 getRingtoneTitleFromUri(Context context, String uri)323 public String getRingtoneTitleFromUri(Context context, String uri) { 324 if (TextUtils.isEmpty(uri)) { 325 return null; 326 } 327 328 Ringtone ring = RingtoneManager.getRingtone(getActivity(), Uri.parse(uri)); 329 if (ring != null) { 330 return ring.getTitle(context); 331 } 332 return null; 333 } 334 335 /** 336 * If necessary, upgrades previous versions of preferences to the current 337 * set of keys and values. 338 * @param prefs the preferences to upgrade 339 */ migrateOldPreferences(SharedPreferences prefs)340 private void migrateOldPreferences(SharedPreferences prefs) { 341 // If needed, migrate vibration setting from a previous version 342 343 mVibrate.setChecked(Utils.getDefaultVibrate(getActivity(), prefs)); 344 345 // If needed, migrate the old alerts type settin 346 if (!prefs.contains(KEY_ALERTS) && prefs.contains(KEY_ALERTS_TYPE)) { 347 String type = prefs.getString(KEY_ALERTS_TYPE, ALERT_TYPE_STATUS_BAR); 348 if (type.equals(ALERT_TYPE_OFF)) { 349 mAlert.setChecked(false); 350 mPopup.setChecked(false); 351 mPopup.setEnabled(false); 352 } else if (type.equals(ALERT_TYPE_STATUS_BAR)) { 353 mAlert.setChecked(true); 354 mPopup.setChecked(false); 355 mPopup.setEnabled(true); 356 } else if (type.equals(ALERT_TYPE_ALERTS)) { 357 mAlert.setChecked(true); 358 mPopup.setChecked(true); 359 mPopup.setEnabled(true); 360 } 361 // clear out the old setting 362 prefs.edit().remove(KEY_ALERTS_TYPE).commit(); 363 } 364 } 365 366 /** 367 * Keeps the dependent settings in sync with the parent preference, so for 368 * example, when notifications are turned off, we disable the preferences 369 * for configuring the exact notification behavior. 370 */ updateChildPreferences()371 private void updateChildPreferences() { 372 if (mAlert.isChecked()) { 373 mVibrate.setEnabled(true); 374 mPopup.setEnabled(true); 375 } else { 376 mVibrate.setEnabled(false); 377 mPopup.setEnabled(false); 378 } 379 } 380 381 382 @Override onPreferenceTreeClick( PreferenceScreen preferenceScreen, Preference preference)383 public boolean onPreferenceTreeClick( 384 PreferenceScreen preferenceScreen, Preference preference) { 385 final String key = preference.getKey(); 386 return super.onPreferenceTreeClick(preferenceScreen, preference); 387 } 388 389 @Override onTimeZoneSet(TimeZoneInfo tzi)390 public void onTimeZoneSet(TimeZoneInfo tzi) { 391 if (mTzPickerUtils == null) { 392 mTzPickerUtils = new TimeZonePickerUtils(getActivity()); 393 } 394 395 final CharSequence timezoneName = mTzPickerUtils.getGmtDisplayName( 396 getActivity(), tzi.mTzId, System.currentTimeMillis(), false); 397 mHomeTZ.setSummary(timezoneName); 398 Utils.setTimeZone(getActivity(), tzi.mTzId); 399 } 400 } 401