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