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 }