SettingsActivity.java revision 4e7ee09e878178873241846757b178535da3dd76
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.RingtoneSelectionListener { 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 /** 137 * Called by the RingtonePickerDialogFragment class after the dialog is finished. 138 */ 139 @Override 140 public void onRingtoneSelected(Uri ringtoneUri, String fragmentTag) { 141 final PrefsFragment fragment = 142 (PrefsFragment) getFragmentManager().findFragmentById(R.id.main); 143 final Preference preference = fragment.findPreference(KEY_TIMER_RINGTONE); 144 DataModel.getDataModel().setTimerRingtoneUri(ringtoneUri); 145 preference.setSummary(DataModel.getDataModel().getTimerRingtoneTitle()); 146 } 147 148 public static class PrefsFragment extends PreferenceFragment 149 implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener { 150 151 @Override 152 public void onCreatePreferences(Bundle bundle, String rootKey) { 153 addPreferencesFromResource(R.xml.settings); 154 loadTimeZoneList(); 155 } 156 157 @Override 158 public void onActivityCreated(Bundle savedInstanceState) { 159 super.onActivityCreated(savedInstanceState); 160 161 // By default, do not recreate the DeskClock activity 162 getActivity().setResult(RESULT_CANCELED); 163 } 164 165 @Override 166 public void onResume() { 167 super.onResume(); 168 169 refresh(); 170 } 171 172 @Override 173 public void onDisplayPreferenceDialog(Preference preference) { 174 final String key = preference.getKey(); 175 switch (key) { 176 case KEY_ALARM_SNOOZE: 177 showDialog(SnoozeLengthDialogFragment.newInstance(preference)); 178 break; 179 case KEY_ALARM_CRESCENDO: 180 case KEY_TIMER_CRESCENDO: 181 showDialog(CrescendoLengthDialogFragment.newInstance(preference)); 182 break; 183 default: 184 super.onDisplayPreferenceDialog(preference); 185 } 186 } 187 188 @Override 189 public boolean onPreferenceChange(Preference pref, Object newValue) { 190 final int idx; 191 switch (pref.getKey()) { 192 case KEY_AUTO_SILENCE: 193 final ListPreference autoSilencePref = (ListPreference) pref; 194 String delay = (String) newValue; 195 updateAutoSnoozeSummary(autoSilencePref, delay); 196 break; 197 case KEY_CLOCK_STYLE: 198 final ListPreference clockStylePref = (ListPreference) pref; 199 idx = clockStylePref.findIndexOfValue((String) newValue); 200 clockStylePref.setSummary(clockStylePref.getEntries()[idx]); 201 break; 202 case KEY_HOME_TZ: 203 final ListPreference homeTimezonePref = (ListPreference) pref; 204 idx = homeTimezonePref.findIndexOfValue((String) newValue); 205 homeTimezonePref.setSummary(homeTimezonePref.getEntries()[idx]); 206 break; 207 case KEY_AUTO_HOME_CLOCK: 208 final boolean autoHomeClockEnabled = ((SwitchPreference) pref).isChecked(); 209 final Preference homeTimeZonePref = findPreference(KEY_HOME_TZ); 210 homeTimeZonePref.setEnabled(!autoHomeClockEnabled); 211 break; 212 case KEY_VOLUME_BUTTONS: 213 final ListPreference volumeButtonsPref = (ListPreference) pref; 214 final int index = volumeButtonsPref.findIndexOfValue((String) newValue); 215 volumeButtonsPref.setSummary(volumeButtonsPref.getEntries()[index]); 216 break; 217 case KEY_WEEK_START: 218 final ListPreference weekStartPref = 219 (ListPreference) findPreference(KEY_WEEK_START); 220 idx = weekStartPref.findIndexOfValue((String) newValue); 221 weekStartPref.setSummary(weekStartPref.getEntries()[idx]); 222 break; 223 case KEY_TIMER_VIBRATE: 224 final SwitchPreference timerVibratePref = 225 (SwitchPreference) findPreference(KEY_TIMER_VIBRATE); 226 DataModel.getDataModel().setTimerVibrate(timerVibratePref.isChecked()); 227 break; 228 } 229 // Set result so DeskClock knows to refresh itself 230 getActivity().setResult(RESULT_OK); 231 return true; 232 } 233 234 @Override 235 public boolean onPreferenceClick(Preference pref) { 236 final Activity activity = getActivity(); 237 if (activity == null) { 238 return false; 239 } 240 241 switch (pref.getKey()) { 242 case KEY_DATE_TIME: 243 final Intent dialogIntent = new Intent(Settings.ACTION_DATE_SETTINGS); 244 dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 245 startActivity(dialogIntent); 246 return true; 247 case KEY_TIMER_RINGTONE: 248 final String dialogTitle = getString(R.string.timer_ringtone_title); 249 final String defaultTitle = getString(R.string.default_timer_ringtone_title); 250 final Uri currentUri = DataModel.getDataModel().getTimerRingtoneUri(); 251 final Uri defaultUri = DataModel.getDataModel().getDefaultTimerRingtoneUri(); 252 final DialogFragment newFragment = RingtonePickerDialogFragment 253 .newInstance(dialogTitle, defaultTitle, defaultUri, currentUri, null); 254 showDialog(newFragment); 255 default: 256 return false; 257 } 258 } 259 260 /** 261 * Reconstruct the timezone list. 262 */ 263 private void loadTimeZoneList() { 264 final CharSequence[][] timezones = getAllTimezones(); 265 final ListPreference homeTimezonePref = (ListPreference) findPreference(KEY_HOME_TZ); 266 homeTimezonePref.setEntryValues(timezones[0]); 267 homeTimezonePref.setEntries(timezones[1]); 268 homeTimezonePref.setSummary(homeTimezonePref.getEntry()); 269 homeTimezonePref.setOnPreferenceChangeListener(this); 270 } 271 272 /** 273 * Returns an array of ids/time zones. This returns a double indexed array 274 * of ids and time zones for Calendar. It is an inefficient method and 275 * shouldn't be called often, but can be used for one time generation of 276 * this list. 277 * 278 * @return double array of tz ids and tz names 279 */ 280 public CharSequence[][] getAllTimezones() { 281 final Resources res = getResources(); 282 final String[] ids = res.getStringArray(R.array.timezone_values); 283 final String[] labels = res.getStringArray(R.array.timezone_labels); 284 285 int minLength = ids.length; 286 if (ids.length != labels.length) { 287 minLength = Math.min(minLength, labels.length); 288 LogUtils.e("Timezone ids and labels have different length!"); 289 } 290 291 final long currentTimeMillis = System.currentTimeMillis(); 292 final List<TimeZoneRow> timezones = new ArrayList<>(minLength); 293 for (int i = 0; i < minLength; i++) { 294 timezones.add(new TimeZoneRow(ids[i], labels[i], currentTimeMillis)); 295 } 296 Collections.sort(timezones); 297 298 final CharSequence[][] timeZones = new CharSequence[2][timezones.size()]; 299 int i = 0; 300 for (TimeZoneRow row : timezones) { 301 timeZones[0][i] = row.mId; 302 timeZones[1][i++] = row.mDisplayName; 303 } 304 return timeZones; 305 } 306 307 private void refresh() { 308 final ListPreference autoSilencePref = 309 (ListPreference) findPreference(KEY_AUTO_SILENCE); 310 String delay = autoSilencePref.getValue(); 311 updateAutoSnoozeSummary(autoSilencePref, delay); 312 autoSilencePref.setOnPreferenceChangeListener(this); 313 314 final ListPreference clockStylePref = (ListPreference) findPreference(KEY_CLOCK_STYLE); 315 clockStylePref.setSummary(clockStylePref.getEntry()); 316 clockStylePref.setOnPreferenceChangeListener(this); 317 318 final Preference autoHomeClockPref = findPreference(KEY_AUTO_HOME_CLOCK); 319 final boolean autoHomeClockEnabled = ((SwitchPreference) autoHomeClockPref).isChecked(); 320 autoHomeClockPref.setOnPreferenceChangeListener(this); 321 322 final ListPreference homeTimezonePref = (ListPreference) findPreference(KEY_HOME_TZ); 323 homeTimezonePref.setEnabled(autoHomeClockEnabled); 324 homeTimezonePref.setSummary(homeTimezonePref.getEntry()); 325 homeTimezonePref.setOnPreferenceChangeListener(this); 326 327 final ListPreference volumeButtonsPref = 328 (ListPreference) findPreference(KEY_VOLUME_BUTTONS); 329 volumeButtonsPref.setSummary(volumeButtonsPref.getEntry()); 330 volumeButtonsPref.setOnPreferenceChangeListener(this); 331 332 ((SnoozeLengthDialogPreference) findPreference(KEY_ALARM_SNOOZE)).updateSummary(); 333 ((CrescendoLengthDialogPreference) findPreference(KEY_ALARM_CRESCENDO)).updateSummary(); 334 ((CrescendoLengthDialogPreference) findPreference(KEY_TIMER_CRESCENDO)).updateSummary(); 335 336 final Preference dateAndTimeSetting = findPreference(KEY_DATE_TIME); 337 dateAndTimeSetting.setOnPreferenceClickListener(this); 338 339 final ListPreference weekStartPref = (ListPreference) findPreference(KEY_WEEK_START); 340 // Set the default value programmatically 341 final String value = weekStartPref.getValue(); 342 final int idx = weekStartPref.findIndexOfValue( 343 value == null ? String.valueOf(Utils.DEFAULT_WEEK_START) : value); 344 weekStartPref.setValueIndex(idx); 345 weekStartPref.setSummary(weekStartPref.getEntries()[idx]); 346 weekStartPref.setOnPreferenceChangeListener(this); 347 348 final Preference timerRingtonePref = findPreference(KEY_TIMER_RINGTONE); 349 timerRingtonePref.setOnPreferenceClickListener(this); 350 timerRingtonePref.setSummary(DataModel.getDataModel().getTimerRingtoneTitle()); 351 } 352 353 private void updateAutoSnoozeSummary(ListPreference listPref, String delay) { 354 int i = Integer.parseInt(delay); 355 if (i == -1) { 356 listPref.setSummary(R.string.auto_silence_never); 357 } else { 358 listPref.setSummary(Utils.getNumberFormattedQuantityString(getActivity(), 359 R.plurals.auto_silence_summary, i)); 360 } 361 } 362 363 private void showDialog(DialogFragment fragment) { 364 fragment.setTargetFragment(this, 0); 365 fragment.show(getFragmentManager(), PREFERENCE_DIALOG_FRAGMENT_TAG); 366 } 367 368 private static class TimeZoneRow implements Comparable<TimeZoneRow> { 369 370 private static final boolean SHOW_DAYLIGHT_SAVINGS_INDICATOR = false; 371 372 public final String mId; 373 public final String mDisplayName; 374 public final int mOffset; 375 376 public TimeZoneRow(String id, String name, long currentTimeMillis) { 377 final TimeZone tz = TimeZone.getTimeZone(id); 378 final boolean useDaylightTime = tz.useDaylightTime(); 379 mId = id; 380 mOffset = tz.getOffset(currentTimeMillis); 381 mDisplayName = buildGmtDisplayName(name, useDaylightTime); 382 } 383 384 @Override 385 public int compareTo(TimeZoneRow another) { 386 return mOffset - another.mOffset; 387 } 388 389 public String buildGmtDisplayName(String displayName, boolean useDaylightTime) { 390 final int p = Math.abs(mOffset); 391 final StringBuilder name = new StringBuilder("(GMT"); 392 name.append(mOffset < 0 ? '-' : '+'); 393 394 name.append(p / DateUtils.HOUR_IN_MILLIS); 395 name.append(':'); 396 397 int min = p / 60000; 398 min %= 60; 399 400 if (min < 10) { 401 name.append('0'); 402 } 403 name.append(min); 404 name.append(") "); 405 name.append(displayName); 406 if (useDaylightTime && SHOW_DAYLIGHT_SAVINGS_INDICATOR) { 407 name.append(" \u2600"); // Sun symbol 408 } 409 return name.toString(); 410 } 411 } 412 } 413}