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