1 /*
2  * Copyright (C) 2009 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.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.res.Resources;
23 import android.media.AudioManager;
24 import android.os.Bundle;
25 import android.preference.ListPreference;
26 import android.preference.Preference;
27 import android.preference.PreferenceFragment;
28 import android.preference.RingtonePreference;
29 import android.preference.SwitchPreference;
30 import android.provider.Settings;
31 import android.text.format.DateUtils;
32 import android.view.Menu;
33 import android.view.MenuItem;
34 
35 import com.android.deskclock.BaseActivity;
36 import com.android.deskclock.LogUtils;
37 import com.android.deskclock.R;
38 import com.android.deskclock.Utils;
39 import com.android.deskclock.actionbarmenu.ActionBarMenuManager;
40 import com.android.deskclock.actionbarmenu.MenuItemControllerFactory;
41 import com.android.deskclock.actionbarmenu.NavUpMenuItemController;
42 import com.android.deskclock.data.DataModel;
43 
44 import java.util.ArrayList;
45 import java.util.Collections;
46 import java.util.List;
47 import java.util.Locale;
48 import java.util.TimeZone;
49 
50 /**
51  * Settings for the Alarm Clock.
52  */
53 public final class SettingsActivity extends BaseActivity {
54 
55     public static final String KEY_ALARM_SNOOZE = "snooze_duration";
56     public static final String KEY_ALARM_VOLUME = "volume_setting";
57     public static final String KEY_ALARM_CRESCENDO = "alarm_crescendo_duration";
58     public static final String KEY_TIMER_CRESCENDO = "timer_crescendo_duration";
59     public static final String KEY_TIMER_RINGTONE = "timer_ringtone";
60     public static final String KEY_AUTO_SILENCE = "auto_silence";
61     public static final String KEY_CLOCK_STYLE = "clock_style";
62     public static final String KEY_HOME_TZ = "home_time_zone";
63     public static final String KEY_AUTO_HOME_CLOCK = "automatic_home_clock";
64     public static final String KEY_DATE_TIME = "date_time";
65     public static final String KEY_VOLUME_BUTTONS = "volume_button_setting";
66     public static final String KEY_WEEK_START = "week_start";
67 
68     public static final String TIMEZONE_LOCALE = "tz_locale";
69 
70     public static final String DEFAULT_VOLUME_BEHAVIOR = "0";
71     public static final String VOLUME_BEHAVIOR_SNOOZE = "1";
72     public static final String VOLUME_BEHAVIOR_DISMISS = "2";
73 
74     private final ActionBarMenuManager mActionBarMenuManager = new ActionBarMenuManager(this);
75 
76     @Override
onCreate(Bundle savedInstanceState)77     protected void onCreate(Bundle savedInstanceState) {
78         super.onCreate(savedInstanceState);
79         setVolumeControlStream(AudioManager.STREAM_ALARM);
80         setContentView(R.layout.settings);
81         mActionBarMenuManager.addMenuItemController(new NavUpMenuItemController(this))
82             .addMenuItemController(MenuItemControllerFactory.getInstance()
83                     .buildMenuItemControllers(this));
84     }
85 
86     @Override
onCreateOptionsMenu(Menu menu)87     public boolean onCreateOptionsMenu(Menu menu) {
88         mActionBarMenuManager.createOptionsMenu(menu, getMenuInflater());
89         return true;
90     }
91 
92     @Override
onPrepareOptionsMenu(Menu menu)93     public boolean onPrepareOptionsMenu(Menu menu) {
94         mActionBarMenuManager.prepareShowMenu(menu);
95         return true;
96     }
97 
98     @Override
onOptionsItemSelected(MenuItem item)99     public boolean onOptionsItemSelected(MenuItem item) {
100         if (mActionBarMenuManager.handleMenuItemClick(item)) {
101             return true;
102         }
103         return super.onOptionsItemSelected(item);
104     }
105 
106     public static class PrefsFragment extends PreferenceFragment
107             implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
108         @Override
onCreate(Bundle savedInstanceState)109         public void onCreate(Bundle savedInstanceState) {
110             super.onCreate(savedInstanceState);
111 
112             addPreferencesFromResource(R.xml.settings);
113             loadTimeZoneList();
114         }
115 
116         @Override
onActivityCreated(Bundle savedInstanceState)117         public void onActivityCreated(Bundle savedInstanceState) {
118             super.onActivityCreated(savedInstanceState);
119 
120             // By default, do not recreate the DeskClock activity
121             getActivity().setResult(RESULT_CANCELED);
122 
123         }
124 
125         @Override
onResume()126         public void onResume() {
127             super.onResume();
128 
129             refresh();
130         }
131 
132         @Override
onPreferenceChange(Preference pref, Object newValue)133         public boolean onPreferenceChange(Preference pref, Object newValue) {
134             final int idx;
135             switch (pref.getKey()) {
136                 case KEY_AUTO_SILENCE:
137                     final ListPreference autoSilencePref = (ListPreference) pref;
138                     String delay = (String) newValue;
139                     updateAutoSnoozeSummary(autoSilencePref, delay);
140                     break;
141                 case KEY_CLOCK_STYLE:
142                     final ListPreference clockStylePref = (ListPreference) pref;
143                     idx = clockStylePref.findIndexOfValue((String) newValue);
144                     clockStylePref.setSummary(clockStylePref.getEntries()[idx]);
145                     break;
146                 case KEY_HOME_TZ:
147                     final ListPreference homeTimezonePref = (ListPreference) pref;
148                     idx = homeTimezonePref.findIndexOfValue((String) newValue);
149                     homeTimezonePref.setSummary(homeTimezonePref.getEntries()[idx]);
150                     break;
151                 case KEY_AUTO_HOME_CLOCK:
152                     final boolean autoHomeClockEnabled = ((SwitchPreference) pref).isChecked();
153                     final Preference homeTimeZonePref = findPreference(KEY_HOME_TZ);
154                     homeTimeZonePref.setEnabled(!autoHomeClockEnabled);
155                     break;
156                 case KEY_VOLUME_BUTTONS:
157                     final ListPreference volumeButtonsPref = (ListPreference) pref;
158                     final int index = volumeButtonsPref.findIndexOfValue((String) newValue);
159                     volumeButtonsPref.setSummary(volumeButtonsPref.getEntries()[index]);
160                     break;
161                 case KEY_WEEK_START:
162                     final ListPreference weekStartPref = (ListPreference)
163                             findPreference(KEY_WEEK_START);
164                     idx = weekStartPref.findIndexOfValue((String) newValue);
165                     weekStartPref.setSummary(weekStartPref.getEntries()[idx]);
166                     break;
167                 case KEY_TIMER_RINGTONE:
168                     final RingtonePreference timerRingtonePref = (RingtonePreference)
169                             findPreference(KEY_TIMER_RINGTONE);
170                     timerRingtonePref.setSummary(DataModel.getDataModel().getTimerRingtoneTitle());
171                     break;
172             }
173             // Set result so DeskClock knows to refresh itself
174             getActivity().setResult(RESULT_OK);
175             return true;
176         }
177 
178         @Override
onPreferenceClick(Preference pref)179         public boolean onPreferenceClick(Preference pref) {
180             final Activity activity = getActivity();
181             if (activity == null) {
182                 return false;
183             }
184 
185             switch (pref.getKey()) {
186                 case KEY_DATE_TIME:
187                     final Intent dialogIntent = new Intent(Settings.ACTION_DATE_SETTINGS);
188                     dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
189                     startActivity(dialogIntent);
190                     return true;
191                 case KEY_ALARM_VOLUME:
192                     final AudioManager audioManager =
193                             (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
194                     audioManager.adjustStreamVolume(AudioManager.STREAM_ALARM,
195                             AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI);
196                     return true;
197                 default:
198                     return false;
199             }
200         }
201 
202         /**
203          * Reconstruct the timezone list.
204          */
loadTimeZoneList()205         private void loadTimeZoneList() {
206             final CharSequence[][] timezones = getAllTimezones();
207             final ListPreference homeTimezonePref = (ListPreference) findPreference(KEY_HOME_TZ);
208             homeTimezonePref.setEntryValues(timezones[0]);
209             homeTimezonePref.setEntries(timezones[1]);
210             homeTimezonePref.setSummary(homeTimezonePref.getEntry());
211             homeTimezonePref.setOnPreferenceChangeListener(this);
212         }
213 
214         /**
215          * Returns an array of ids/time zones. This returns a double indexed array
216          * of ids and time zones for Calendar. It is an inefficient method and
217          * shouldn't be called often, but can be used for one time generation of
218          * this list.
219          *
220          * @return double array of tz ids and tz names
221          */
getAllTimezones()222         public CharSequence[][] getAllTimezones() {
223             final Resources res = getResources();
224             final String[] ids = res.getStringArray(R.array.timezone_values);
225             final String[] labels = res.getStringArray(R.array.timezone_labels);
226 
227             int minLength = ids.length;
228             if (ids.length != labels.length) {
229                 minLength = Math.min(minLength, labels.length);
230                 LogUtils.e("Timezone ids and labels have different length!");
231             }
232 
233             final long currentTimeMillis = System.currentTimeMillis();
234             final List<TimeZoneRow> timezones = new ArrayList<>(minLength);
235             for (int i = 0; i < minLength; i++) {
236                 timezones.add(new TimeZoneRow(ids[i], labels[i], currentTimeMillis));
237             }
238             Collections.sort(timezones);
239 
240             final CharSequence[][] timeZones = new CharSequence[2][timezones.size()];
241             int i = 0;
242             for (TimeZoneRow row : timezones) {
243                 timeZones[0][i] = row.mId;
244                 timeZones[1][i++] = row.mDisplayName;
245             }
246             return timeZones;
247         }
248 
refresh()249         private void refresh() {
250             final ListPreference autoSilencePref =
251                     (ListPreference) findPreference(KEY_AUTO_SILENCE);
252             String delay = autoSilencePref.getValue();
253             updateAutoSnoozeSummary(autoSilencePref, delay);
254             autoSilencePref.setOnPreferenceChangeListener(this);
255 
256             final ListPreference clockStylePref = (ListPreference) findPreference(KEY_CLOCK_STYLE);
257             clockStylePref.setSummary(clockStylePref.getEntry());
258             clockStylePref.setOnPreferenceChangeListener(this);
259 
260             final Preference autoHomeClockPref = findPreference(KEY_AUTO_HOME_CLOCK);
261             final boolean autoHomeClockEnabled = ((SwitchPreference) autoHomeClockPref).isChecked();
262             autoHomeClockPref.setOnPreferenceChangeListener(this);
263 
264             final ListPreference homeTimezonePref = (ListPreference) findPreference(KEY_HOME_TZ);
265             homeTimezonePref.setEnabled(autoHomeClockEnabled);
266             homeTimezonePref.setSummary(homeTimezonePref.getEntry());
267             homeTimezonePref.setOnPreferenceChangeListener(this);
268 
269             final ListPreference volumeButtonsPref =
270                     (ListPreference) findPreference(KEY_VOLUME_BUTTONS);
271             volumeButtonsPref.setSummary(volumeButtonsPref.getEntry());
272             volumeButtonsPref.setOnPreferenceChangeListener(this);
273 
274             final Preference volumePref = findPreference(KEY_ALARM_VOLUME);
275             volumePref.setOnPreferenceClickListener(this);
276 
277             final SnoozeLengthDialog snoozePref =
278                     (SnoozeLengthDialog) findPreference(KEY_ALARM_SNOOZE);
279             snoozePref.setSummary();
280 
281             final CrescendoLengthDialog alarmCrescendoPref =
282                     (CrescendoLengthDialog) findPreference(KEY_ALARM_CRESCENDO);
283             alarmCrescendoPref.setSummary();
284 
285             final CrescendoLengthDialog timerCrescendoPref =
286                     (CrescendoLengthDialog) findPreference(KEY_TIMER_CRESCENDO);
287             timerCrescendoPref.setSummary();
288 
289             final Preference dateAndTimeSetting = findPreference(KEY_DATE_TIME);
290             dateAndTimeSetting.setOnPreferenceClickListener(this);
291 
292             final ListPreference weekStartPref = (ListPreference) findPreference(KEY_WEEK_START);
293             // Set the default value programmatically
294             final String value = weekStartPref.getValue();
295             final int idx = weekStartPref.findIndexOfValue(
296                     value == null ? String.valueOf(Utils.DEFAULT_WEEK_START) : value);
297             weekStartPref.setValueIndex(idx);
298             weekStartPref.setSummary(weekStartPref.getEntries()[idx]);
299             weekStartPref.setOnPreferenceChangeListener(this);
300 
301             final RingtonePreference timerRingtonePref =
302                     (RingtonePreference) findPreference(KEY_TIMER_RINGTONE);
303             timerRingtonePref.setSummary(DataModel.getDataModel().getTimerRingtoneTitle());
304             timerRingtonePref.setOnPreferenceChangeListener(this);
305         }
306 
updateAutoSnoozeSummary(ListPreference listPref, String delay)307         private void updateAutoSnoozeSummary(ListPreference listPref, String delay) {
308             int i = Integer.parseInt(delay);
309             if (i == -1) {
310                 listPref.setSummary(R.string.auto_silence_never);
311             } else {
312                 listPref.setSummary(Utils.getNumberFormattedQuantityString(getActivity(),
313                         R.plurals.auto_silence_summary, i));
314             }
315         }
316 
317         private static class TimeZoneRow implements Comparable<TimeZoneRow> {
318 
319             private static final boolean SHOW_DAYLIGHT_SAVINGS_INDICATOR = false;
320 
321             public final String mId;
322             public final String mDisplayName;
323             public final int mOffset;
324 
TimeZoneRow(String id, String name, long currentTimeMillis)325             public TimeZoneRow(String id, String name, long currentTimeMillis) {
326                 final TimeZone tz = TimeZone.getTimeZone(id);
327                 final boolean useDaylightTime = tz.useDaylightTime();
328                 mId = id;
329                 mOffset = tz.getOffset(currentTimeMillis);
330                 mDisplayName = buildGmtDisplayName(name, useDaylightTime);
331             }
332 
333             @Override
compareTo(TimeZoneRow another)334             public int compareTo(TimeZoneRow another) {
335                 return mOffset - another.mOffset;
336             }
337 
buildGmtDisplayName(String displayName, boolean useDaylightTime)338             public String buildGmtDisplayName(String displayName, boolean useDaylightTime) {
339                 final int p = Math.abs(mOffset);
340                 final StringBuilder name = new StringBuilder("(GMT");
341                 name.append(mOffset < 0 ? '-' : '+');
342 
343                 name.append(p / DateUtils.HOUR_IN_MILLIS);
344                 name.append(':');
345 
346                 int min = p / 60000;
347                 min %= 60;
348 
349                 if (min < 10) {
350                     name.append('0');
351                 }
352                 name.append(min);
353                 name.append(") ");
354                 name.append(displayName);
355                 if (useDaylightTime && SHOW_DAYLIGHT_SAVINGS_INDICATOR) {
356                     name.append(" \u2600"); // Sun symbol
357                 }
358                 return name.toString();
359             }
360         }
361     }
362 }
363