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 17 package com.android.settings.notification; 18 19 import android.app.NotificationManager; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.BroadcastReceiver; 22 import android.content.ComponentName; 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.PackageManager; 28 import android.content.pm.ServiceInfo; 29 import android.database.ContentObserver; 30 import android.database.Cursor; 31 import android.database.sqlite.SQLiteException; 32 import android.media.AudioManager; 33 import android.media.RingtoneManager; 34 import android.net.Uri; 35 import android.os.AsyncTask; 36 import android.os.Bundle; 37 import android.os.Handler; 38 import android.os.Looper; 39 import android.os.Message; 40 import android.os.UserHandle; 41 import android.os.UserManager; 42 import android.os.Vibrator; 43 import android.preference.Preference; 44 import android.preference.Preference.OnPreferenceChangeListener; 45 import android.preference.PreferenceCategory; 46 import android.preference.SeekBarVolumizer; 47 import android.preference.TwoStatePreference; 48 import android.provider.MediaStore; 49 import android.provider.OpenableColumns; 50 import android.provider.SearchIndexableResource; 51 import android.provider.Settings; 52 import android.util.Log; 53 54 import com.android.internal.logging.MetricsLogger; 55 import com.android.internal.widget.LockPatternUtils; 56 import com.android.settings.DropDownPreference; 57 import com.android.settings.R; 58 import com.android.settings.SettingsPreferenceFragment; 59 import com.android.settings.Utils; 60 import com.android.settings.search.BaseSearchIndexProvider; 61 import com.android.settings.search.Indexable; 62 63 import java.util.ArrayList; 64 import java.util.Arrays; 65 import java.util.List; 66 import java.util.Objects; 67 68 public class NotificationSettings extends SettingsPreferenceFragment implements Indexable { 69 private static final String TAG = "NotificationSettings"; 70 71 private static final String KEY_SOUND = "sound"; 72 private static final String KEY_MEDIA_VOLUME = "media_volume"; 73 private static final String KEY_ALARM_VOLUME = "alarm_volume"; 74 private static final String KEY_RING_VOLUME = "ring_volume"; 75 private static final String KEY_NOTIFICATION_VOLUME = "notification_volume"; 76 private static final String KEY_PHONE_RINGTONE = "ringtone"; 77 private static final String KEY_NOTIFICATION_RINGTONE = "notification_ringtone"; 78 private static final String KEY_VIBRATE_WHEN_RINGING = "vibrate_when_ringing"; 79 private static final String KEY_WIFI_DISPLAY = "wifi_display"; 80 private static final String KEY_NOTIFICATION = "notification"; 81 private static final String KEY_NOTIFICATION_PULSE = "notification_pulse"; 82 private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "lock_screen_notifications"; 83 private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access"; 84 private static final String KEY_ZEN_ACCESS = "manage_zen_access"; 85 private static final String KEY_ZEN_MODE = "zen_mode"; 86 87 private static final String[] RESTRICTED_KEYS = { 88 KEY_MEDIA_VOLUME, 89 KEY_ALARM_VOLUME, 90 KEY_RING_VOLUME, 91 KEY_NOTIFICATION_VOLUME, 92 KEY_ZEN_ACCESS, 93 KEY_ZEN_MODE, 94 }; 95 96 private static final int SAMPLE_CUTOFF = 2000; // manually cap sample playback at 2 seconds 97 98 private final VolumePreferenceCallback mVolumeCallback = new VolumePreferenceCallback(); 99 private final H mHandler = new H(); 100 private final SettingsObserver mSettingsObserver = new SettingsObserver(); 101 private final Receiver mReceiver = new Receiver(); 102 private final ArrayList<VolumeSeekBarPreference> mVolumePrefs = new ArrayList<>(); 103 104 private Context mContext; 105 private PackageManager mPM; 106 private boolean mVoiceCapable; 107 private Vibrator mVibrator; 108 private AudioManager mAudioManager; 109 private VolumeSeekBarPreference mRingOrNotificationPreference; 110 111 private Preference mPhoneRingtonePreference; 112 private Preference mNotificationRingtonePreference; 113 private TwoStatePreference mVibrateWhenRinging; 114 private TwoStatePreference mNotificationPulse; 115 private DropDownPreference mLockscreen; 116 private Preference mNotificationAccess; 117 private Preference mZenAccess; 118 private boolean mSecure; 119 private int mLockscreenSelectedValue; 120 private ComponentName mSuppressor; 121 private int mRingerMode = -1; 122 123 private UserManager mUserManager; 124 125 @Override 126 protected int getMetricsCategory() { 127 return MetricsLogger.NOTIFICATION; 128 } 129 130 @Override 131 public void onCreate(Bundle savedInstanceState) { 132 super.onCreate(savedInstanceState); 133 mContext = getActivity(); 134 mPM = mContext.getPackageManager(); 135 mUserManager = UserManager.get(getContext()); 136 mVoiceCapable = Utils.isVoiceCapable(mContext); 137 mSecure = new LockPatternUtils(getActivity()).isSecure(UserHandle.myUserId()); 138 139 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 140 mVibrator = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE); 141 if (mVibrator != null && !mVibrator.hasVibrator()) { 142 mVibrator = null; 143 } 144 145 addPreferencesFromResource(R.xml.notification_settings); 146 147 final PreferenceCategory sound = (PreferenceCategory) findPreference(KEY_SOUND); 148 initVolumePreference(KEY_MEDIA_VOLUME, AudioManager.STREAM_MUSIC, 149 com.android.internal.R.drawable.ic_audio_media_mute); 150 initVolumePreference(KEY_ALARM_VOLUME, AudioManager.STREAM_ALARM, 151 com.android.internal.R.drawable.ic_audio_alarm_mute); 152 if (mVoiceCapable) { 153 mRingOrNotificationPreference = 154 initVolumePreference(KEY_RING_VOLUME, AudioManager.STREAM_RING, 155 com.android.internal.R.drawable.ic_audio_ring_notif_mute); 156 sound.removePreference(sound.findPreference(KEY_NOTIFICATION_VOLUME)); 157 } else { 158 mRingOrNotificationPreference = 159 initVolumePreference(KEY_NOTIFICATION_VOLUME, AudioManager.STREAM_NOTIFICATION, 160 com.android.internal.R.drawable.ic_audio_ring_notif_mute); 161 sound.removePreference(sound.findPreference(KEY_RING_VOLUME)); 162 } 163 initRingtones(sound); 164 initVibrateWhenRinging(sound); 165 166 final PreferenceCategory notification = (PreferenceCategory) 167 findPreference(KEY_NOTIFICATION); 168 initPulse(notification); 169 initLockscreenNotifications(notification); 170 171 mNotificationAccess = findPreference(KEY_NOTIFICATION_ACCESS); 172 refreshNotificationListeners(); 173 mZenAccess = findPreference(KEY_ZEN_ACCESS); 174 refreshZenAccess(); 175 updateRingerMode(); 176 updateEffectsSuppressor(); 177 } 178 179 @Override 180 public void onResume() { 181 super.onResume(); 182 refreshNotificationListeners(); 183 refreshZenAccess(); 184 lookupRingtoneNames(); 185 mSettingsObserver.register(true); 186 mReceiver.register(true); 187 updateRingOrNotificationPreference(); 188 updateEffectsSuppressor(); 189 for (VolumeSeekBarPreference volumePref : mVolumePrefs) { 190 volumePref.onActivityResume(); 191 } 192 boolean isRestricted = mUserManager.hasUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME); 193 for (String key : RESTRICTED_KEYS) { 194 Preference pref = findPreference(key); 195 if (pref != null) { 196 pref.setEnabled(!isRestricted); 197 } 198 } 199 } 200 201 @Override 202 public void onPause() { 203 super.onPause(); 204 mVolumeCallback.stopSample(); 205 mSettingsObserver.register(false); 206 mReceiver.register(false); 207 } 208 209 // === Volumes === 210 211 private VolumeSeekBarPreference initVolumePreference(String key, int stream, int muteIcon) { 212 final VolumeSeekBarPreference volumePref = (VolumeSeekBarPreference) findPreference(key); 213 volumePref.setCallback(mVolumeCallback); 214 volumePref.setStream(stream); 215 mVolumePrefs.add(volumePref); 216 volumePref.setMuteIcon(muteIcon); 217 return volumePref; 218 } 219 220 private void updateRingOrNotificationPreference() { 221 mRingOrNotificationPreference.showIcon(mSuppressor != null 222 ? com.android.internal.R.drawable.ic_audio_ring_notif_mute 223 : mRingerMode == AudioManager.RINGER_MODE_VIBRATE || wasRingerModeVibrate() 224 ? com.android.internal.R.drawable.ic_audio_ring_notif_vibrate 225 : com.android.internal.R.drawable.ic_audio_ring_notif); 226 } 227 228 private boolean wasRingerModeVibrate() { 229 return mVibrator != null && mRingerMode == AudioManager.RINGER_MODE_SILENT 230 && mAudioManager.getLastAudibleStreamVolume(AudioManager.STREAM_RING) == 0; 231 } 232 233 private void updateRingerMode() { 234 final int ringerMode = mAudioManager.getRingerModeInternal(); 235 if (mRingerMode == ringerMode) return; 236 mRingerMode = ringerMode; 237 updateRingOrNotificationPreference(); 238 } 239 240 private void updateEffectsSuppressor() { 241 final ComponentName suppressor = NotificationManager.from(mContext).getEffectsSuppressor(); 242 if (Objects.equals(suppressor, mSuppressor)) return; 243 mSuppressor = suppressor; 244 if (mRingOrNotificationPreference != null) { 245 final String text = suppressor != null ? 246 mContext.getString(com.android.internal.R.string.muted_by, 247 getSuppressorCaption(suppressor)) : null; 248 mRingOrNotificationPreference.setSuppressionText(text); 249 } 250 updateRingOrNotificationPreference(); 251 } 252 253 private String getSuppressorCaption(ComponentName suppressor) { 254 final PackageManager pm = mContext.getPackageManager(); 255 try { 256 final ServiceInfo info = pm.getServiceInfo(suppressor, 0); 257 if (info != null) { 258 final CharSequence seq = info.loadLabel(pm); 259 if (seq != null) { 260 final String str = seq.toString().trim(); 261 if (str.length() > 0) { 262 return str; 263 } 264 } 265 } 266 } catch (Throwable e) { 267 Log.w(TAG, "Error loading suppressor caption", e); 268 } 269 return suppressor.getPackageName(); 270 } 271 272 private final class VolumePreferenceCallback implements VolumeSeekBarPreference.Callback { 273 private SeekBarVolumizer mCurrent; 274 275 @Override 276 public void onSampleStarting(SeekBarVolumizer sbv) { 277 if (mCurrent != null && mCurrent != sbv) { 278 mCurrent.stopSample(); 279 } 280 mCurrent = sbv; 281 if (mCurrent != null) { 282 mHandler.removeMessages(H.STOP_SAMPLE); 283 mHandler.sendEmptyMessageDelayed(H.STOP_SAMPLE, SAMPLE_CUTOFF); 284 } 285 } 286 287 @Override 288 public void onStreamValueChanged(int stream, int progress) { 289 // noop 290 } 291 292 public void stopSample() { 293 if (mCurrent != null) { 294 mCurrent.stopSample(); 295 } 296 } 297 }; 298 299 300 // === Phone & notification ringtone === 301 302 private void initRingtones(PreferenceCategory root) { 303 mPhoneRingtonePreference = root.findPreference(KEY_PHONE_RINGTONE); 304 if (mPhoneRingtonePreference != null && !mVoiceCapable) { 305 root.removePreference(mPhoneRingtonePreference); 306 mPhoneRingtonePreference = null; 307 } 308 mNotificationRingtonePreference = root.findPreference(KEY_NOTIFICATION_RINGTONE); 309 } 310 311 private void lookupRingtoneNames() { 312 AsyncTask.execute(mLookupRingtoneNames); 313 } 314 315 private final Runnable mLookupRingtoneNames = new Runnable() { 316 @Override 317 public void run() { 318 if (mPhoneRingtonePreference != null) { 319 final CharSequence summary = updateRingtoneName( 320 mContext, RingtoneManager.TYPE_RINGTONE); 321 if (summary != null) { 322 mHandler.obtainMessage(H.UPDATE_PHONE_RINGTONE, summary).sendToTarget(); 323 } 324 } 325 if (mNotificationRingtonePreference != null) { 326 final CharSequence summary = updateRingtoneName( 327 mContext, RingtoneManager.TYPE_NOTIFICATION); 328 if (summary != null) { 329 mHandler.obtainMessage(H.UPDATE_NOTIFICATION_RINGTONE, summary).sendToTarget(); 330 } 331 } 332 } 333 }; 334 335 private static CharSequence updateRingtoneName(Context context, int type) { 336 if (context == null) { 337 Log.e(TAG, "Unable to update ringtone name, no context provided"); 338 return null; 339 } 340 Uri ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, type); 341 CharSequence summary = context.getString(com.android.internal.R.string.ringtone_unknown); 342 // Is it a silent ringtone? 343 if (ringtoneUri == null) { 344 summary = context.getString(com.android.internal.R.string.ringtone_silent); 345 } else { 346 Cursor cursor = null; 347 try { 348 if (MediaStore.AUTHORITY.equals(ringtoneUri.getAuthority())) { 349 // Fetch the ringtone title from the media provider 350 cursor = context.getContentResolver().query(ringtoneUri, 351 new String[] { MediaStore.Audio.Media.TITLE }, null, null, null); 352 } else if (ContentResolver.SCHEME_CONTENT.equals(ringtoneUri.getScheme())) { 353 cursor = context.getContentResolver().query(ringtoneUri, 354 new String[] { OpenableColumns.DISPLAY_NAME }, null, null, null); 355 } 356 if (cursor != null) { 357 if (cursor.moveToFirst()) { 358 summary = cursor.getString(0); 359 } 360 } 361 } catch (SQLiteException sqle) { 362 // Unknown title for the ringtone 363 } catch (IllegalArgumentException iae) { 364 // Some other error retrieving the column from the provider 365 } finally { 366 if (cursor != null) { 367 cursor.close(); 368 } 369 } 370 } 371 return summary; 372 } 373 374 // === Vibrate when ringing === 375 376 private void initVibrateWhenRinging(PreferenceCategory root) { 377 mVibrateWhenRinging = (TwoStatePreference) root.findPreference(KEY_VIBRATE_WHEN_RINGING); 378 if (mVibrateWhenRinging == null) { 379 Log.i(TAG, "Preference not found: " + KEY_VIBRATE_WHEN_RINGING); 380 return; 381 } 382 if (!mVoiceCapable) { 383 root.removePreference(mVibrateWhenRinging); 384 mVibrateWhenRinging = null; 385 return; 386 } 387 mVibrateWhenRinging.setPersistent(false); 388 updateVibrateWhenRinging(); 389 mVibrateWhenRinging.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 390 @Override 391 public boolean onPreferenceChange(Preference preference, Object newValue) { 392 final boolean val = (Boolean) newValue; 393 return Settings.System.putInt(getContentResolver(), 394 Settings.System.VIBRATE_WHEN_RINGING, 395 val ? 1 : 0); 396 } 397 }); 398 } 399 400 private void updateVibrateWhenRinging() { 401 if (mVibrateWhenRinging == null) return; 402 mVibrateWhenRinging.setChecked(Settings.System.getInt(getContentResolver(), 403 Settings.System.VIBRATE_WHEN_RINGING, 0) != 0); 404 } 405 406 // === Pulse notification light === 407 408 private void initPulse(PreferenceCategory parent) { 409 mNotificationPulse = (TwoStatePreference) parent.findPreference(KEY_NOTIFICATION_PULSE); 410 if (mNotificationPulse == null) { 411 Log.i(TAG, "Preference not found: " + KEY_NOTIFICATION_PULSE); 412 return; 413 } 414 if (!getResources() 415 .getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed)) { 416 parent.removePreference(mNotificationPulse); 417 } else { 418 updatePulse(); 419 mNotificationPulse.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 420 @Override 421 public boolean onPreferenceChange(Preference preference, Object newValue) { 422 final boolean val = (Boolean)newValue; 423 return Settings.System.putInt(getContentResolver(), 424 Settings.System.NOTIFICATION_LIGHT_PULSE, 425 val ? 1 : 0); 426 } 427 }); 428 } 429 } 430 431 private void updatePulse() { 432 if (mNotificationPulse == null) { 433 return; 434 } 435 try { 436 mNotificationPulse.setChecked(Settings.System.getInt(getContentResolver(), 437 Settings.System.NOTIFICATION_LIGHT_PULSE) == 1); 438 } catch (Settings.SettingNotFoundException snfe) { 439 Log.e(TAG, Settings.System.NOTIFICATION_LIGHT_PULSE + " not found"); 440 } 441 } 442 443 // === Lockscreen (public / private) notifications === 444 445 private void initLockscreenNotifications(PreferenceCategory parent) { 446 mLockscreen = (DropDownPreference) parent.findPreference(KEY_LOCK_SCREEN_NOTIFICATIONS); 447 if (mLockscreen == null) { 448 Log.i(TAG, "Preference not found: " + KEY_LOCK_SCREEN_NOTIFICATIONS); 449 return; 450 } 451 452 boolean isSecureNotificationsDisabled = isSecureNotificationsDisabled(); 453 boolean isUnredactedNotificationsDisabled = isUnredactedNotificationsDisabled(); 454 if (!isSecureNotificationsDisabled && !isUnredactedNotificationsDisabled) { 455 mLockscreen.addItem(R.string.lock_screen_notifications_summary_show, 456 R.string.lock_screen_notifications_summary_show); 457 } 458 if (mSecure && !isSecureNotificationsDisabled) { 459 mLockscreen.addItem(R.string.lock_screen_notifications_summary_hide, 460 R.string.lock_screen_notifications_summary_hide); 461 } 462 mLockscreen.addItem(R.string.lock_screen_notifications_summary_disable, 463 R.string.lock_screen_notifications_summary_disable); 464 updateLockscreenNotifications(); 465 if (mLockscreen.getItemCount() > 1) { 466 mLockscreen.setCallback(new DropDownPreference.Callback() { 467 @Override 468 public boolean onItemSelected(int pos, Object value) { 469 final int val = (Integer) value; 470 if (val == mLockscreenSelectedValue) { 471 return true; 472 } 473 final boolean enabled = 474 val != R.string.lock_screen_notifications_summary_disable; 475 final boolean show = val == R.string.lock_screen_notifications_summary_show; 476 Settings.Secure.putInt(getContentResolver(), 477 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, show ? 1 : 0); 478 Settings.Secure.putInt(getContentResolver(), 479 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, enabled ? 1 : 0); 480 mLockscreenSelectedValue = val; 481 return true; 482 } 483 }); 484 } else { 485 // There is one or less option for the user, disable the drop down. 486 mLockscreen.setEnabled(false); 487 } 488 } 489 490 private boolean isSecureNotificationsDisabled() { 491 final DevicePolicyManager dpm = 492 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); 493 return dpm != null && (dpm.getKeyguardDisabledFeatures(null) 494 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) != 0; 495 } 496 497 private boolean isUnredactedNotificationsDisabled() { 498 final DevicePolicyManager dpm = 499 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); 500 return dpm != null && (dpm.getKeyguardDisabledFeatures(null) 501 & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) != 0; 502 } 503 504 private void updateLockscreenNotifications() { 505 if (mLockscreen == null) { 506 return; 507 } 508 final boolean enabled = getLockscreenNotificationsEnabled(); 509 final boolean allowPrivate = !mSecure || getLockscreenAllowPrivateNotifications(); 510 mLockscreenSelectedValue = !enabled ? R.string.lock_screen_notifications_summary_disable : 511 allowPrivate ? R.string.lock_screen_notifications_summary_show : 512 R.string.lock_screen_notifications_summary_hide; 513 mLockscreen.setSelectedValue(mLockscreenSelectedValue); 514 } 515 516 private boolean getLockscreenNotificationsEnabled() { 517 return Settings.Secure.getInt(getContentResolver(), 518 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0; 519 } 520 521 private boolean getLockscreenAllowPrivateNotifications() { 522 return Settings.Secure.getInt(getContentResolver(), 523 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0; 524 } 525 526 // === Notification listeners === 527 528 private void refreshNotificationListeners() { 529 if (mNotificationAccess != null) { 530 final int n = NotificationAccessSettings.getEnabledListenersCount(mContext); 531 if (n == 0) { 532 mNotificationAccess.setSummary(getResources().getString( 533 R.string.manage_notification_access_summary_zero)); 534 } else { 535 mNotificationAccess.setSummary(String.format(getResources().getQuantityString( 536 R.plurals.manage_notification_access_summary_nonzero, 537 n, n))); 538 } 539 } 540 } 541 542 // === Zen access === 543 544 private void refreshZenAccess() { 545 // noop for now 546 } 547 548 // === Callbacks === 549 550 private final class SettingsObserver extends ContentObserver { 551 private final Uri VIBRATE_WHEN_RINGING_URI = 552 Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING); 553 private final Uri NOTIFICATION_LIGHT_PULSE_URI = 554 Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 555 private final Uri LOCK_SCREEN_PRIVATE_URI = 556 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS); 557 private final Uri LOCK_SCREEN_SHOW_URI = 558 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS); 559 560 public SettingsObserver() { 561 super(mHandler); 562 } 563 564 public void register(boolean register) { 565 final ContentResolver cr = getContentResolver(); 566 if (register) { 567 cr.registerContentObserver(VIBRATE_WHEN_RINGING_URI, false, this); 568 cr.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, false, this); 569 cr.registerContentObserver(LOCK_SCREEN_PRIVATE_URI, false, this); 570 cr.registerContentObserver(LOCK_SCREEN_SHOW_URI, false, this); 571 } else { 572 cr.unregisterContentObserver(this); 573 } 574 } 575 576 @Override 577 public void onChange(boolean selfChange, Uri uri) { 578 super.onChange(selfChange, uri); 579 if (VIBRATE_WHEN_RINGING_URI.equals(uri)) { 580 updateVibrateWhenRinging(); 581 } 582 if (NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 583 updatePulse(); 584 } 585 if (LOCK_SCREEN_PRIVATE_URI.equals(uri) || LOCK_SCREEN_SHOW_URI.equals(uri)) { 586 updateLockscreenNotifications(); 587 } 588 } 589 } 590 591 private final class H extends Handler { 592 private static final int UPDATE_PHONE_RINGTONE = 1; 593 private static final int UPDATE_NOTIFICATION_RINGTONE = 2; 594 private static final int STOP_SAMPLE = 3; 595 private static final int UPDATE_EFFECTS_SUPPRESSOR = 4; 596 private static final int UPDATE_RINGER_MODE = 5; 597 598 private H() { 599 super(Looper.getMainLooper()); 600 } 601 602 @Override 603 public void handleMessage(Message msg) { 604 switch (msg.what) { 605 case UPDATE_PHONE_RINGTONE: 606 mPhoneRingtonePreference.setSummary((CharSequence) msg.obj); 607 break; 608 case UPDATE_NOTIFICATION_RINGTONE: 609 mNotificationRingtonePreference.setSummary((CharSequence) msg.obj); 610 break; 611 case STOP_SAMPLE: 612 mVolumeCallback.stopSample(); 613 break; 614 case UPDATE_EFFECTS_SUPPRESSOR: 615 updateEffectsSuppressor(); 616 break; 617 case UPDATE_RINGER_MODE: 618 updateRingerMode(); 619 break; 620 } 621 } 622 } 623 624 private class Receiver extends BroadcastReceiver { 625 private boolean mRegistered; 626 627 public void register(boolean register) { 628 if (mRegistered == register) return; 629 if (register) { 630 final IntentFilter filter = new IntentFilter(); 631 filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 632 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION); 633 mContext.registerReceiver(this, filter); 634 } else { 635 mContext.unregisterReceiver(this); 636 } 637 mRegistered = register; 638 } 639 640 @Override 641 public void onReceive(Context context, Intent intent) { 642 final String action = intent.getAction(); 643 if (NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED.equals(action)) { 644 mHandler.sendEmptyMessage(H.UPDATE_EFFECTS_SUPPRESSOR); 645 } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { 646 mHandler.sendEmptyMessage(H.UPDATE_RINGER_MODE); 647 } 648 } 649 } 650 651 // === Indexing === 652 653 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 654 new BaseSearchIndexProvider() { 655 656 public List<SearchIndexableResource> getXmlResourcesToIndex( 657 Context context, boolean enabled) { 658 final SearchIndexableResource sir = new SearchIndexableResource(context); 659 sir.xmlResId = R.xml.notification_settings; 660 return Arrays.asList(sir); 661 } 662 663 public List<String> getNonIndexableKeys(Context context) { 664 final ArrayList<String> rt = new ArrayList<String>(); 665 if (Utils.isVoiceCapable(context)) { 666 rt.add(KEY_NOTIFICATION_VOLUME); 667 } else { 668 rt.add(KEY_RING_VOLUME); 669 rt.add(KEY_PHONE_RINGTONE); 670 rt.add(KEY_WIFI_DISPLAY); 671 rt.add(KEY_VIBRATE_WHEN_RINGING); 672 } 673 return rt; 674 } 675 }; 676 } 677