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