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