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