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