ZenModeSettings.java revision 7e90548836b3e7c4ec8132d9965ba11f055f6931
1/* 2 * Copyright (C) 2014 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.settings.notification; 18 19import static com.android.settings.notification.ZenModeDowntimeDaysSelection.DAYS; 20 21import android.app.AlertDialog; 22import android.app.Dialog; 23import android.app.DialogFragment; 24import android.app.FragmentManager; 25import android.app.INotificationManager; 26import android.app.TimePickerDialog; 27import android.content.Context; 28import android.content.DialogInterface; 29import android.content.DialogInterface.OnDismissListener; 30import android.content.pm.PackageManager; 31import android.content.res.Resources; 32import android.database.ContentObserver; 33import android.net.Uri; 34import android.os.Bundle; 35import android.os.Handler; 36import android.os.ServiceManager; 37import android.preference.Preference; 38import android.preference.Preference.OnPreferenceChangeListener; 39import android.preference.Preference.OnPreferenceClickListener; 40import android.preference.PreferenceCategory; 41import android.preference.PreferenceScreen; 42import android.preference.SwitchPreference; 43import android.provider.Settings.Global; 44import android.service.notification.Condition; 45import android.service.notification.ZenModeConfig; 46import android.text.format.DateFormat; 47import android.util.Log; 48import android.util.SparseArray; 49import android.widget.ScrollView; 50import android.widget.TimePicker; 51 52import com.android.settings.R; 53import com.android.settings.SettingsPreferenceFragment; 54import com.android.settings.Utils; 55import com.android.settings.notification.DropDownPreference.Callback; 56import com.android.settings.search.BaseSearchIndexProvider; 57import com.android.settings.search.Indexable; 58import com.android.settings.search.SearchIndexableRaw; 59 60import java.text.SimpleDateFormat; 61import java.util.ArrayList; 62import java.util.Calendar; 63import java.util.List; 64import java.util.Objects; 65 66public class ZenModeSettings extends SettingsPreferenceFragment implements Indexable { 67 private static final String TAG = "ZenModeSettings"; 68 private static final boolean DEBUG = true; 69 70 private static final String KEY_ZEN_MODE = "zen_mode"; 71 private static final String KEY_IMPORTANT = "important"; 72 private static final String KEY_CALLS = "phone_calls"; 73 private static final String KEY_MESSAGES = "messages"; 74 private static final String KEY_STARRED = "starred"; 75 private static final String KEY_EVENTS = "events"; 76 private static final String KEY_ALARM_INFO = "alarm_info"; 77 78 private static final String KEY_DOWNTIME = "downtime"; 79 private static final String KEY_DAYS = "days"; 80 private static final String KEY_START_TIME = "start_time"; 81 private static final String KEY_END_TIME = "end_time"; 82 83 private static final String KEY_AUTOMATION = "automation"; 84 private static final String KEY_ENTRY = "entry"; 85 private static final String KEY_CONDITION_PROVIDERS = "manage_condition_providers"; 86 87 private static final SettingPrefWithCallback PREF_ZEN_MODE = new SettingPrefWithCallback( 88 SettingPref.TYPE_GLOBAL, KEY_ZEN_MODE, Global.ZEN_MODE, Global.ZEN_MODE_OFF, 89 Global.ZEN_MODE_OFF, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, 90 Global.ZEN_MODE_NO_INTERRUPTIONS) { 91 protected String getCaption(Resources res, int value) { 92 switch (value) { 93 case Global.ZEN_MODE_NO_INTERRUPTIONS: 94 return res.getString(R.string.zen_mode_option_no_interruptions); 95 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: 96 return res.getString(R.string.zen_mode_option_important_interruptions); 97 default: 98 return res.getString(R.string.zen_mode_option_off); 99 } 100 } 101 }; 102 103 private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("EEE"); 104 105 private static SparseArray<String> allKeyTitles(Context context) { 106 final SparseArray<String> rt = new SparseArray<String>(); 107 rt.put(R.string.zen_mode_important_category, KEY_IMPORTANT); 108 if (Utils.isVoiceCapable(context)) { 109 rt.put(R.string.zen_mode_phone_calls, KEY_CALLS); 110 rt.put(R.string.zen_mode_option_title, KEY_ZEN_MODE); 111 } else { 112 rt.put(R.string.zen_mode_option_title_novoice, KEY_ZEN_MODE); 113 } 114 rt.put(R.string.zen_mode_messages, KEY_MESSAGES); 115 rt.put(R.string.zen_mode_from_starred, KEY_STARRED); 116 rt.put(R.string.zen_mode_events, KEY_EVENTS); 117 rt.put(R.string.zen_mode_alarm_info, KEY_ALARM_INFO); 118 rt.put(R.string.zen_mode_downtime_category, KEY_DOWNTIME); 119 rt.put(R.string.zen_mode_downtime_days, KEY_DAYS); 120 rt.put(R.string.zen_mode_start_time, KEY_START_TIME); 121 rt.put(R.string.zen_mode_end_time, KEY_END_TIME); 122 rt.put(R.string.zen_mode_automation_category, KEY_AUTOMATION); 123 rt.put(R.string.manage_condition_providers, KEY_CONDITION_PROVIDERS); 124 return rt; 125 } 126 127 private final Handler mHandler = new Handler(); 128 private final SettingsObserver mSettingsObserver = new SettingsObserver(); 129 130 private Context mContext; 131 private PackageManager mPM; 132 private ZenModeConfig mConfig; 133 private boolean mDisableListeners; 134 private SwitchPreference mCalls; 135 private SwitchPreference mMessages; 136 private DropDownPreference mStarred; 137 private SwitchPreference mEvents; 138 private Preference mDays; 139 private TimePickerPreference mStart; 140 private TimePickerPreference mEnd; 141 private PreferenceCategory mAutomationCategory; 142 private Preference mEntry; 143 private Preference mConditionProviders; 144 private AlertDialog mDialog; 145 146 @Override 147 public void onCreate(Bundle savedInstanceState) { 148 super.onCreate(savedInstanceState); 149 mContext = getActivity(); 150 mPM = mContext.getPackageManager(); 151 152 addPreferencesFromResource(R.xml.zen_mode_settings); 153 final PreferenceScreen root = getPreferenceScreen(); 154 155 mConfig = getZenModeConfig(); 156 if (DEBUG) Log.d(TAG, "Loaded mConfig=" + mConfig); 157 158 final Preference zenMode = PREF_ZEN_MODE.init(this); 159 PREF_ZEN_MODE.setCallback(new SettingPrefWithCallback.Callback() { 160 @Override 161 public void onSettingSelected(int value) { 162 if (value != Global.ZEN_MODE_OFF) { 163 showConditionSelection(value); 164 } 165 } 166 }); 167 if (!Utils.isVoiceCapable(mContext)) { 168 zenMode.setTitle(R.string.zen_mode_option_title_novoice); 169 } 170 171 final PreferenceCategory important = 172 (PreferenceCategory) root.findPreference(KEY_IMPORTANT); 173 174 mCalls = (SwitchPreference) important.findPreference(KEY_CALLS); 175 if (Utils.isVoiceCapable(mContext)) { 176 mCalls.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 177 @Override 178 public boolean onPreferenceChange(Preference preference, Object newValue) { 179 if (mDisableListeners) return true; 180 final boolean val = (Boolean) newValue; 181 if (val == mConfig.allowCalls) return true; 182 if (DEBUG) Log.d(TAG, "onPrefChange allowCalls=" + val); 183 final ZenModeConfig newConfig = mConfig.copy(); 184 newConfig.allowCalls = val; 185 return setZenModeConfig(newConfig); 186 } 187 }); 188 } else { 189 important.removePreference(mCalls); 190 mCalls = null; 191 } 192 193 mMessages = (SwitchPreference) important.findPreference(KEY_MESSAGES); 194 mMessages.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 195 @Override 196 public boolean onPreferenceChange(Preference preference, Object newValue) { 197 if (mDisableListeners) return true; 198 final boolean val = (Boolean) newValue; 199 if (val == mConfig.allowMessages) return true; 200 if (DEBUG) Log.d(TAG, "onPrefChange allowMessages=" + val); 201 final ZenModeConfig newConfig = mConfig.copy(); 202 newConfig.allowMessages = val; 203 return setZenModeConfig(newConfig); 204 } 205 }); 206 207 mStarred = (DropDownPreference) important.findPreference(KEY_STARRED); 208 mStarred.addItem(R.string.zen_mode_from_anyone, ZenModeConfig.SOURCE_ANYONE); 209 mStarred.addItem(R.string.zen_mode_from_starred, ZenModeConfig.SOURCE_STAR); 210 mStarred.addItem(R.string.zen_mode_from_contacts, ZenModeConfig.SOURCE_CONTACT); 211 mStarred.setCallback(new DropDownPreference.Callback() { 212 @Override 213 public boolean onItemSelected(int pos, Object newValue) { 214 if (mDisableListeners) return true; 215 final int val = (Integer) newValue; 216 if (val == mConfig.allowFrom) return true; 217 if (DEBUG) Log.d(TAG, "onPrefChange allowFrom=" + 218 ZenModeConfig.sourceToString(val)); 219 final ZenModeConfig newConfig = mConfig.copy(); 220 newConfig.allowFrom = val; 221 return setZenModeConfig(newConfig); 222 } 223 }); 224 important.addPreference(mStarred); 225 226 mEvents = (SwitchPreference) important.findPreference(KEY_EVENTS); 227 mEvents.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 228 @Override 229 public boolean onPreferenceChange(Preference preference, Object newValue) { 230 if (mDisableListeners) return true; 231 final boolean val = (Boolean) newValue; 232 if (val == mConfig.allowEvents) return true; 233 if (DEBUG) Log.d(TAG, "onPrefChange allowEvents=" + val); 234 final ZenModeConfig newConfig = mConfig.copy(); 235 newConfig.allowEvents = val; 236 return setZenModeConfig(newConfig); 237 } 238 }); 239 240 final PreferenceCategory downtime = (PreferenceCategory) root.findPreference(KEY_DOWNTIME); 241 242 mDays = downtime.findPreference(KEY_DAYS); 243 mDays.setOnPreferenceClickListener(new OnPreferenceClickListener() { 244 @Override 245 public boolean onPreferenceClick(Preference preference) { 246 new AlertDialog.Builder(mContext) 247 .setTitle(R.string.zen_mode_downtime_days) 248 .setView(new ZenModeDowntimeDaysSelection(mContext, mConfig.sleepMode) { 249 @Override 250 protected void onChanged(String mode) { 251 if (mDisableListeners) return; 252 if (Objects.equals(mode, mConfig.sleepMode)) return; 253 if (DEBUG) Log.d(TAG, "days.onChanged sleepMode=" + mode); 254 final ZenModeConfig newConfig = mConfig.copy(); 255 newConfig.sleepMode = mode; 256 setZenModeConfig(newConfig); 257 } 258 }) 259 .setOnDismissListener(new OnDismissListener() { 260 @Override 261 public void onDismiss(DialogInterface dialog) { 262 updateDays(); 263 } 264 }) 265 .setPositiveButton(R.string.done_button, null) 266 .show(); 267 return true; 268 } 269 }); 270 271 final FragmentManager mgr = getFragmentManager(); 272 273 mStart = new TimePickerPreference(mContext, mgr); 274 mStart.setKey(KEY_START_TIME); 275 mStart.setTitle(R.string.zen_mode_start_time); 276 mStart.setCallback(new TimePickerPreference.Callback() { 277 @Override 278 public boolean onSetTime(int hour, int minute) { 279 if (mDisableListeners) return true; 280 if (!ZenModeConfig.isValidHour(hour)) return false; 281 if (!ZenModeConfig.isValidMinute(minute)) return false; 282 if (hour == mConfig.sleepStartHour && minute == mConfig.sleepStartMinute) { 283 return true; 284 } 285 if (DEBUG) Log.d(TAG, "onPrefChange sleepStart h=" + hour + " m=" + minute); 286 final ZenModeConfig newConfig = mConfig.copy(); 287 newConfig.sleepStartHour = hour; 288 newConfig.sleepStartMinute = minute; 289 return setZenModeConfig(newConfig); 290 } 291 }); 292 downtime.addPreference(mStart); 293 mStart.setDependency(mDays.getKey()); 294 295 mEnd = new TimePickerPreference(mContext, mgr); 296 mEnd.setKey(KEY_END_TIME); 297 mEnd.setTitle(R.string.zen_mode_end_time); 298 mEnd.setCallback(new TimePickerPreference.Callback() { 299 @Override 300 public boolean onSetTime(int hour, int minute) { 301 if (mDisableListeners) return true; 302 if (!ZenModeConfig.isValidHour(hour)) return false; 303 if (!ZenModeConfig.isValidMinute(minute)) return false; 304 if (hour == mConfig.sleepEndHour && minute == mConfig.sleepEndMinute) { 305 return true; 306 } 307 if (DEBUG) Log.d(TAG, "onPrefChange sleepEnd h=" + hour + " m=" + minute); 308 final ZenModeConfig newConfig = mConfig.copy(); 309 newConfig.sleepEndHour = hour; 310 newConfig.sleepEndMinute = minute; 311 return setZenModeConfig(newConfig); 312 } 313 }); 314 downtime.addPreference(mEnd); 315 mEnd.setDependency(mDays.getKey()); 316 317 mAutomationCategory = (PreferenceCategory) findPreference(KEY_AUTOMATION); 318 mEntry = findPreference(KEY_ENTRY); 319 mEntry.setOnPreferenceClickListener(new OnPreferenceClickListener() { 320 @Override 321 public boolean onPreferenceClick(Preference preference) { 322 new AlertDialog.Builder(mContext) 323 .setTitle(R.string.zen_mode_entry_conditions_title) 324 .setView(new ZenModeAutomaticConditionSelection(mContext)) 325 .setOnDismissListener(new OnDismissListener() { 326 @Override 327 public void onDismiss(DialogInterface dialog) { 328 refreshAutomationSection(); 329 } 330 }) 331 .setPositiveButton(R.string.dlg_ok, null) 332 .show(); 333 return true; 334 } 335 }); 336 mConditionProviders = findPreference(KEY_CONDITION_PROVIDERS); 337 338 updateControls(); 339 } 340 341 private void updateDays() { 342 if (mConfig != null) { 343 final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode); 344 if (days != null && days.length != 0) { 345 final StringBuilder sb = new StringBuilder(); 346 final Calendar c = Calendar.getInstance(); 347 for (int i = 0; i < DAYS.length; i++) { 348 final int day = DAYS[i]; 349 for (int j = 0; j < days.length; j++) { 350 if (day == days[j]) { 351 c.set(Calendar.DAY_OF_WEEK, day); 352 if (sb.length() > 0) { 353 sb.append(mContext.getString(R.string.summary_divider_text)); 354 } 355 sb.append(DAY_FORMAT.format(c.getTime())); 356 break; 357 } 358 } 359 } 360 if (sb.length() > 0) { 361 mDays.setSummary(sb); 362 mDays.notifyDependencyChange(false); 363 return; 364 } 365 } 366 } 367 mDays.setSummary(R.string.zen_mode_downtime_days_none); 368 mDays.notifyDependencyChange(true); 369 } 370 371 private void updateEndSummary() { 372 final int startMin = 60 * mConfig.sleepStartHour + mConfig.sleepStartMinute; 373 final int endMin = 60 * mConfig.sleepEndHour + mConfig.sleepEndMinute; 374 final boolean nextDay = startMin >= endMin; 375 mEnd.setSummaryFormat(nextDay ? R.string.zen_mode_end_time_summary_format : 0); 376 } 377 378 private void updateControls() { 379 mDisableListeners = true; 380 if (mCalls != null) { 381 mCalls.setChecked(mConfig.allowCalls); 382 } 383 mMessages.setChecked(mConfig.allowMessages); 384 mStarred.setSelectedValue(mConfig.allowFrom); 385 mEvents.setChecked(mConfig.allowEvents); 386 updateStarredEnabled(); 387 updateDays(); 388 mStart.setTime(mConfig.sleepStartHour, mConfig.sleepStartMinute); 389 mEnd.setTime(mConfig.sleepEndHour, mConfig.sleepEndMinute); 390 mDisableListeners = false; 391 refreshAutomationSection(); 392 updateEndSummary(); 393 } 394 395 private void updateStarredEnabled() { 396 mStarred.setEnabled(mConfig.allowCalls || mConfig.allowMessages); 397 } 398 399 private void refreshAutomationSection() { 400 if (mConditionProviders != null) { 401 final int total = ConditionProviderSettings.getProviderCount(mPM); 402 if (total == 0) { 403 getPreferenceScreen().removePreference(mAutomationCategory); 404 } else { 405 final int n = ConditionProviderSettings.getEnabledProviderCount(mContext); 406 if (n == 0) { 407 mConditionProviders.setSummary(getResources().getString( 408 R.string.manage_condition_providers_summary_zero)); 409 } else { 410 mConditionProviders.setSummary(String.format(getResources().getQuantityString( 411 R.plurals.manage_condition_providers_summary_nonzero, 412 n, n))); 413 } 414 final String entrySummary = getEntryConditionSummary(); 415 if (n == 0 || entrySummary == null) { 416 mEntry.setSummary(R.string.zen_mode_entry_conditions_summary_none); 417 } else { 418 mEntry.setSummary(entrySummary); 419 } 420 } 421 } 422 } 423 424 private String getEntryConditionSummary() { 425 final INotificationManager nm = INotificationManager.Stub.asInterface( 426 ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 427 try { 428 final Condition[] automatic = nm.getAutomaticZenModeConditions(); 429 if (automatic == null || automatic.length == 0) { 430 return null; 431 } 432 final String divider = getString(R.string.summary_divider_text); 433 final StringBuilder sb = new StringBuilder(); 434 for (int i = 0; i < automatic.length; i++) { 435 if (i > 0) sb.append(divider); 436 sb.append(automatic[i].summary); 437 } 438 return sb.toString(); 439 } catch (Exception e) { 440 Log.w(TAG, "Error calling getAutomaticZenModeConditions", e); 441 return null; 442 } 443 } 444 445 @Override 446 public void onResume() { 447 super.onResume(); 448 updateControls(); 449 mSettingsObserver.register(); 450 } 451 452 @Override 453 public void onPause() { 454 super.onPause(); 455 mSettingsObserver.unregister(); 456 } 457 458 private void updateZenModeConfig() { 459 final ZenModeConfig config = getZenModeConfig(); 460 if (Objects.equals(config, mConfig)) return; 461 mConfig = config; 462 if (DEBUG) Log.d(TAG, "updateZenModeConfig mConfig=" + mConfig); 463 updateControls(); 464 } 465 466 private ZenModeConfig getZenModeConfig() { 467 final INotificationManager nm = INotificationManager.Stub.asInterface( 468 ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 469 try { 470 return nm.getZenModeConfig(); 471 } catch (Exception e) { 472 Log.w(TAG, "Error calling NoMan", e); 473 return new ZenModeConfig(); 474 } 475 } 476 477 private boolean setZenModeConfig(ZenModeConfig config) { 478 final INotificationManager nm = INotificationManager.Stub.asInterface( 479 ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 480 try { 481 final boolean success = nm.setZenModeConfig(config); 482 if (success) { 483 mConfig = config; 484 if (DEBUG) Log.d(TAG, "Saved mConfig=" + mConfig); 485 updateEndSummary(); 486 updateStarredEnabled(); 487 } 488 return success; 489 } catch (Exception e) { 490 Log.w(TAG, "Error calling NoMan", e); 491 return false; 492 } 493 } 494 495 protected void putZenModeSetting(int value) { 496 Global.putInt(getContentResolver(), Global.ZEN_MODE, value); 497 } 498 499 protected void showConditionSelection(final int newSettingsValue) { 500 if (mDialog != null) return; 501 502 final ZenModeConditionSelection zenModeConditionSelection = 503 new ZenModeConditionSelection(mContext); 504 DialogInterface.OnClickListener positiveListener = new DialogInterface.OnClickListener() { 505 @Override 506 public void onClick(DialogInterface dialog, int which) { 507 zenModeConditionSelection.confirmCondition(); 508 mDialog = null; 509 } 510 }; 511 final int oldSettingsValue = PREF_ZEN_MODE.getValue(mContext); 512 ScrollView scrollView = new ScrollView(mContext); 513 scrollView.addView(zenModeConditionSelection); 514 mDialog = new AlertDialog.Builder(getActivity()) 515 .setTitle(PREF_ZEN_MODE.getCaption(getResources(), newSettingsValue)) 516 .setView(scrollView) 517 .setPositiveButton(R.string.okay, positiveListener) 518 .setNegativeButton(R.string.cancel_all_caps, new DialogInterface.OnClickListener() { 519 @Override 520 public void onClick(DialogInterface dialog, int which) { 521 cancelDialog(oldSettingsValue); 522 } 523 }) 524 .setOnCancelListener(new DialogInterface.OnCancelListener() { 525 @Override 526 public void onCancel(DialogInterface dialog) { 527 cancelDialog(oldSettingsValue); 528 } 529 }).create(); 530 mDialog.show(); 531 } 532 533 protected void cancelDialog(int oldSettingsValue) { 534 // If not making a decision, reset drop down to current setting. 535 PREF_ZEN_MODE.setValueWithoutCallback(mContext, oldSettingsValue); 536 mDialog = null; 537 } 538 539 // Enable indexing of searchable data 540 public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 541 new BaseSearchIndexProvider() { 542 @Override 543 public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) { 544 final SparseArray<String> keyTitles = allKeyTitles(context); 545 final int N = keyTitles.size(); 546 final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>(N); 547 final Resources res = context.getResources(); 548 for (int i = 0; i < N; i++) { 549 final SearchIndexableRaw data = new SearchIndexableRaw(context); 550 data.key = keyTitles.valueAt(i); 551 data.title = res.getString(keyTitles.keyAt(i)); 552 data.screenTitle = res.getString(R.string.zen_mode_settings_title); 553 result.add(data); 554 } 555 return result; 556 } 557 558 public List<String> getNonIndexableKeys(Context context) { 559 final ArrayList<String> rt = new ArrayList<String>(); 560 if (!Utils.isVoiceCapable(context)) { 561 rt.add(KEY_CALLS); 562 } 563 return rt; 564 } 565 }; 566 567 private static class SettingPrefWithCallback extends SettingPref { 568 569 private Callback mCallback; 570 private int mValue; 571 572 public SettingPrefWithCallback(int type, String key, String setting, int def, 573 int... values) { 574 super(type, key, setting, def, values); 575 } 576 577 public void setCallback(Callback callback) { 578 mCallback = callback; 579 } 580 581 @Override 582 public void update(Context context) { 583 // Avoid callbacks from non-user changes. 584 mValue = getValue(context); 585 super.update(context); 586 } 587 588 @Override 589 protected boolean setSetting(Context context, int value) { 590 if (value == mValue) return true; 591 mValue = value; 592 if (mCallback != null) { 593 mCallback.onSettingSelected(value); 594 } 595 return super.setSetting(context, value); 596 } 597 598 @Override 599 public Preference init(SettingsPreferenceFragment settings) { 600 Preference ret = super.init(settings); 601 mValue = getValue(settings.getActivity()); 602 603 return ret; 604 } 605 606 public boolean setValueWithoutCallback(Context context, int value) { 607 // Set the current value ahead of time, this way we won't trigger a callback. 608 mValue = value; 609 return putInt(mType, context.getContentResolver(), mSetting, value); 610 } 611 612 public int getValue(Context context) { 613 return getInt(mType, context.getContentResolver(), mSetting, mDefault); 614 } 615 616 public interface Callback { 617 void onSettingSelected(int value); 618 } 619 } 620 621 private final class SettingsObserver extends ContentObserver { 622 private final Uri ZEN_MODE_URI = Global.getUriFor(Global.ZEN_MODE); 623 private final Uri ZEN_MODE_CONFIG_ETAG_URI = Global.getUriFor(Global.ZEN_MODE_CONFIG_ETAG); 624 625 public SettingsObserver() { 626 super(mHandler); 627 } 628 629 public void register() { 630 getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this); 631 getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_ETAG_URI, false, this); 632 } 633 634 public void unregister() { 635 getContentResolver().unregisterContentObserver(this); 636 } 637 638 @Override 639 public void onChange(boolean selfChange, Uri uri) { 640 super.onChange(selfChange, uri); 641 if (ZEN_MODE_URI.equals(uri)) { 642 PREF_ZEN_MODE.update(mContext); 643 } 644 if (ZEN_MODE_CONFIG_ETAG_URI.equals(uri)) { 645 updateZenModeConfig(); 646 } 647 } 648 } 649 650 private static class TimePickerPreference extends Preference { 651 private final Context mContext; 652 653 private int mSummaryFormat; 654 private int mHourOfDay; 655 private int mMinute; 656 private Callback mCallback; 657 658 public TimePickerPreference(Context context, final FragmentManager mgr) { 659 super(context); 660 mContext = context; 661 setPersistent(false); 662 setOnPreferenceClickListener(new OnPreferenceClickListener(){ 663 @Override 664 public boolean onPreferenceClick(Preference preference) { 665 final TimePickerFragment frag = new TimePickerFragment(); 666 frag.pref = TimePickerPreference.this; 667 frag.show(mgr, TimePickerPreference.class.getName()); 668 return true; 669 } 670 }); 671 } 672 673 public void setCallback(Callback callback) { 674 mCallback = callback; 675 } 676 677 public void setSummaryFormat(int resId) { 678 mSummaryFormat = resId; 679 updateSummary(); 680 } 681 682 public void setTime(int hourOfDay, int minute) { 683 if (mCallback != null && !mCallback.onSetTime(hourOfDay, minute)) return; 684 mHourOfDay = hourOfDay; 685 mMinute = minute; 686 updateSummary(); 687 } 688 689 private void updateSummary() { 690 final Calendar c = Calendar.getInstance(); 691 c.set(Calendar.HOUR_OF_DAY, mHourOfDay); 692 c.set(Calendar.MINUTE, mMinute); 693 String time = DateFormat.getTimeFormat(mContext).format(c.getTime()); 694 if (mSummaryFormat != 0) { 695 time = mContext.getResources().getString(mSummaryFormat, time); 696 } 697 setSummary(time); 698 } 699 700 public static class TimePickerFragment extends DialogFragment implements 701 TimePickerDialog.OnTimeSetListener { 702 public TimePickerPreference pref; 703 704 @Override 705 public Dialog onCreateDialog(Bundle savedInstanceState) { 706 final boolean usePref = pref != null && pref.mHourOfDay >= 0 && pref.mMinute >= 0; 707 final Calendar c = Calendar.getInstance(); 708 final int hour = usePref ? pref.mHourOfDay : c.get(Calendar.HOUR_OF_DAY); 709 final int minute = usePref ? pref.mMinute : c.get(Calendar.MINUTE); 710 return new TimePickerDialog(getActivity(), this, hour, minute, 711 DateFormat.is24HourFormat(getActivity())); 712 } 713 714 public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 715 if (pref != null) { 716 pref.setTime(hourOfDay, minute); 717 } 718 } 719 } 720 721 public interface Callback { 722 boolean onSetTime(int hour, int minute); 723 } 724 } 725} 726