blob: dd4c9550ea2ffe0884fd638287d46c0725424d3a [file] [log] [blame]
/*
* Copyright (C) 2021 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.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.provider.CalendarContract
import android.provider.CalendarContract.CalendarCache
import android.text.TextUtils
import android.text.format.Time
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
class GeneralPreferences : PreferenceFragment(), OnSharedPreferenceChangeListener,
OnPreferenceChangeListener, OnTimeZoneSetListener {
var mAlert: CheckBoxPreference? = null
var mVibrate: CheckBoxPreference? = null
var mPopup: CheckBoxPreference? = null
var mUseHomeTZ: CheckBoxPreference? = null
var mHideDeclined: CheckBoxPreference? = null
var mHomeTZ: Preference? = null
var mTzPickerUtils: TimeZonePickerUtils? = null
var mWeekStart: ListPreference? = null
var mDefaultReminder: ListPreference? = null
private var mTimeZoneId: String? = null
@Override
override fun onCreate(icicle: Bundle?) {
super.onCreate(icicle)
val activity: Activity = getActivity()
// Make sure to always use the same preferences file regardless of the package name
// we're running under
val preferenceManager: PreferenceManager = getPreferenceManager()
val sharedPreferences: SharedPreferences? = getSharedPreferences(activity)
preferenceManager.setSharedPreferencesName(SHARED_PREFS_NAME)
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.general_preferences)
val preferenceScreen: PreferenceScreen = getPreferenceScreen()
mAlert = preferenceScreen.findPreference(KEY_ALERTS) as CheckBoxPreference
mVibrate = preferenceScreen.findPreference(KEY_ALERTS_VIBRATE) as CheckBoxPreference
val vibrator: Vibrator = activity.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
if (vibrator == null || !vibrator.hasVibrator()) {
val mAlertGroup: PreferenceCategory = preferenceScreen
.findPreference(KEY_ALERTS_CATEGORY) as PreferenceCategory
mAlertGroup.removePreference(mVibrate)
}
mPopup = preferenceScreen.findPreference(KEY_ALERTS_POPUP) as CheckBoxPreference
mUseHomeTZ = preferenceScreen.findPreference(KEY_HOME_TZ_ENABLED) as CheckBoxPreference
mHideDeclined = preferenceScreen.findPreference(KEY_HIDE_DECLINED) as CheckBoxPreference
mWeekStart = preferenceScreen.findPreference(KEY_WEEK_START_DAY) as ListPreference
mDefaultReminder = preferenceScreen.findPreference(KEY_DEFAULT_REMINDER) as ListPreference
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)
val prefs: SharedPreferences = 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(object : Preference.OnPreferenceClickListener {
@Override
override fun onPreferenceClick(preference: Preference?): Boolean {
showTimezoneDialog()
return true
}
})
if (mTzPickerUtils == null) {
mTzPickerUtils = TimeZonePickerUtils(getActivity())
}
val timezoneName: CharSequence? = mTzPickerUtils?.getGmtDisplayName(getActivity(),
mTimeZoneId, System.currentTimeMillis(), false)
mHomeTZ?.setSummary(timezoneName ?: mTimeZoneId)
val tzpd: TimeZonePickerDialog = activity.getFragmentManager()
.findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER) as TimeZonePickerDialog
if (tzpd != null) {
tzpd.setOnTimeZoneSetListener(this)
}
migrateOldPreferences(sharedPreferences)
updateChildPreferences()
}
private fun showTimezoneDialog() {
val activity: Activity = getActivity() ?: return
val b = Bundle()
b.putLong(TimeZonePickerDialog.BUNDLE_START_TIME_MILLIS, System.currentTimeMillis())
b.putString(TimeZonePickerDialog.BUNDLE_TIME_ZONE, Utils.getTimeZone(activity, null))
val fm: FragmentManager = getActivity().getFragmentManager()
var tzpd: TimeZonePickerDialog? = fm
.findFragmentByTag(FRAG_TAG_TIME_ZONE_PICKER) as TimeZonePickerDialog
if (tzpd != null) {
tzpd.dismiss()
}
tzpd = TimeZonePickerDialog()
tzpd.setArguments(b)
tzpd.setOnTimeZoneSetListener(this)
tzpd.show(fm, FRAG_TAG_TIME_ZONE_PICKER)
}
@Override
override fun onStart() {
super.onStart()
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this)
setPreferenceListeners(this)
}
/**
* Sets up all the preference change listeners to use the specified
* listener.
*/
private fun setPreferenceListeners(listener: OnPreferenceChangeListener?) {
mUseHomeTZ?.setOnPreferenceChangeListener(listener)
mHomeTZ?.setOnPreferenceChangeListener(listener)
mWeekStart?.setOnPreferenceChangeListener(listener)
mDefaultReminder?.setOnPreferenceChangeListener(listener)
mHideDeclined?.setOnPreferenceChangeListener(listener)
mVibrate?.setOnPreferenceChangeListener(listener)
}
@Override
override fun onStop() {
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this)
setPreferenceListeners(null)
super.onStop()
}
@Override
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String) {
val a: Activity = getActivity()
if (key.equals(KEY_ALERTS)) {
updateChildPreferences()
if (a != null) {
val intent = Intent()
intent.setClass(a, AlertReceiver::class.java)
if (mAlert?.isChecked() ?: false) {
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
override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean {
val tz: String?
val activity: Activity = getActivity()
if (preference === mUseHomeTZ) {
tz = if (newValue != null) {
mTimeZoneId
} else {
CalendarCache.TIMEZONE_TYPE_AUTO
}
Utils.setTimeZone(activity, tz)
return true
} else if (preference === mHideDeclined) {
mHideDeclined?.setChecked(newValue as Boolean)
val intent = Intent(Utils.getWidgetScheduledUpdateAction(activity))
intent.setDataAndType(CalendarContract.CONTENT_URI, Utils.APPWIDGET_DATA_TYPE)
activity.sendBroadcast(intent)
return true
} else if (preference === mWeekStart) {
mWeekStart?.setValue(newValue as String)
mWeekStart?.setSummary(mWeekStart?.getEntry())
} else if (preference === mDefaultReminder) {
mDefaultReminder?.setValue(newValue as String)
mDefaultReminder?.setSummary(mDefaultReminder?.getEntry())
} else if (preference === mVibrate) {
mVibrate?.setChecked(newValue as Boolean)
return true
} else {
return true
}
return false
}
fun getRingtoneTitleFromUri(context: Context?, uri: String?): String? {
if (TextUtils.isEmpty(uri)) {
return null
}
val ring: Ringtone = RingtoneManager.getRingtone(getActivity(), Uri.parse(uri))
return if (ring != null) {
ring.getTitle(context)
} else null
}
/**
* If necessary, upgrades previous versions of preferences to the current
* set of keys and values.
* @param prefs the preferences to upgrade
*/
private fun migrateOldPreferences(prefs: SharedPreferences?) {
// 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) == false && prefs?.contains(KEY_ALERTS_TYPE) == true) {
val type: String? = 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 fun updateChildPreferences() {
if (mAlert?.isChecked() ?: false) {
mVibrate?.setEnabled(true)
mPopup?.setEnabled(true)
} else {
mVibrate?.setEnabled(false)
mPopup?.setEnabled(false)
}
}
@Override
override fun onPreferenceTreeClick(
preferenceScreen: PreferenceScreen?,
preference: Preference
): Boolean {
val key: String = preference.getKey()
return super.onPreferenceTreeClick(preferenceScreen, preference)
}
@Override
override fun onTimeZoneSet(tzi: TimeZoneInfo) {
if (mTzPickerUtils == null) {
mTzPickerUtils = TimeZonePickerUtils(getActivity())
}
val timezoneName: CharSequence? = mTzPickerUtils?.getGmtDisplayName(
getActivity(), tzi.mTzId, System.currentTimeMillis(), false)
mHomeTZ?.setSummary(timezoneName)
Utils.setTimeZone(getActivity(), tzi.mTzId)
}
companion object {
// 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.
const val SHARED_PREFS_NAME = "com.android.calendar_preferences"
const val SHARED_PREFS_NAME_NO_BACKUP = "com.android.calendar_preferences_no_backup"
private const val FRAG_TAG_TIME_ZONE_PICKER = "TimeZonePicker"
// Preference keys
const val KEY_HIDE_DECLINED = "preferences_hide_declined"
const val KEY_WEEK_START_DAY = "preferences_week_start_day"
const val KEY_SHOW_WEEK_NUM = "preferences_show_week_num"
const val KEY_DAYS_PER_WEEK = "preferences_days_per_week"
const val KEY_SKIP_SETUP = "preferences_skip_setup"
const val KEY_CLEAR_SEARCH_HISTORY = "preferences_clear_search_history"
const val KEY_ALERTS_CATEGORY = "preferences_alerts_category"
const val KEY_ALERTS = "preferences_alerts"
const val KEY_ALERTS_VIBRATE = "preferences_alerts_vibrate"
const val KEY_ALERTS_RINGTONE = "preferences_alerts_ringtone"
const val KEY_ALERTS_POPUP = "preferences_alerts_popup"
const val KEY_SHOW_CONTROLS = "preferences_show_controls"
const val KEY_DEFAULT_REMINDER = "preferences_default_reminder"
const val NO_REMINDER = -1
const val NO_REMINDER_STRING = "-1"
const val REMINDER_DEFAULT_TIME = 10 // in minutes
const val KEY_DEFAULT_CELL_HEIGHT = "preferences_default_cell_height"
const val KEY_VERSION = "preferences_version"
/** Key to SharePreference for default view (CalendarController.ViewType) */
const val KEY_START_VIEW = "preferred_startView"
/**
* Key to SharePreference for default detail view (CalendarController.ViewType)
* Typically used by widget
*/
const val KEY_DETAILED_VIEW = "preferred_detailedView"
const val KEY_DEFAULT_CALENDAR = "preference_defaultCalendar"
// These must be in sync with the array preferences_week_start_day_values
const val WEEK_START_DEFAULT = "-1"
const val WEEK_START_SATURDAY = "7"
const val WEEK_START_SUNDAY = "1"
const val WEEK_START_MONDAY = "2"
// These keys are kept to enable migrating users from previous versions
private const val KEY_ALERTS_TYPE = "preferences_alerts_type"
private const val ALERT_TYPE_ALERTS = "0"
private const val ALERT_TYPE_STATUS_BAR = "1"
private const val ALERT_TYPE_OFF = "2"
const val KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled"
const val KEY_HOME_TZ = "preferences_home_tz"
// Default preference values
const val DEFAULT_START_VIEW: Int = CalendarController.ViewType.WEEK
const val DEFAULT_DETAILED_VIEW: Int = CalendarController.ViewType.DAY
const val DEFAULT_SHOW_WEEK_NUM = false
// This should match the XML file.
const val DEFAULT_RINGTONE = "content://settings/system/notification_sound"
/** Return a properly configured SharedPreferences instance */
@JvmStatic
fun getSharedPreferences(context: Context?): SharedPreferences? {
return context?.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE)
}
/** Set the default shared preferences in the proper context */
@JvmStatic
fun setDefaultValues(context: Context?) {
PreferenceManager.setDefaultValues(context, SHARED_PREFS_NAME, Context.MODE_PRIVATE,
R.xml.general_preferences, false)
}
}
}