1 /* 2 * Copyright (C) 2020 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.deskclock.settings 18 19 import android.content.Context 20 import android.content.Intent 21 import android.os.Bundle 22 import android.os.Vibrator 23 import android.provider.Settings 24 import android.view.Menu 25 import android.view.MenuItem 26 import android.view.View 27 import androidx.preference.ListPreference 28 import androidx.preference.ListPreferenceDialogFragmentCompat 29 import androidx.preference.Preference 30 import androidx.preference.PreferenceDialogFragmentCompat 31 import androidx.preference.PreferenceFragmentCompat 32 import androidx.preference.TwoStatePreference 33 34 import com.android.deskclock.BaseActivity 35 import com.android.deskclock.DropShadowController 36 import com.android.deskclock.R 37 import com.android.deskclock.Utils 38 import com.android.deskclock.actionbarmenu.MenuItemControllerFactory 39 import com.android.deskclock.actionbarmenu.NavUpMenuItemController 40 import com.android.deskclock.actionbarmenu.OptionsMenuManager 41 import com.android.deskclock.data.DataModel 42 import com.android.deskclock.ringtone.RingtonePickerActivity 43 44 /** 45 * Settings for the Alarm Clock. 46 */ 47 class SettingsActivity : BaseActivity() { 48 private val mOptionsMenuManager = OptionsMenuManager() 49 50 /** 51 * The controller that shows the drop shadow when content is not scrolled to the top. 52 */ 53 private lateinit var mDropShadowController: DropShadowController 54 onCreatenull55 override fun onCreate(savedInstanceState: Bundle?) { 56 super.onCreate(savedInstanceState) 57 setContentView(R.layout.settings) 58 59 mOptionsMenuManager.addMenuItemController(NavUpMenuItemController(this)) 60 .addMenuItemController(*MenuItemControllerFactory.buildMenuItemControllers(this)) 61 62 // Create the prefs fragment in code to ensure it's created before PreferenceDialogFragment 63 if (savedInstanceState == null) { 64 getSupportFragmentManager().beginTransaction() 65 .replace(R.id.main, PrefsFragment(), PREFS_FRAGMENT_TAG) 66 .disallowAddToBackStack() 67 .commit() 68 } 69 } 70 onResumenull71 override fun onResume() { 72 super.onResume() 73 74 val dropShadow: View = findViewById(R.id.drop_shadow) 75 val fragment = getSupportFragmentManager().findFragmentById(R.id.main) as PrefsFragment 76 mDropShadowController = DropShadowController(dropShadow, fragment.getListView()) 77 } 78 onPausenull79 override fun onPause() { 80 mDropShadowController.stop() 81 super.onPause() 82 } 83 onCreateOptionsMenunull84 override fun onCreateOptionsMenu(menu: Menu): Boolean { 85 mOptionsMenuManager.onCreateOptionsMenu(menu) 86 return true 87 } 88 onPrepareOptionsMenunull89 override fun onPrepareOptionsMenu(menu: Menu): Boolean { 90 mOptionsMenuManager.onPrepareOptionsMenu(menu) 91 return true 92 } 93 onOptionsItemSelectednull94 override fun onOptionsItemSelected(item: MenuItem): Boolean { 95 return (mOptionsMenuManager.onOptionsItemSelected(item) || 96 super.onOptionsItemSelected(item)) 97 } 98 99 class PrefsFragment : 100 PreferenceFragmentCompat(), 101 Preference.OnPreferenceChangeListener, 102 Preference.OnPreferenceClickListener { 103 onCreatePreferencesnull104 override fun onCreatePreferences(bundle: Bundle?, rootKey: String?) { 105 getPreferenceManager().setStorageDeviceProtected() 106 addPreferencesFromResource(R.xml.settings) 107 val timerVibrate: Preference? = findPreference(KEY_TIMER_VIBRATE) 108 timerVibrate?.let { 109 val hasVibrator: Boolean = (it.getContext() 110 .getSystemService(VIBRATOR_SERVICE) as Vibrator).hasVibrator() 111 it.setVisible(hasVibrator) 112 } 113 loadTimeZoneList() 114 } 115 onActivityCreatednull116 override fun onActivityCreated(savedInstanceState: Bundle?) { 117 super.onActivityCreated(savedInstanceState) 118 119 // By default, do not recreate the DeskClock activity 120 getActivity()?.setResult(RESULT_CANCELED) 121 } 122 onResumenull123 override fun onResume() { 124 super.onResume() 125 refresh() 126 } 127 onPreferenceChangenull128 override fun onPreferenceChange(pref: Preference, newValue: Any): Boolean { 129 when (pref.getKey()) { 130 KEY_ALARM_CRESCENDO, KEY_HOME_TZ, KEY_ALARM_SNOOZE, KEY_TIMER_CRESCENDO -> { 131 val preference: ListPreference = pref as ListPreference 132 val index: Int = preference.findIndexOfValue(newValue as String) 133 preference.setSummary(preference.getEntries().get(index)) 134 } 135 KEY_CLOCK_STYLE, KEY_WEEK_START, KEY_VOLUME_BUTTONS -> { 136 val simpleMenuPreference = pref as SimpleMenuPreference 137 val i: Int = simpleMenuPreference.findIndexOfValue(newValue as String) 138 pref.setSummary(simpleMenuPreference.getEntries().get(i)) 139 } 140 KEY_CLOCK_DISPLAY_SECONDS -> { 141 DataModel.dataModel.displayClockSeconds = newValue as Boolean 142 } 143 KEY_AUTO_SILENCE -> { 144 val delay = newValue as String 145 updateAutoSnoozeSummary(pref as ListPreference, delay) 146 } 147 KEY_AUTO_HOME_CLOCK -> { 148 val autoHomeClockEnabled: Boolean = (pref as TwoStatePreference).isChecked() 149 val homeTimeZonePref: Preference? = findPreference(KEY_HOME_TZ) 150 homeTimeZonePref?.setEnabled(!autoHomeClockEnabled) 151 } 152 KEY_TIMER_VIBRATE -> { 153 val timerVibratePref: TwoStatePreference = pref as TwoStatePreference 154 DataModel.dataModel.timerVibrate = timerVibratePref.isChecked() 155 } 156 KEY_TIMER_RINGTONE -> pref.setSummary(DataModel.dataModel.timerRingtoneTitle) 157 } 158 159 // Set result so DeskClock knows to refresh itself 160 getActivity()?.setResult(RESULT_OK) 161 return true 162 } 163 onPreferenceClicknull164 override fun onPreferenceClick(pref: Preference): Boolean { 165 val context: Context = getActivity() ?: return false 166 167 when (pref.getKey()) { 168 KEY_DATE_TIME -> { 169 val dialogIntent = Intent(Settings.ACTION_DATE_SETTINGS) 170 dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 171 startActivity(dialogIntent) 172 return true 173 } 174 KEY_TIMER_RINGTONE -> { 175 startActivity(RingtonePickerActivity.createTimerRingtonePickerIntent(context)) 176 return true 177 } 178 else -> return false 179 } 180 } 181 onDisplayPreferenceDialognull182 override fun onDisplayPreferenceDialog(preference: Preference) { 183 // Only single-selection lists are currently supported. 184 val f: PreferenceDialogFragmentCompat 185 f = if (preference is ListPreference) { 186 ListPreferenceDialogFragmentCompat.newInstance(preference.getKey()) 187 } else { 188 throw IllegalArgumentException("Unsupported DialogPreference type") 189 } 190 showDialog(f) 191 } 192 showDialognull193 private fun showDialog(fragment: PreferenceDialogFragmentCompat) { 194 // Don't show dialog if one is already shown. 195 if (parentFragmentManager.findFragmentByTag(PREFERENCE_DIALOG_FRAGMENT_TAG) != null) { 196 return 197 } 198 // Always set the target fragment, this is required by PreferenceDialogFragment 199 // internally. 200 fragment.setTargetFragment(this, 0) 201 // Don't use getChildFragmentManager(), it causes issues on older platforms when the 202 // target fragment is being restored after an orientation change. 203 fragment.show(parentFragmentManager, PREFERENCE_DIALOG_FRAGMENT_TAG) 204 } 205 206 /** 207 * Reconstruct the timezone list. 208 */ loadTimeZoneListnull209 private fun loadTimeZoneList() { 210 val timezones = DataModel.dataModel.timeZones 211 val homeTimezonePref: ListPreference? = findPreference(KEY_HOME_TZ) 212 homeTimezonePref?.let { 213 it.setEntryValues(timezones.timeZoneIds) 214 it.setEntries(timezones.timeZoneNames) 215 it.setSummary(homeTimezonePref.getEntry()) 216 it.setOnPreferenceChangeListener(this) 217 } 218 } 219 refreshnull220 private fun refresh() { 221 val autoSilencePref: ListPreference? = findPreference(KEY_AUTO_SILENCE) 222 autoSilencePref?.let { 223 val delay: String = it.getValue() 224 updateAutoSnoozeSummary(it, delay) 225 it.setOnPreferenceChangeListener(this) 226 } 227 228 val clockStylePref: SimpleMenuPreference? = findPreference(KEY_CLOCK_STYLE) 229 clockStylePref?.let { 230 it.setSummary(it.getEntry()) 231 it.setOnPreferenceChangeListener(this) 232 } 233 234 val volumeButtonsPref: SimpleMenuPreference? = findPreference(KEY_VOLUME_BUTTONS) 235 volumeButtonsPref?.let { 236 it.setSummary(volumeButtonsPref.getEntry()) 237 it.setOnPreferenceChangeListener(this) 238 } 239 240 val clockSecondsPref: Preference? = findPreference(KEY_CLOCK_DISPLAY_SECONDS) 241 clockSecondsPref?.setOnPreferenceChangeListener(this) 242 243 val autoHomeClockPref: Preference? = findPreference(KEY_AUTO_HOME_CLOCK) 244 val autoHomeClockEnabled: Boolean = 245 (autoHomeClockPref as TwoStatePreference).isChecked() 246 autoHomeClockPref.setOnPreferenceChangeListener(this) 247 248 val homeTimezonePref: ListPreference? = findPreference(KEY_HOME_TZ) 249 homeTimezonePref?.setEnabled(autoHomeClockEnabled) 250 refreshListPreference(homeTimezonePref!!) 251 252 refreshListPreference(findPreference(KEY_ALARM_CRESCENDO)!!) 253 refreshListPreference(findPreference(KEY_TIMER_CRESCENDO)!!) 254 refreshListPreference(findPreference(KEY_ALARM_SNOOZE)!!) 255 256 val dateAndTimeSetting: Preference? = findPreference(KEY_DATE_TIME) 257 dateAndTimeSetting?.setOnPreferenceClickListener(this) 258 259 val weekStartPref: SimpleMenuPreference? = findPreference(KEY_WEEK_START) 260 // Set the default value programmatically 261 val weekdayOrder = DataModel.dataModel.weekdayOrder 262 val firstDay = weekdayOrder.calendarDays[0] 263 val value = firstDay.toString() 264 weekStartPref?.let { 265 val idx: Int = it.findIndexOfValue(value) 266 it.setValueIndex(idx) 267 it.setSummary(weekStartPref.getEntries().get(idx)) 268 it.setOnPreferenceChangeListener(this) 269 } 270 271 val timerRingtonePref: Preference? = findPreference(KEY_TIMER_RINGTONE) 272 timerRingtonePref?.let { 273 it.setOnPreferenceClickListener(this) 274 it.setSummary(DataModel.dataModel.timerRingtoneTitle) 275 } 276 } 277 refreshListPreferencenull278 private fun refreshListPreference(preference: ListPreference) { 279 preference.setSummary(preference.getEntry()) 280 preference.setOnPreferenceChangeListener(this) 281 } 282 updateAutoSnoozeSummarynull283 private fun updateAutoSnoozeSummary(listPref: ListPreference, delay: String) { 284 val i = delay.toInt() 285 if (i == -1) { 286 listPref.setSummary(R.string.auto_silence_never) 287 } else { 288 listPref.setSummary(Utils.getNumberFormattedQuantityString(getActivity()!!, 289 R.plurals.auto_silence_summary, i)) 290 } 291 } 292 } 293 294 companion object { 295 const val KEY_ALARM_SNOOZE = "snooze_duration" 296 const val KEY_ALARM_CRESCENDO = "alarm_crescendo_duration" 297 const val KEY_TIMER_CRESCENDO = "timer_crescendo_duration" 298 const val KEY_TIMER_RINGTONE = "timer_ringtone" 299 const val KEY_TIMER_VIBRATE = "timer_vibrate" 300 const val KEY_AUTO_SILENCE = "auto_silence" 301 const val KEY_CLOCK_STYLE = "clock_style" 302 const val KEY_CLOCK_DISPLAY_SECONDS = "display_clock_seconds" 303 const val KEY_HOME_TZ = "home_time_zone" 304 const val KEY_AUTO_HOME_CLOCK = "automatic_home_clock" 305 const val KEY_DATE_TIME = "date_time" 306 const val KEY_VOLUME_BUTTONS = "volume_button_setting" 307 const val KEY_WEEK_START = "week_start" 308 const val DEFAULT_VOLUME_BEHAVIOR = "0" 309 const val VOLUME_BEHAVIOR_SNOOZE = "1" 310 const val VOLUME_BEHAVIOR_DISMISS = "2" 311 const val PREFS_FRAGMENT_TAG = "prefs_fragment" 312 const val PREFERENCE_DIALOG_FRAGMENT_TAG = "preference_dialog" 313 } 314 }