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
17package com.android.deskclock;
18
19import android.app.ActionBar;
20import android.content.Intent;
21import android.content.res.Resources;
22import android.media.AudioManager;
23import android.os.Bundle;
24import android.preference.CheckBoxPreference;
25import android.preference.ListPreference;
26import android.preference.Preference;
27import android.preference.PreferenceActivity;
28import android.preference.PreferenceScreen;
29import android.provider.Settings;
30import android.text.format.DateUtils;
31import android.view.Menu;
32import android.view.MenuItem;
33
34import com.android.deskclock.worldclock.Cities;
35
36import java.util.ArrayList;
37import java.util.Collections;
38import java.util.List;
39import java.util.TimeZone;
40
41/**
42 * Settings for the Alarm Clock.
43 */
44public class SettingsActivity extends PreferenceActivity
45        implements Preference.OnPreferenceChangeListener {
46
47    private static final int ALARM_STREAM_TYPE_BIT =
48            1 << AudioManager.STREAM_ALARM;
49
50    static final String KEY_ALARM_IN_SILENT_MODE =
51            "alarm_in_silent_mode";
52    static final String KEY_ALARM_SNOOZE =
53            "snooze_duration";
54    static final String KEY_VOLUME_BEHAVIOR =
55            "volume_button_setting";
56    static final String KEY_AUTO_SILENCE =
57            "auto_silence";
58    public static final String KEY_CLOCK_STYLE =
59            "clock_style";
60    public static final String KEY_HOME_TZ =
61            "home_time_zone";
62    public static final String KEY_AUTO_HOME_CLOCK =
63            "automatic_home_clock";
64    static final String KEY_VOLUME_BUTTONS =
65            "volume_button_setting";
66
67    public static final String DEFAULT_VOLUME_BEHAVIOR = "0";
68
69    private static CharSequence[][] mTimezones;
70    private long mTime;
71
72
73    @Override
74    protected void onCreate(Bundle savedInstanceState) {
75        super.onCreate(savedInstanceState);
76        addPreferencesFromResource(R.xml.settings);
77
78        ActionBar actionBar = getActionBar();
79        if (actionBar != null) {
80            actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
81        }
82
83        // We don't want to reconstruct the timezone list every single time
84        // onResume() is called so we do it once in onCreate
85        ListPreference listPref;
86        listPref = (ListPreference) findPreference(KEY_HOME_TZ);
87        if (mTimezones == null) {
88            mTime = System.currentTimeMillis();
89            mTimezones = getAllTimezones();
90        }
91
92        listPref.setEntryValues(mTimezones[0]);
93        listPref.setEntries(mTimezones[1]);
94        listPref.setSummary(listPref.getEntry());
95        listPref.setOnPreferenceChangeListener(this);
96    }
97
98    @Override
99    protected void onResume() {
100        super.onResume();
101        refresh();
102    }
103
104    @Override
105    public boolean onOptionsItemSelected (MenuItem item) {
106        switch (item.getItemId()) {
107            case android.R.id.home:
108                finish();
109                return true;
110            default:
111                break;
112        }
113        return super.onOptionsItemSelected(item);
114    }
115
116
117    @Override
118    public boolean onCreateOptionsMenu (Menu menu) {
119        getMenuInflater().inflate(R.menu.settings_menu, menu);
120        MenuItem help = menu.findItem(R.id.menu_item_help);
121        if (help != null) {
122            Utils.prepareHelpMenuItem(this, help);
123        }
124        return super.onCreateOptionsMenu(menu);
125    }
126
127    @Override
128    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
129            Preference preference) {
130        if (KEY_ALARM_IN_SILENT_MODE.equals(preference.getKey())) {
131            CheckBoxPreference pref = (CheckBoxPreference) preference;
132            int ringerModeStreamTypes = Settings.System.getInt(
133                    getContentResolver(),
134                    Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
135
136            if (pref.isChecked()) {
137                ringerModeStreamTypes &= ~ALARM_STREAM_TYPE_BIT;
138            } else {
139                ringerModeStreamTypes |= ALARM_STREAM_TYPE_BIT;
140            }
141
142            Settings.System.putInt(getContentResolver(),
143                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
144                    ringerModeStreamTypes);
145
146            return true;
147        }
148
149        return super.onPreferenceTreeClick(preferenceScreen, preference);
150    }
151
152    @Override
153    public boolean onPreferenceChange(Preference pref, Object newValue) {
154        if (KEY_AUTO_SILENCE.equals(pref.getKey())) {
155            final ListPreference listPref = (ListPreference) pref;
156            String delay = (String) newValue;
157            updateAutoSnoozeSummary(listPref, delay);
158        } else if (KEY_CLOCK_STYLE.equals(pref.getKey())) {
159            final ListPreference listPref = (ListPreference) pref;
160            final int idx = listPref.findIndexOfValue((String) newValue);
161            listPref.setSummary(listPref.getEntries()[idx]);
162        } else if (KEY_HOME_TZ.equals(pref.getKey())) {
163            final ListPreference listPref = (ListPreference) pref;
164            final int idx = listPref.findIndexOfValue((String) newValue);
165            listPref.setSummary(listPref.getEntries()[idx]);
166            notifyHomeTimeZoneChanged();
167        } else if (KEY_AUTO_HOME_CLOCK.equals(pref.getKey())) {
168            boolean state =((CheckBoxPreference) pref).isChecked();
169            Preference homeTimeZone = findPreference(KEY_HOME_TZ);
170            homeTimeZone.setEnabled(!state);
171            notifyHomeTimeZoneChanged();
172        } else if (KEY_VOLUME_BUTTONS.equals(pref.getKey())) {
173            final ListPreference listPref = (ListPreference) pref;
174            final int idx = listPref.findIndexOfValue((String) newValue);
175            listPref.setSummary(listPref.getEntries()[idx]);
176        }
177        return true;
178    }
179
180    private void updateAutoSnoozeSummary(ListPreference listPref,
181            String delay) {
182        int i = Integer.parseInt(delay);
183        if (i == -1) {
184            listPref.setSummary(R.string.auto_silence_never);
185        } else {
186            listPref.setSummary(getString(R.string.auto_silence_summary, i));
187        }
188    }
189
190    private void notifyHomeTimeZoneChanged() {
191        Intent i = new Intent(Cities.WORLDCLOCK_UPDATE_INTENT);
192        sendBroadcast(i);
193    }
194
195
196    private void refresh() {
197        ListPreference listPref = (ListPreference) findPreference(KEY_AUTO_SILENCE);
198        String delay = listPref.getValue();
199        updateAutoSnoozeSummary(listPref, delay);
200        listPref.setOnPreferenceChangeListener(this);
201
202        listPref = (ListPreference) findPreference(KEY_CLOCK_STYLE);
203        listPref.setSummary(listPref.getEntry());
204        listPref.setOnPreferenceChangeListener(this);
205
206        Preference pref = findPreference(KEY_AUTO_HOME_CLOCK);
207        boolean state =((CheckBoxPreference) pref).isChecked();
208        pref.setOnPreferenceChangeListener(this);
209
210        listPref = (ListPreference)findPreference(KEY_HOME_TZ);
211        listPref.setEnabled(state);
212        listPref.setSummary(listPref.getEntry());
213
214        listPref = (ListPreference) findPreference(KEY_VOLUME_BUTTONS);
215        listPref.setSummary(listPref.getEntry());
216        listPref.setOnPreferenceChangeListener(this);
217
218        SnoozeLengthDialog snoozePref = (SnoozeLengthDialog) findPreference(KEY_ALARM_SNOOZE);
219        snoozePref.setSummary();
220    }
221
222    private class TimeZoneRow implements Comparable<TimeZoneRow> {
223        private static final boolean SHOW_DAYLIGHT_SAVINGS_INDICATOR = false;
224
225        public final String mId;
226        public final String mDisplayName;
227        public final int mOffset;
228
229        public TimeZoneRow(String id, String name) {
230            mId = id;
231            TimeZone tz = TimeZone.getTimeZone(id);
232            boolean useDaylightTime = tz.useDaylightTime();
233            mOffset = tz.getOffset(mTime);
234            mDisplayName = buildGmtDisplayName(id, name, useDaylightTime);
235        }
236
237        @Override
238        public int compareTo(TimeZoneRow another) {
239            return mOffset - another.mOffset;
240        }
241
242        public String buildGmtDisplayName(String id, String displayName, boolean useDaylightTime) {
243            int p = Math.abs(mOffset);
244            StringBuilder name = new StringBuilder("(GMT");
245            name.append(mOffset < 0 ? '-' : '+');
246
247            name.append(p / DateUtils.HOUR_IN_MILLIS);
248            name.append(':');
249
250            int min = p / 60000;
251            min %= 60;
252
253            if (min < 10) {
254                name.append('0');
255            }
256            name.append(min);
257            name.append(") ");
258            name.append(displayName);
259            if (useDaylightTime && SHOW_DAYLIGHT_SAVINGS_INDICATOR) {
260                name.append(" \u2600"); // Sun symbol
261            }
262            return name.toString();
263        }
264    }
265
266
267    /**
268     * Returns an array of ids/time zones. This returns a double indexed array
269     * of ids and time zones for Calendar. It is an inefficient method and
270     * shouldn't be called often, but can be used for one time generation of
271     * this list.
272     *
273     * @return double array of tz ids and tz names
274     */
275    public CharSequence[][] getAllTimezones() {
276        Resources resources = this.getResources();
277        String[] ids = resources.getStringArray(R.array.timezone_values);
278        String[] labels = resources.getStringArray(R.array.timezone_labels);
279        if (ids.length != labels.length) {
280            Log.wtf("Timezone ids and labels have different length!");
281        }
282        List<TimeZoneRow> timezones = new ArrayList<TimeZoneRow>();
283        for (int i = 0; i < ids.length; i++) {
284            timezones.add(new TimeZoneRow(ids[i], labels[i]));
285        }
286        Collections.sort(timezones);
287
288        CharSequence[][] timeZones = new CharSequence[2][timezones.size()];
289        int i = 0;
290        for (TimeZoneRow row : timezones) {
291            timeZones[0][i] = row.mId;
292            timeZones[1][i++] = row.mDisplayName;
293        }
294        return timeZones;
295    }
296
297}
298