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