SettingsActivity.java revision e84dc3edceb9cc5e272816ed53cc31ad59eb16dc
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_CRESCENDO = "alarm_crescendo_duration"; 61 public static final String KEY_TIMER_CRESCENDO = "timer_crescendo_duration"; 62 public static final String KEY_TIMER_RINGTONE = "timer_ringtone"; 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 TIMEZONE_LOCALE = "tz_locale"; 72 73 public static final String DEFAULT_VOLUME_BEHAVIOR = "0"; 74 public static final String VOLUME_BEHAVIOR_SNOOZE = "1"; 75 public static final String VOLUME_BEHAVIOR_DISMISS = "2"; 76 77 public static final String PREFS_FRAGMENT_TAG = "prefs_fragment"; 78 public static final String PREFERENCE_DIALOG_FRAGMENT_TAG = "preference_dialog"; 79 80 private final ActionBarMenuManager mActionBarMenuManager = new ActionBarMenuManager(this); 81 82 @Override 83 protected void onCreate(Bundle savedInstanceState) { 84 super.onCreate(savedInstanceState); 85 setVolumeControlStream(AudioManager.STREAM_ALARM); 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 public boolean onCreateOptionsMenu(Menu menu) { 102 mActionBarMenuManager.createOptionsMenu(menu, getMenuInflater()); 103 return true; 104 } 105 106 @Override 107 public boolean onPrepareOptionsMenu(Menu menu) { 108 mActionBarMenuManager.prepareShowMenu(menu); 109 return true; 110 } 111 112 @Override 113 public boolean onOptionsItemSelected(MenuItem item) { 114 if (mActionBarMenuManager.handleMenuItemClick(item)) { 115 return true; 116 } 117 return super.onOptionsItemSelected(item); 118 } 119 120 /** 121 * Called by the RingtonePickerDialogFragment class after the dialog is finished. 122 */ 123 @Override 124 public void onRingtoneSelected(Uri ringtoneUri, String fragmentTag) { 125 final PrefsFragment fragment = 126 (PrefsFragment) getFragmentManager().findFragmentById(R.id.main); 127 final Preference preference = fragment.findPreference(KEY_TIMER_RINGTONE); 128 DataModel.getDataModel().setTimerRingtoneUri(ringtoneUri); 129 preference.setSummary(DataModel.getDataModel().getTimerRingtoneTitle()); 130 } 131 132 public static class PrefsFragment extends PreferenceFragment 133 implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener { 134 135 private static CharSequence[][] mTimezones; 136 private long mTime; 137 138 @Override 139 public void onCreatePreferences(Bundle bundle, String s) { 140 addPreferencesFromResource(R.xml.settings); 141 } 142 143 @Override 144 public void onResume() { 145 super.onResume(); 146 loadTimeZoneList(); 147 // By default, do not recreate the DeskClock activity 148 getActivity().setResult(RESULT_CANCELED); 149 refresh(); 150 } 151 152 @Override 153 public void onDisplayPreferenceDialog(Preference preference) { 154 final String key = preference.getKey(); 155 switch (key) { 156 case KEY_ALARM_SNOOZE: 157 showDialog(SnoozeLengthDialogFragment.newInstance(preference)); 158 break; 159 case KEY_ALARM_CRESCENDO: 160 case KEY_TIMER_CRESCENDO: 161 showDialog(CrescendoLengthDialogFragment.newInstance(preference)); 162 break; 163 default: 164 super.onDisplayPreferenceDialog(preference); 165 } 166 } 167 168 @Override 169 public boolean onPreferenceChange(Preference pref, Object newValue) { 170 final int idx; 171 switch (pref.getKey()) { 172 case KEY_AUTO_SILENCE: 173 final ListPreference autoSilencePref = (ListPreference) pref; 174 String delay = (String) newValue; 175 updateAutoSnoozeSummary(autoSilencePref, delay); 176 break; 177 case KEY_CLOCK_STYLE: 178 final ListPreference clockStylePref = (ListPreference) pref; 179 idx = clockStylePref.findIndexOfValue((String) newValue); 180 clockStylePref.setSummary(clockStylePref.getEntries()[idx]); 181 break; 182 case KEY_HOME_TZ: 183 final ListPreference homeTimezonePref = (ListPreference) pref; 184 idx = homeTimezonePref.findIndexOfValue((String) newValue); 185 homeTimezonePref.setSummary(homeTimezonePref.getEntries()[idx]); 186 break; 187 case KEY_AUTO_HOME_CLOCK: 188 final boolean autoHomeClockEnabled = ((SwitchPreference) pref).isChecked(); 189 final Preference homeTimeZonePref = findPreference(KEY_HOME_TZ); 190 homeTimeZonePref.setEnabled(!autoHomeClockEnabled); 191 break; 192 case KEY_VOLUME_BUTTONS: 193 final ListPreference volumeButtonsPref = (ListPreference) pref; 194 final int index = volumeButtonsPref.findIndexOfValue((String) newValue); 195 volumeButtonsPref.setSummary(volumeButtonsPref.getEntries()[index]); 196 break; 197 case KEY_WEEK_START: 198 final ListPreference weekStartPref = (ListPreference) 199 findPreference(KEY_WEEK_START); 200 idx = weekStartPref.findIndexOfValue((String) newValue); 201 weekStartPref.setSummary(weekStartPref.getEntries()[idx]); 202 break; 203 } 204 // Set result so DeskClock knows to refresh itself 205 getActivity().setResult(RESULT_OK); 206 return true; 207 } 208 209 @Override 210 public boolean onPreferenceClick(Preference pref) { 211 final Activity activity = getActivity(); 212 if (activity == null) { 213 return false; 214 } 215 216 switch (pref.getKey()) { 217 case KEY_DATE_TIME: 218 Intent dialogIntent = new Intent(Settings.ACTION_DATE_SETTINGS); 219 dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 220 startActivity(dialogIntent); 221 return true; 222 case KEY_TIMER_RINGTONE: 223 final String dialogTitle = getString(R.string.timer_ringtone_title); 224 final String defaultTitle = getString(R.string.default_timer_ringtone_title); 225 final Uri currentUri = DataModel.getDataModel().getTimerRingtoneUri(); 226 final Uri defaultUri = DataModel.getDataModel().getDefaultTimerRingtoneUri(); 227 final DialogFragment newFragment = RingtonePickerDialogFragment 228 .newInstance(dialogTitle, defaultTitle, defaultUri, currentUri, null); 229 showDialog(newFragment); 230 default: 231 return false; 232 } 233 } 234 235 /** 236 * Reconstruct the timezone list. We don't want to do this unnecessary, so proceed only if 237 * this is the initial load or the locale has changed since the last load. 238 */ 239 private void loadTimeZoneList() { 240 final Locale currentLocale = getResources().getConfiguration().locale; 241 final Context context = getActivity(); 242 if (mTimezones == null || Utils.getTimezoneLocale(context) != currentLocale) { 243 mTime = System.currentTimeMillis(); 244 mTimezones = getAllTimezones(); 245 Utils.setTimezoneLocale(context, currentLocale); 246 } 247 final ListPreference homeTimezonePref = (ListPreference) findPreference(KEY_HOME_TZ); 248 homeTimezonePref.setEntryValues(mTimezones[0]); 249 homeTimezonePref.setEntries(mTimezones[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 Resources resources = this.getResources(); 264 String[] ids = resources.getStringArray(R.array.timezone_values); 265 String[] labels = resources.getStringArray(R.array.timezone_labels); 266 int minLength = ids.length; 267 if (ids.length != labels.length) { 268 minLength = Math.min(minLength, labels.length); 269 LogUtils.e("Timezone ids and labels have different length!"); 270 } 271 List<TimeZoneRow> timezones = new ArrayList<>(); 272 for (int i = 0; i < minLength; i++) { 273 timezones.add(new TimeZoneRow(ids[i], labels[i])); 274 } 275 Collections.sort(timezones); 276 277 CharSequence[][] timeZones = new CharSequence[2][timezones.size()]; 278 int i = 0; 279 for (TimeZoneRow row : timezones) { 280 timeZones[0][i] = row.mId; 281 timeZones[1][i++] = row.mDisplayName; 282 } 283 return timeZones; 284 } 285 286 private void refresh() { 287 final ListPreference autoSilencePref = 288 (ListPreference) findPreference(KEY_AUTO_SILENCE); 289 String delay = autoSilencePref.getValue(); 290 updateAutoSnoozeSummary(autoSilencePref, delay); 291 autoSilencePref.setOnPreferenceChangeListener(this); 292 293 final ListPreference clockStylePref = (ListPreference) findPreference(KEY_CLOCK_STYLE); 294 clockStylePref.setSummary(clockStylePref.getEntry()); 295 clockStylePref.setOnPreferenceChangeListener(this); 296 297 final Preference autoHomeClockPref = findPreference(KEY_AUTO_HOME_CLOCK); 298 final boolean autoHomeClockEnabled = ((SwitchPreference) autoHomeClockPref).isChecked(); 299 autoHomeClockPref.setOnPreferenceChangeListener(this); 300 301 final ListPreference homeTimezonePref = (ListPreference) findPreference(KEY_HOME_TZ); 302 homeTimezonePref.setEnabled(autoHomeClockEnabled); 303 homeTimezonePref.setSummary(homeTimezonePref.getEntry()); 304 homeTimezonePref.setOnPreferenceChangeListener(this); 305 306 final ListPreference volumeButtonsPref = 307 (ListPreference) findPreference(KEY_VOLUME_BUTTONS); 308 volumeButtonsPref.setSummary(volumeButtonsPref.getEntry()); 309 volumeButtonsPref.setOnPreferenceChangeListener(this); 310 311 ((SnoozeLengthDialogPreference) findPreference(KEY_ALARM_SNOOZE)).updateSummary(); 312 ((CrescendoLengthDialogPreference) findPreference(KEY_ALARM_CRESCENDO)).updateSummary(); 313 ((CrescendoLengthDialogPreference) findPreference(KEY_TIMER_CRESCENDO)).updateSummary(); 314 315 final Preference dateAndTimeSetting = findPreference(KEY_DATE_TIME); 316 dateAndTimeSetting.setOnPreferenceClickListener(this); 317 318 final ListPreference weekStartPref = (ListPreference) findPreference(KEY_WEEK_START); 319 // Set the default value programmatically 320 final String value = weekStartPref.getValue(); 321 final int idx = weekStartPref.findIndexOfValue( 322 value == null ? String.valueOf(Utils.DEFAULT_WEEK_START) : value); 323 weekStartPref.setValueIndex(idx); 324 weekStartPref.setSummary(weekStartPref.getEntries()[idx]); 325 weekStartPref.setOnPreferenceChangeListener(this); 326 327 final Preference timerRingtonePref = findPreference(KEY_TIMER_RINGTONE); 328 timerRingtonePref.setOnPreferenceClickListener(this); 329 timerRingtonePref.setSummary(DataModel.getDataModel().getTimerRingtoneTitle()); 330 } 331 332 private void updateAutoSnoozeSummary(ListPreference listPref, String delay) { 333 int i = Integer.parseInt(delay); 334 if (i == -1) { 335 listPref.setSummary(R.string.auto_silence_never); 336 } else { 337 listPref.setSummary(Utils.getNumberFormattedQuantityString(getActivity(), 338 R.plurals.auto_silence_summary, i)); 339 } 340 } 341 342 private void showDialog(DialogFragment fragment) { 343 fragment.setTargetFragment(this, 0); 344 fragment.show(getFragmentManager(), PREFERENCE_DIALOG_FRAGMENT_TAG); 345 } 346 347 private class TimeZoneRow implements Comparable<TimeZoneRow> { 348 private static final boolean SHOW_DAYLIGHT_SAVINGS_INDICATOR = false; 349 350 public final String mId; 351 public final String mDisplayName; 352 public final int mOffset; 353 354 public TimeZoneRow(String id, String name) { 355 mId = id; 356 TimeZone tz = TimeZone.getTimeZone(id); 357 boolean useDaylightTime = tz.useDaylightTime(); 358 mOffset = tz.getOffset(mTime); 359 mDisplayName = buildGmtDisplayName(name, useDaylightTime); 360 } 361 362 @Override 363 public int compareTo(TimeZoneRow another) { 364 return mOffset - another.mOffset; 365 } 366 367 public String buildGmtDisplayName(String displayName, boolean useDaylightTime) { 368 int p = Math.abs(mOffset); 369 StringBuilder name = new StringBuilder("(GMT"); 370 name.append(mOffset < 0 ? '-' : '+'); 371 372 name.append(p / DateUtils.HOUR_IN_MILLIS); 373 name.append(':'); 374 375 int min = p / 60000; 376 min %= 60; 377 378 if (min < 10) { 379 name.append('0'); 380 } 381 name.append(min); 382 name.append(") "); 383 name.append(displayName); 384 if (useDaylightTime && SHOW_DAYLIGHT_SAVINGS_INDICATOR) { 385 name.append(" \u2600"); // Sun symbol 386 } 387 return name.toString(); 388 } 389 } 390 } 391} 392