VolumeZen: Sound & Notifications settings.

- Add sound settings under the newly combined Sound & Notifications
  top-level settings page.
- New slider preferences for setting audio stream volumes.
- Migrate checkbox prefs to switch prefs.
- New settings subpage for touch sounds.
- New settings subpage for "Showing notifications"
- New setting pref for displaying intercepted notifications in zen mode.
- New tri-state lockscreen notifications pref.
- Add priority + sensitivity options to app notification dialog.
- Remove badges on app notifications row, migrate to subtitle text.
- Migrate strings to common spot in strings.xml
- Remove heads up setting.
- Remove tweaks category (unused).
- Clean up notification settings, separate out into a code section per option.
- Clean up _settings.xml files, prefix each pref with option name.
- Add appropriate indexing data to each settings page.

Depends on f/b change Ic30aa575ae07650cee62c8c1d83b6bc69395cf0d

Change-Id: If700385a7d0057f6c4c4bcf6e648dcf88b8ebff2
diff --git a/src/com/android/settings/RingerVolumePreference.java b/src/com/android/settings/RingerVolumePreference.java
index dd81ded..0f28e06 100644
--- a/src/com/android/settings/RingerVolumePreference.java
+++ b/src/com/android/settings/RingerVolumePreference.java
@@ -34,6 +34,7 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.preference.SeekBarVolumizer;
 import android.preference.VolumePreference;
 import android.provider.Settings;
 import android.provider.Settings.System;
@@ -173,10 +174,10 @@
             mSeekBars[i] = seekBar;
             if (SEEKBAR_TYPE[i] == AudioManager.STREAM_MUSIC) {
                 mSeekBarVolumizer[i] = new SeekBarVolumizer(getContext(), seekBar,
-                        SEEKBAR_TYPE[i], getMediaVolumeUri(getContext()));
+                        SEEKBAR_TYPE[i], getMediaVolumeUri(getContext()), this);
             } else {
                 mSeekBarVolumizer[i] = new SeekBarVolumizer(getContext(), seekBar,
-                        SEEKBAR_TYPE[i]);
+                        SEEKBAR_TYPE[i], null, this);
             }
         }
 
@@ -275,7 +276,7 @@
     }
 
     @Override
-    protected void onSampleStarting(SeekBarVolumizer volumizer) {
+    public void onSampleStarting(SeekBarVolumizer volumizer) {
         super.onSampleStarting(volumizer);
         for (SeekBarVolumizer vol : mSeekBarVolumizer) {
             if (vol != null && vol != volumizer) vol.stopSample();
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 25378086..38176eb 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -88,6 +88,9 @@
     public static class PrintJobSettingsActivity extends SettingsActivity { /* empty */ }
     public static class ZenModeSettingsActivity extends SettingsActivity { /* empty */ }
     public static class NotificationSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class NotificationDisplaySettingsActivity extends SettingsActivity { /* empty */ }
+    public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class TouchSoundSettingsActivity extends SettingsActivity { /* empty */ }
 
     public static class TopLevelSettings extends SettingsActivity { /* empty */ }
 }
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index c63ae63..1cae805 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -29,11 +29,8 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
-import android.graphics.Paint;
-import android.graphics.Path;
+import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.PathShape;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -57,6 +54,9 @@
 import android.widget.TextView;
 
 import com.android.settings.R;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
 
 import java.text.Collator;
 import java.util.ArrayList;
@@ -64,7 +64,7 @@
 import java.util.Comparator;
 import java.util.List;
 
-public class AppNotificationSettings extends ListFragment {
+public class AppNotificationSettings extends ListFragment implements Indexable {
     private static final String TAG = "AppNotificationSettings";
     private static final boolean DEBUG = true;
 
@@ -187,6 +187,9 @@
         final TextView title = (TextView) layout.findViewById(android.R.id.title);
         title.setText(row.label);
         final CheckBox showBox = (CheckBox) layout.findViewById(android.R.id.button1);
+        final CheckBox priBox = (CheckBox) layout.findViewById(android.R.id.button2);
+        final CheckBox senBox = (CheckBox) layout.findViewById(android.R.id.button3);
+
         showBox.setChecked(!row.banned);
         final OnCheckedChangeListener showListener = new OnCheckedChangeListener() {
             @Override
@@ -195,6 +198,8 @@
                 if (success) {
                     row.banned = !isChecked;
                     mAdapter.bindView(v, row, true /*animate*/);
+                    priBox.setEnabled(!row.banned);
+                    senBox.setEnabled(!row.banned);
                 } else {
                     showBox.setOnCheckedChangeListener(null);
                     showBox.setChecked(!isChecked);
@@ -203,6 +208,44 @@
             }
         };
         showBox.setOnCheckedChangeListener(showListener);
+
+        priBox.setChecked(row.priority);
+        final OnCheckedChangeListener priListener = new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                boolean success = mBackend.setHighPriority(row.pkg, row.uid, isChecked);
+                if (success) {
+                    row.priority = isChecked;
+                    mAdapter.bindView(v, row, true /*animate*/);
+                } else {
+                    priBox.setOnCheckedChangeListener(null);
+                    priBox.setChecked(!isChecked);
+                    priBox.setOnCheckedChangeListener(this);
+                }
+            }
+        };
+        priBox.setOnCheckedChangeListener(priListener);
+
+        senBox.setChecked(row.sensitive);
+        final OnCheckedChangeListener senListener = new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                boolean success = mBackend.setSensitive(row.pkg, row.uid, isChecked);
+                if (success) {
+                    row.sensitive = isChecked;
+                    mAdapter.bindView(v, row, true /*animate*/);
+                } else {
+                    senBox.setOnCheckedChangeListener(null);
+                    senBox.setChecked(!isChecked);
+                    senBox.setOnCheckedChangeListener(this);
+                }
+            }
+        };
+        senBox.setOnCheckedChangeListener(senListener);
+
+        priBox.setEnabled(!row.banned);
+        senBox.setEnabled(!row.banned);
+
         final AlertDialog d = new AlertDialog.Builder(mContext)
             .setView(layout)
             .setPositiveButton(R.string.app_notifications_dialog_done, null)
@@ -214,48 +257,16 @@
         ViewGroup row;
         ViewGroup appButton;
         ImageView icon;
-        ImageView banBadge;
-        ImageView priBadge;
         TextView title;
+        TextView subtitle;
         View settingsDivider;
         ImageView settingsButton;
         View rowDivider;
     }
 
     private class NotificationAppAdapter extends ArrayAdapter<Row> implements SectionIndexer {
-        private final ShapeDrawable mBanShape, mPriShape;
-
         public NotificationAppAdapter(Context context) {
             super(context, 0, 0);
-            final int s = context.getResources()
-                    .getDimensionPixelSize(R.dimen.notification_app_icon_badge_size);
-            mBanShape = shape(banPath(s), s);
-            mPriShape = shape(priPath(s), s);
-        }
-
-        private ShapeDrawable shape(Path path, int s) {
-            final ShapeDrawable sd = new ShapeDrawable(new PathShape(path, s, s));
-            sd.getPaint().setStyle(Paint.Style.STROKE);
-            sd.getPaint().setColor(0xffffffff);
-            sd.getPaint().setStrokeWidth(s / 12);
-            sd.setIntrinsicWidth(s);
-            sd.setIntrinsicHeight(s);
-            return sd;
-        }
-
-        private Path banPath(int s) {
-            final Path p = new Path();
-            final int d = s / 5;
-            p.moveTo(d, d); p.lineTo(s - d, s - d);
-            p.moveTo(d, s - d); p.lineTo(s - d, d);
-            return p;
-        }
-
-        private Path priPath(int s) {
-            final Path p = new Path();
-            final int d = s / 5;
-            p.moveTo(s / 2, d); p.lineTo(s / 2, s - d);
-            return p;
         }
 
         @Override
@@ -302,11 +313,8 @@
             vh.appButton = (ViewGroup) v.findViewById(android.R.id.button1);
             vh.appButton.setLayoutTransition(new LayoutTransition());
             vh.icon = (ImageView) v.findViewById(android.R.id.icon);
-            vh.banBadge = (ImageView) v.findViewById(android.R.id.icon1);
-            vh.banBadge.setImageDrawable(mBanShape);
-            vh.priBadge = (ImageView) v.findViewById(android.R.id.icon2);
-            vh.priBadge.setImageDrawable(mPriShape);
             vh.title = (TextView) v.findViewById(android.R.id.title);
+            vh.subtitle = (TextView) v.findViewById(android.R.id.text1);
             vh.settingsDivider = v.findViewById(R.id.settings_divider);
             vh.settingsButton = (ImageView) v.findViewById(android.R.id.button2);
             vh.rowDivider = v.findViewById(R.id.row_divider);
@@ -326,6 +334,7 @@
 
         public void bindView(final View view, Row r, boolean animate) {
             if (!(r instanceof AppRow)) {
+                // it's a section row
                 TextView tv = (TextView)view;
                 tv.setText(r.section);
                 return;
@@ -343,9 +352,10 @@
             });
             enableLayoutTransitions(vh.appButton, animate);
             vh.icon.setImageDrawable(row.icon);
-            vh.banBadge.setVisibility(row.banned ? View.VISIBLE : View.GONE);
-            vh.priBadge.setVisibility(row.priority ? View.VISIBLE : View.GONE);
             vh.title.setText(row.label);
+            final String sub = getSubtitle(row);
+            vh.subtitle.setText(sub);
+            vh.subtitle.setVisibility(!sub.isEmpty() ? View.VISIBLE : View.GONE);
             final boolean showSettings = !row.banned && row.settingsIntent != null;
             vh.settingsDivider.setVisibility(showSettings ? View.VISIBLE : View.GONE);
             vh.settingsButton.setVisibility(showSettings ? View.VISIBLE : View.GONE);
@@ -359,6 +369,17 @@
             });
         }
 
+        private String getSubtitle(AppRow row) {
+            if (row.banned) return mContext.getString(R.string.app_notification_row_banned);
+            if (!row.priority && !row.sensitive) return "";
+            final String priString = mContext.getString(R.string.app_notification_row_priority);
+            final String senString = mContext.getString(R.string.app_notification_row_sensitive);
+            if (row.priority != row.sensitive) {
+                return row.priority ? priString : senString;
+            }
+            return priString + mContext.getString(R.string.summary_divider_text) + senString;
+        }
+
         @Override
         public Object[] getSections() {
             return mSections.toArray(new Object[mSections.size()]);
@@ -396,7 +417,8 @@
         public Intent settingsIntent;
         public boolean banned;
         public boolean priority;
-        public boolean first;
+        public boolean sensitive;
+        public boolean first;  // first app in section
     }
 
     private static final Comparator<AppRow> mRowComparator = new Comparator<AppRow>() {
@@ -435,6 +457,7 @@
                     row.icon = pkg.applicationInfo.loadIcon(pm);
                     row.banned = mBackend.getNotificationsBanned(row.pkg, row.uid);
                     row.priority = mBackend.getHighPriority(row.pkg, row.uid);
+                    row.sensitive = mBackend.getSensitive(row.pkg, row.uid);
                     mRows.put(row.pkg, row);
                 }
                 // collect config activities
@@ -552,5 +575,38 @@
             // TODO save high-pri state to NoMan
             return true;
         }
+
+        public boolean getSensitive(String pkg, int uid) {
+            // TODO get visibility state from NoMan
+            return false;
+        }
+
+        public boolean setSensitive(String pkg, int uid, boolean sensitive) {
+            // TODO save visibility state to NoMan
+            return true;
+        }
     }
+
+    // === Indexing ===
+
+    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+        new BaseSearchIndexProvider() {
+            @Override
+            public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+                final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
+                add(result, context, R.string.app_notifications_title);
+                add(result, context, R.string.app_notifications_dialog_show);
+                add(result, context, R.string.app_notifications_dialog_priority);
+                add(result, context, R.string.app_notifications_dialog_visibility);
+                return result;
+            }
+
+            private void add(List<SearchIndexableRaw> result, Context context, int title) {
+                final Resources res = context.getResources();
+                final SearchIndexableRaw data = new SearchIndexableRaw(context);
+                data.title = res.getString(title);
+                data.screenTitle = res.getString(R.string.app_notifications_title);
+                result.add(data);
+            }
+        };
 }
diff --git a/src/com/android/settings/notification/NotificationDisplaySettings.java b/src/com/android/settings/notification/NotificationDisplaySettings.java
new file mode 100644
index 0000000..8c492e2
--- /dev/null
+++ b/src/com/android/settings/notification/NotificationDisplaySettings.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
+import android.preference.TwoStatePreference;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NotificationDisplaySettings extends SettingsPreferenceFragment implements Indexable {
+    private static final String TAG = "NotificationDisplaySettings";
+
+    private static final String KEY_NOTIFICATION_PULSE = "notification_pulse";
+    private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "lock_screen_notifications";
+    private static final String KEY_ZEN_MODE_NOTIFICATIONS = "zen_mode_notifications";
+
+    private final Handler mHandler = new Handler();
+    private final SettingsObserver mSettingsObserver = new SettingsObserver();
+
+    private TwoStatePreference mNotificationPulse;
+    private DropDownPreference mLockscreen;
+    private DropDownPreference mZenModeNotifications;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        addPreferencesFromResource(R.xml.notification_display_settings);
+
+        final PreferenceScreen root = getPreferenceScreen();
+        initPulse(root);
+        initLockscreenNotifications(root);
+        initZenModeNotifications(root);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mSettingsObserver.register(true);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mSettingsObserver.register(false);
+    }
+
+    // === Pulse notification light ===
+
+    private void initPulse(PreferenceScreen parent) {
+        mNotificationPulse = (TwoStatePreference) parent.findPreference(KEY_NOTIFICATION_PULSE);
+        if (mNotificationPulse == null) return;
+        if (!getResources()
+                .getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed)) {
+            parent.removePreference(mNotificationPulse);
+        } else {
+            updatePulse();
+            mNotificationPulse.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+                @Override
+                public boolean onPreferenceChange(Preference preference, Object newValue) {
+                    final boolean val = (Boolean)newValue;
+                    return Settings.System.putInt(getContentResolver(),
+                            Settings.System.NOTIFICATION_LIGHT_PULSE,
+                            val ? 1 : 0);
+                }
+            });
+        }
+    }
+
+    private void updatePulse() {
+        if (mNotificationPulse == null) return;
+        try {
+            mNotificationPulse.setChecked(Settings.System.getInt(getContentResolver(),
+                    Settings.System.NOTIFICATION_LIGHT_PULSE) == 1);
+        } catch (Settings.SettingNotFoundException snfe) {
+            Log.e(TAG, Settings.System.NOTIFICATION_LIGHT_PULSE + " not found");
+        }
+    }
+
+    // === Lockscreen (public / private) notifications ===
+
+    private void initLockscreenNotifications(PreferenceScreen parent) {
+        mLockscreen = (DropDownPreference) parent.findPreference(KEY_LOCK_SCREEN_NOTIFICATIONS);
+        if (mLockscreen == null) return;
+        mLockscreen.addItem(R.string.lock_screen_notifications_summary_show,
+                R.string.lock_screen_notifications_summary_show);
+        mLockscreen.addItem(R.string.lock_screen_notifications_summary_hide,
+                R.string.lock_screen_notifications_summary_hide);
+        mLockscreen.addItem(R.string.lock_screen_notifications_summary_disable,
+                R.string.lock_screen_notifications_summary_disable);
+        updateLockscreenNotifications();
+        mLockscreen.setCallback(new DropDownPreference.Callback() {
+            @Override
+            public boolean onItemSelected(int pos, Object value) {
+                final int val = (Integer) value;
+                final boolean enabled = val != R.string.lock_screen_notifications_summary_disable;
+                final boolean show = val == R.string.lock_screen_notifications_summary_show;
+                Settings.Secure.putInt(getContentResolver(),
+                        Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, show ? 1 : 0);
+                Settings.Global.putInt(getContentResolver(),
+                        Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, enabled ? 1 : 0);
+                return true;
+            }
+        });
+    }
+
+    private void updateLockscreenNotifications() {
+        if (mLockscreen == null) return;
+        final boolean allowPrivate = getLockscreenAllowPrivateNotifications();
+        final boolean enabled = getLockscreenNotificationsEnabled();
+        final int val = !enabled ? R.string.lock_screen_notifications_summary_disable :
+                allowPrivate ? R.string.lock_screen_notifications_summary_show :
+                R.string.lock_screen_notifications_summary_hide;
+        mLockscreen.setSelectedValue(val);
+    }
+
+    private boolean getLockscreenNotificationsEnabled() {
+        return Settings.Global.getInt(getContentResolver(),
+                Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0;
+    }
+
+    private boolean getLockscreenAllowPrivateNotifications() {
+        return Settings.Secure.getInt(getContentResolver(),
+                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0;
+    }
+
+    // === Zen mode notifications ===
+
+    private void initZenModeNotifications(PreferenceScreen parent) {
+        mZenModeNotifications = (DropDownPreference)
+                parent.findPreference(KEY_ZEN_MODE_NOTIFICATIONS);
+        if (mZenModeNotifications == null) return;
+        mZenModeNotifications.addItem(R.string.zen_mode_notifications_summary_hide, 0);
+        mZenModeNotifications.addItem(R.string.zen_mode_notifications_summary_show, 1);
+        updateZenModeNotifications();
+        mZenModeNotifications.setCallback(new DropDownPreference.Callback() {
+            @Override
+            public boolean onItemSelected(int pos, Object value) {
+                final int val = (Integer) value;
+                Settings.Secure.putInt(getContentResolver(),
+                        Settings.Secure.DISPLAY_INTERCEPTED_NOTIFICATIONS, val);
+                return true;
+            }
+        });
+    }
+
+    private void updateZenModeNotifications() {
+        if (mZenModeNotifications == null) return;
+        mZenModeNotifications.setSelectedValue(Settings.Secure.getInt(getContentResolver(),
+                Settings.Secure.DISPLAY_INTERCEPTED_NOTIFICATIONS, 0));
+    }
+
+    // === Indexing ===
+
+    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+        new BaseSearchIndexProvider() {
+            @Override
+            public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+                final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
+                add(result, context, R.string.notification_display_settings);
+                add(result, context, R.string.notification_pulse_title);
+                add(result, context, R.string.lock_screen_notifications_title);
+                add(result, context, R.string.zen_mode_notifications_title);
+                return result;
+            }
+
+            private void add(List<SearchIndexableRaw> result, Context context, int title) {
+                final Resources res = context.getResources();
+                final SearchIndexableRaw data = new SearchIndexableRaw(context);
+                data.title = res.getString(title);
+                data.screenTitle = res.getString(R.string.notification_display_settings);
+                result.add(data);
+            }
+        };
+
+    // === Callbacks ===
+
+    private final class SettingsObserver extends ContentObserver {
+        private final Uri NOTIFICATION_LIGHT_PULSE_URI =
+                Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
+        private final Uri LOCK_SCREEN_PRIVATE_URI =
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
+        private final Uri LOCK_SCREEN_SHOW_URI =
+                Settings.Global.getUriFor(Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS);
+        private final Uri DISPLAY_INTERCEPTED_NOTIFICATIONS_URI =
+                Settings.Secure.getUriFor(Settings.Secure.DISPLAY_INTERCEPTED_NOTIFICATIONS);
+
+        public SettingsObserver() {
+            super(mHandler);
+        }
+
+        public void register(boolean register) {
+            final ContentResolver cr = getContentResolver();
+            if (register) {
+                cr.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, false, this);
+                cr.registerContentObserver(LOCK_SCREEN_PRIVATE_URI, false, this);
+                cr.registerContentObserver(LOCK_SCREEN_SHOW_URI, false, this);
+                cr.registerContentObserver(DISPLAY_INTERCEPTED_NOTIFICATIONS_URI, false, this);
+            } else {
+                cr.unregisterContentObserver(this);
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            if (NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
+                updatePulse();
+            }
+            if (LOCK_SCREEN_PRIVATE_URI.equals(uri) || LOCK_SCREEN_SHOW_URI.equals(uri)) {
+                updateLockscreenNotifications();
+            }
+            if (DISPLAY_INTERCEPTED_NOTIFICATIONS_URI.equals(uri)) {
+                updateZenModeNotifications();
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/notification/NotificationSettings.java b/src/com/android/settings/notification/NotificationSettings.java
index d432bed..61df419 100644
--- a/src/com/android/settings/notification/NotificationSettings.java
+++ b/src/com/android/settings/notification/NotificationSettings.java
@@ -16,209 +16,212 @@
 
 package com.android.settings.notification;
 
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.media.AudioManager;
 import android.media.RingtoneManager;
-import android.os.Build;
+import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.preference.Preference;
-import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceGroup;
+import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.PreferenceScreen;
+import android.preference.SeekBarVolumizer;
 import android.preference.TwoStatePreference;
 import android.provider.Settings;
-import android.util.Log;
 
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.SoundSettings;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
 
-public class NotificationSettings extends SettingsPreferenceFragment implements
-        Preference.OnPreferenceChangeListener, OnPreferenceClickListener {
+import java.util.ArrayList;
+import java.util.List;
+
+public class NotificationSettings extends SettingsPreferenceFragment implements Indexable {
     private static final String TAG = "NotificationSettings";
 
-    private static final String KEY_NOTIFICATION_SOUND = "notification_sound";
-    private static final String KEY_NOTIFICATION_PULSE = "notification_pulse";
-    private static final String KEY_HEADS_UP = "heads_up";
-    private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "toggle_lock_screen_notifications";
+    private static final String KEY_MEDIA_VOLUME = "media_volume";
+    private static final String KEY_ALARM_VOLUME = "alarm_volume";
+    private static final String KEY_RING_VOLUME = "ring_volume";
+    private static final String KEY_RINGER_MODE = "ringer_mode";
+    private static final String KEY_PHONE_RINGTONE = "ringtone";
+    private static final String KEY_NOTIFICATION_RINGTONE = "notification_ringtone";
+    private static final String KEY_VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
     private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access";
 
-    private static final String KEY_TWEAKS_CATEGORY = "category_tweaks"; // power toys, eng only
+    private static final int SAMPLE_CUTOFF = 2000;  // manually cap sample playback at 2 seconds
 
-    private static final int MSG_UPDATE_SOUND_SUMMARY = 2;
+    private final VolumePreferenceCallback mVolumeCallback = new VolumePreferenceCallback();
+    private final H mHandler = new H();
+    private final SettingsObserver mSettingsObserver = new SettingsObserver();
 
     private Context mContext;
     private PackageManager mPM;
 
-    private Preference mNotificationSoundPreference;
+    private DropDownPreference mRingerMode;
+    private Preference mPhoneRingtonePreference;
+    private Preference mNotificationRingtonePreference;
+    private TwoStatePreference mVibrateWhenRinging;
     private Preference mNotificationAccess;
-    private DropDownPreference mLockscreen;
-    private TwoStatePreference mHeadsUp;
-    private TwoStatePreference mNotificationPulse;
-
-    private final Runnable mRingtoneLookupRunnable = new Runnable() {
-        @Override
-        public void run() {
-            if (mNotificationSoundPreference != null) {
-                final CharSequence summary = SoundSettings.updateRingtoneName(
-                        mContext, RingtoneManager.TYPE_NOTIFICATION);
-                if (summary != null) {
-                    mHandler.sendMessage(
-                            mHandler.obtainMessage(MSG_UPDATE_SOUND_SUMMARY, summary));
-                }
-            }
-        }
-    };
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_UPDATE_SOUND_SUMMARY:
-                    mNotificationSoundPreference.setSummary((CharSequence) msg.obj);
-                    break;
-            }
-        }
-    };
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mContext = getActivity();
-        final ContentResolver resolver = mContext.getContentResolver();
-
         mPM = mContext.getPackageManager();
 
         addPreferencesFromResource(R.xml.notification_settings);
 
         final PreferenceScreen root = getPreferenceScreen();
-
-        PreferenceGroup tweaksCategory = (PreferenceGroup)
-                root.findPreference(KEY_TWEAKS_CATEGORY);
-
-        if (tweaksCategory != null
-                && !(Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug"))) {
-            root.removePreference(tweaksCategory);
-            tweaksCategory = null;
-        }
-
-        mNotificationSoundPreference = findPreference(KEY_NOTIFICATION_SOUND);
+        initVolumePreference(KEY_MEDIA_VOLUME, AudioManager.STREAM_MUSIC);
+        initVolumePreference(KEY_ALARM_VOLUME, AudioManager.STREAM_ALARM);
+        initVolumePreference(KEY_RING_VOLUME, AudioManager.STREAM_RING);
+        initRingerMode(root);
+        initRingtones(root);
+        initVibrateWhenRinging(root);
 
         mNotificationAccess = findPreference(KEY_NOTIFICATION_ACCESS);
         refreshNotificationListeners();
-
-        mLockscreen = (DropDownPreference) root.findPreference(KEY_LOCK_SCREEN_NOTIFICATIONS);
-        if (mLockscreen != null) {
-            if (!getDeviceLockscreenNotificationsEnabled()) {
-                root.removePreference(mLockscreen);
-            } else {
-                mLockscreen.addItem(R.string.lock_screen_notifications_summary_show, 1);
-                mLockscreen.addItem(R.string.lock_screen_notifications_summary_hide, 0);
-                final int val = getLockscreenAllowPrivateNotifications() ? 1 : 0;
-                mLockscreen.setSelectedValue(val);
-                mLockscreen.setCallback(new DropDownPreference.Callback() {
-                    @Override
-                    public boolean onItemSelected(int pos, Object value) {
-                        final int val = (Integer) value;
-                        Settings.Secure.putInt(getContentResolver(),
-                                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, val);
-                        return true;
-                    }
-                });
-            }
-        }
-
-        mHeadsUp = (TwoStatePreference) findPreference(KEY_HEADS_UP);
-        if (mHeadsUp != null) {
-            updateHeadsUpMode(resolver);
-            mHeadsUp.setOnPreferenceChangeListener(this);
-            resolver.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED),
-                    false, new ContentObserver(mHandler) {
-                @Override
-                public void onChange(boolean selfChange) {
-                    updateHeadsUpMode(resolver);
-                }
-            });
-        }
-        mNotificationPulse = (TwoStatePreference) findPreference(KEY_NOTIFICATION_PULSE);
-
-        if (mNotificationPulse != null
-                && getResources().getBoolean(
-                com.android.internal.R.bool.config_intrusiveNotificationLed) == false) {
-            getPreferenceScreen().removePreference(mNotificationPulse);
-        } else {
-            try {
-                mNotificationPulse.setChecked(Settings.System.getInt(resolver,
-                        Settings.System.NOTIFICATION_LIGHT_PULSE) == 1);
-                mNotificationPulse.setOnPreferenceChangeListener(this);
-            } catch (Settings.SettingNotFoundException snfe) {
-                Log.e(TAG, Settings.System.NOTIFICATION_LIGHT_PULSE + " not found");
-            }
-        }
     }
 
     @Override
     public void onResume() {
         super.onResume();
-
         refreshNotificationListeners();
         lookupRingtoneNames();
+        final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+        mContext.registerReceiver(mReceiver, filter);
+        mSettingsObserver.register(true);
     }
 
     @Override
-    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
-        final String key = preference.getKey();
+    public void onPause() {
+        super.onPause();
+        mVolumeCallback.stopSample();
+        mContext.unregisterReceiver(mReceiver);
+        mSettingsObserver.register(false);
+    }
 
-        if (KEY_HEADS_UP.equals(key)) {
-            setHeadsUpMode(getContentResolver(), mHeadsUp.isChecked());
-        } else if (KEY_NOTIFICATION_PULSE.equals(key)) {
-            Settings.System.putInt(getContentResolver(),
-                    Settings.System.NOTIFICATION_LIGHT_PULSE,
-                    mNotificationPulse.isChecked() ? 1 : 0);
-        } else {
-            return super.onPreferenceTreeClick(preferenceScreen, preference);
+    // === Volumes ===
+
+    private void initVolumePreference(String key, int stream) {
+        final VolumeSeekBarPreference volumePref = (VolumeSeekBarPreference) findPreference(key);
+        volumePref.setStream(stream);
+        volumePref.setCallback(mVolumeCallback);
+    }
+
+    private final class VolumePreferenceCallback implements VolumeSeekBarPreference.Callback {
+        private SeekBarVolumizer mCurrent;
+
+        @Override
+        public void onSampleStarting(SeekBarVolumizer sbv) {
+            if (mCurrent != null && mCurrent != sbv) {
+                mCurrent.stopSample();
+            }
+            mCurrent = sbv;
+            if (mCurrent != null) {
+                mHandler.removeMessages(H.STOP_SAMPLE);
+                mHandler.sendEmptyMessageDelayed(H.STOP_SAMPLE, SAMPLE_CUTOFF);
+            }
         }
 
-        return true;
+        public void stopSample() {
+            if (mCurrent != null) {
+                mCurrent.stopSample();
+            }
+        }
+    };
+
+    // === Ringer mode ===
+
+    private void initRingerMode(PreferenceScreen root) {
+        mRingerMode = (DropDownPreference) root.findPreference(KEY_RINGER_MODE);
+        if (mRingerMode == null) return;
+        final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        mRingerMode.addItem(R.string.ringer_mode_audible, AudioManager.RINGER_MODE_NORMAL);
+        mRingerMode.addItem(R.string.ringer_mode_vibrate, AudioManager.RINGER_MODE_VIBRATE);
+        mRingerMode.addItem(R.string.ringer_mode_silent, AudioManager.RINGER_MODE_SILENT);
+        updateRingerMode();
+        mRingerMode.setCallback(new DropDownPreference.Callback() {
+            @Override
+            public boolean onItemSelected(int pos, Object value) {
+                final int val = (Integer) value;
+                am.setRingerMode(val);
+                return true;
+            }
+        });
     }
 
-    @Override
-    public boolean onPreferenceChange(Preference preference, Object objValue) {
-        return true;
+    private void updateRingerMode() {
+        final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        mRingerMode.setSelectedValue(am.getRingerMode());
     }
 
-    @Override
-    public boolean onPreferenceClick(Preference preference) {
-        return false;
+    // === Phone & notification ringtone ===
+
+    private void initRingtones(PreferenceScreen root) {
+        mPhoneRingtonePreference = root.findPreference(KEY_PHONE_RINGTONE);
+        mNotificationRingtonePreference = root.findPreference(KEY_NOTIFICATION_RINGTONE);
     }
 
-    // === Heads-up notifications ===
-
-    private void updateHeadsUpMode(ContentResolver resolver) {
-        mHeadsUp.setChecked(Settings.Global.HEADS_UP_ON == Settings.Global.getInt(resolver,
-                Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, Settings.Global.HEADS_UP_OFF));
+    private void lookupRingtoneNames() {
+        AsyncTask.execute(mLookupRingtoneNames);
     }
 
-    private void setHeadsUpMode(ContentResolver resolver, boolean value) {
-        Settings.Global.putInt(resolver, Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
-                value ? Settings.Global.HEADS_UP_ON : Settings.Global.HEADS_UP_OFF);
+    private final Runnable mLookupRingtoneNames = new Runnable() {
+        @Override
+        public void run() {
+            if (mPhoneRingtonePreference != null) {
+                final CharSequence summary = SoundSettings.updateRingtoneName(
+                        mContext, RingtoneManager.TYPE_RINGTONE);
+                if (summary != null) {
+                    mHandler.obtainMessage(H.UPDATE_PHONE_RINGTONE, summary).sendToTarget();
+                }
+            }
+            if (mNotificationRingtonePreference != null) {
+                final CharSequence summary = SoundSettings.updateRingtoneName(
+                        mContext, RingtoneManager.TYPE_NOTIFICATION);
+                if (summary != null) {
+                    mHandler.obtainMessage(H.UPDATE_NOTIFICATION_RINGTONE, summary).sendToTarget();
+                }
+            }
+        }
+    };
+
+    // === Vibrate when ringing ===
+
+    private void initVibrateWhenRinging(PreferenceScreen root) {
+        mVibrateWhenRinging = (TwoStatePreference) findPreference(KEY_VIBRATE_WHEN_RINGING);
+        if (mVibrateWhenRinging == null) return;
+        mVibrateWhenRinging.setPersistent(false);
+        updateVibrateWhenRinging();
+        mVibrateWhenRinging.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+            @Override
+            public boolean onPreferenceChange(Preference preference, Object newValue) {
+                final boolean val = (Boolean) newValue;
+                return Settings.System.putInt(getContentResolver(),
+                        Settings.System.VIBRATE_WHEN_RINGING,
+                        val ? 1 : 0);
+            }
+        });
     }
 
-    // === Lockscreen (public / private) notifications ===
-
-    private boolean getDeviceLockscreenNotificationsEnabled() {
-        return 0 != Settings.Global.getInt(getContentResolver(),
-                Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
-    }
-
-    private boolean getLockscreenAllowPrivateNotifications() {
-        return 0 != Settings.Secure.getInt(getContentResolver(),
-                Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
+    private void updateVibrateWhenRinging() {
+        if (mVibrateWhenRinging == null) return;
+        mVibrateWhenRinging.setChecked(Settings.System.getInt(getContentResolver(),
+                Settings.System.VIBRATE_WHEN_RINGING, 0) != 0);
     }
 
     // === Notification listeners ===
@@ -242,9 +245,92 @@
         }
     }
 
-    // === Ringtone ===
+    // === Indexing ===
 
-    private void lookupRingtoneNames() {
-        new Thread(mRingtoneLookupRunnable).start();
+    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+        new BaseSearchIndexProvider() {
+            @Override
+            public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+                final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
+                add(result, context, R.string.notification_settings);
+                add(result, context, R.string.media_volume_option_title);
+                add(result, context, R.string.alarm_volume_option_title);
+                add(result, context, R.string.ring_volume_option_title);
+                add(result, context, R.string.ringer_mode_title);
+                add(result, context, R.string.ringtone_title);
+                add(result, context, R.string.vibrate_when_ringing_title);
+                add(result, context, R.string.manage_notification_access_title);
+                return result;
+            }
+
+            private void add(List<SearchIndexableRaw> result, Context context, int title) {
+                final Resources res = context.getResources();
+                final SearchIndexableRaw data = new SearchIndexableRaw(context);
+                data.title = res.getString(title);
+                data.screenTitle = res.getString(R.string.notification_settings);
+                result.add(data);
+            }
+        };
+
+    // === Callbacks ===
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
+                updateRingerMode();
+            }
+        }
+    };
+
+    private final class SettingsObserver extends ContentObserver {
+        private final Uri VIBRATE_WHEN_RINGING_URI =
+                Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING);
+
+        public SettingsObserver() {
+            super(mHandler);
+        }
+
+        public void register(boolean register) {
+            final ContentResolver cr = getContentResolver();
+            if (register) {
+                cr.registerContentObserver(VIBRATE_WHEN_RINGING_URI, false, this);
+            } else {
+                cr.unregisterContentObserver(this);
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            if (VIBRATE_WHEN_RINGING_URI.equals(uri)) {
+                updateVibrateWhenRinging();
+            }
+        }
+    }
+
+    private final class H extends Handler {
+        private static final int UPDATE_PHONE_RINGTONE = 1;
+        private static final int UPDATE_NOTIFICATION_RINGTONE = 2;
+        private static final int STOP_SAMPLE = 3;
+
+        private H() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case UPDATE_PHONE_RINGTONE:
+                    mPhoneRingtonePreference.setSummary((CharSequence) msg.obj);
+                    break;
+                case UPDATE_NOTIFICATION_RINGTONE:
+                    mNotificationRingtonePreference.setSummary((CharSequence) msg.obj);
+                    break;
+                case STOP_SAMPLE:
+                    mVolumeCallback.stopSample();
+                    break;
+            }
+        }
     }
 }
diff --git a/src/com/android/settings/notification/TouchSoundSettings.java b/src/com/android/settings/notification/TouchSoundSettings.java
new file mode 100644
index 0000000..fe122d3
--- /dev/null
+++ b/src/com/android/settings/notification/TouchSoundSettings.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Vibrator;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
+import android.preference.TwoStatePreference;
+import android.provider.Settings.System;
+import android.util.Log;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TouchSoundSettings extends SettingsPreferenceFragment implements Indexable {
+    private static final String TAG = "TouchSoundSettings";
+
+    private static final String KEY_DIAL_PAD_TONES = "dial_pad_tones";
+    private static final String KEY_SCREEN_LOCKING_SOUNDS = "screen_locking_sounds";
+    private static final String KEY_OTHER_TOUCH_SOUNDS = "other_touch_sounds";
+    private static final String KEY_VIBRATE_ON_TOUCH = "vibrate_on_touch";
+
+    private final Handler mHandler = new Handler();
+    private final SettingsObserver mSettingsObserver = new SettingsObserver();
+
+    private AudioManager mAudioManager;
+    private SystemSettingPref mDialPadTones;
+    private SystemSettingPref mScreenLockingSounds;
+    private SystemSettingPref mOtherTouchSounds;
+    private SystemSettingPref mVibrateOnTouch;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        addPreferencesFromResource(R.xml.touch_sound_settings);
+
+        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+
+        final boolean hasVoice = Utils.isVoiceCapable(getActivity());
+        final Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+        final boolean hasHaptic = vibrator != null && vibrator.hasVibrator();
+
+        mDialPadTones = new SystemSettingPref(hasVoice,
+                KEY_DIAL_PAD_TONES, System.DTMF_TONE_WHEN_DIALING);
+
+        mScreenLockingSounds = new SystemSettingPref(true,
+                KEY_SCREEN_LOCKING_SOUNDS, System.LOCKSCREEN_SOUNDS_ENABLED);
+
+        mOtherTouchSounds = new SystemSettingPref(true,
+                KEY_OTHER_TOUCH_SOUNDS,System.SOUND_EFFECTS_ENABLED) {
+            @Override
+            protected void setSetting(boolean value) {
+                if (value) {
+                    mAudioManager.loadSoundEffects();
+                } else {
+                    mAudioManager.unloadSoundEffects();
+                }
+                super.setSetting(value);
+            }
+        };
+
+        mVibrateOnTouch = new SystemSettingPref(hasHaptic,
+                KEY_VIBRATE_ON_TOUCH, System.HAPTIC_FEEDBACK_ENABLED);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mSettingsObserver.register(true);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mSettingsObserver.register(false);
+    }
+
+    // === Common system setting preference helper ===
+
+    private class SystemSettingPref {
+        private final String mSetting;
+        private final Uri mUri;
+
+        private TwoStatePreference mPref;
+
+        private SystemSettingPref(boolean applicable, String key, String setting) {
+            mSetting = setting;
+            mUri = System.getUriFor(mSetting);
+            if (!applicable) removePreference(key);
+            mPref = (TwoStatePreference) getPreferenceScreen().findPreference(key);
+            if (mPref == null) return;
+            update();
+            mPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+                @Override
+                public boolean onPreferenceChange(Preference preference, Object newValue) {
+                    setSetting((Boolean)newValue);
+                    return true;
+                }
+            });
+        }
+
+        protected void setSetting(boolean value) {
+            System.putInt(getContentResolver(), mSetting, value ? 1 : 0);
+        }
+
+        private Uri getUri() {
+            return mUri;
+        }
+
+        private void update() {
+            if (mPref == null) return;
+            mPref.setChecked(System.getInt(getContentResolver(), mSetting, 1) != 0);
+        }
+    }
+
+    // === Indexing ===
+
+    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+        new BaseSearchIndexProvider() {
+            @Override
+            public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+                final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
+                add(result, context, R.string.touch_sound_settings);
+                add(result, context, R.string.dial_pad_tones_title);
+                add(result, context, R.string.screen_locking_sounds_title);
+                add(result, context, R.string.other_touch_sounds_title);
+                add(result, context, R.string.vibrate_on_touch_title);
+                return result;
+            }
+
+            private void add(List<SearchIndexableRaw> result, Context context, int title) {
+                final Resources res = context.getResources();
+                final SearchIndexableRaw data = new SearchIndexableRaw(context);
+                data.title = res.getString(title);
+                data.screenTitle = res.getString(R.string.touch_sound_settings);
+                result.add(data);
+            }
+        };
+
+    // === Callbacks ===
+
+    private final class SettingsObserver extends ContentObserver {
+        public SettingsObserver() {
+            super(mHandler);
+        }
+
+        public void register(boolean register) {
+            final ContentResolver cr = getContentResolver();
+            if (register) {
+                cr.registerContentObserver(mDialPadTones.getUri(), false, this);
+                cr.registerContentObserver(mScreenLockingSounds.getUri(), false, this);
+                cr.registerContentObserver(mOtherTouchSounds.getUri(), false, this);
+                cr.registerContentObserver(mVibrateOnTouch.getUri(), false, this);
+            } else {
+                cr.unregisterContentObserver(this);
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            if (mDialPadTones.getUri().equals(uri)) {
+                mDialPadTones.update();
+            }
+            if (mScreenLockingSounds.getUri().equals(uri)) {
+                mScreenLockingSounds.update();
+            }
+            if (mOtherTouchSounds.getUri().equals(uri)) {
+                mOtherTouchSounds.update();
+            }
+            if (mVibrateOnTouch.getUri().equals(uri)) {
+                mVibrateOnTouch.update();
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/notification/VolumeSeekBarPreference.java b/src/com/android/settings/notification/VolumeSeekBarPreference.java
new file mode 100644
index 0000000..5b0621d
--- /dev/null
+++ b/src/com/android/settings/notification/VolumeSeekBarPreference.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.preference.PreferenceManager;
+import android.preference.SeekBarPreference;
+import android.preference.SeekBarVolumizer;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.SeekBar;
+
+import com.android.settings.R;
+
+/** A slider preference that directly controls an audio stream volume (no dialog) **/
+public class VolumeSeekBarPreference extends SeekBarPreference
+        implements PreferenceManager.OnActivityStopListener {
+    private static final String TAG = "VolumeSeekBarPreference";
+
+    private final Context mContext;
+
+    private int mStream;
+    private SeekBar mSeekBar;
+    private SeekBarVolumizer mVolumizer;
+    private Callback mCallback;
+
+    public VolumeSeekBarPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+    }
+
+    public void setStream(int stream) {
+        mStream = stream;
+    }
+
+    public void setCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    @Override
+    public void onActivityStop() {
+        if (mVolumizer != null) {
+            mVolumizer.stop();
+        }
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+        if (mStream == 0) {
+            Log.w(TAG, "No stream found, not binding volumizer");
+            return;
+        }
+        getPreferenceManager().registerOnActivityStopListener(this);
+        final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+        if (seekBar == mSeekBar) return;
+        mSeekBar = seekBar;
+        final SeekBarVolumizer.Callback sbvc = new SeekBarVolumizer.Callback() {
+            @Override
+            public void onSampleStarting(SeekBarVolumizer sbv) {
+                if (mCallback != null) {
+                    mCallback.onSampleStarting(sbv);
+                }
+            }
+        };
+        final Uri sampleUri = mStream == AudioManager.STREAM_MUSIC ? getMediaVolumeUri() : null;
+        mVolumizer = new SeekBarVolumizer(mContext, seekBar, mStream, sampleUri, sbvc);
+    }
+
+    private Uri getMediaVolumeUri() {
+        return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
+                + mContext.getPackageName()
+                + "/" + R.raw.media_volume);
+    }
+
+    public interface Callback {
+        void onSampleStarting(SeekBarVolumizer sbv);
+    }
+}
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index e5ffd67..f72bde0 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -329,7 +329,7 @@
             if (automatic == null || automatic.length == 0) {
                 return null;
             }
-            final String divider = getString(R.string.zen_mode_entry_conditions_summary_divider);
+            final String divider = getString(R.string.summary_divider_text);
             final StringBuilder sb = new StringBuilder();
             for (int i = 0; i < automatic.length; i++) {
                 if (i > 0) sb.append(divider);
diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java
index 80aef85..e3f004d 100644
--- a/src/com/android/settings/search/SearchIndexableResources.java
+++ b/src/com/android/settings/search/SearchIndexableResources.java
@@ -36,7 +36,10 @@
 import com.android.settings.fuelgauge.PowerUsageSummary;
 import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
 import com.android.settings.location.LocationSettings;
+import com.android.settings.notification.AppNotificationSettings;
+import com.android.settings.notification.NotificationDisplaySettings;
 import com.android.settings.notification.NotificationSettings;
+import com.android.settings.notification.TouchSoundSettings;
 import com.android.settings.notification.ZenModeSettings;
 import com.android.settings.print.PrintSettingsFragment;
 import com.android.settings.users.UserSettings;
@@ -137,12 +140,30 @@
                         NotificationSettings.class.getName(),
                         R.drawable.ic_settings_notifications));
 
+        sResMap.put(NotificationDisplaySettings.class.getName(),
+                new SearchIndexableResource(RANK_NOTIFICATIONS,
+                        R.xml.notification_display_settings,
+                        NotificationDisplaySettings.class.getName(),
+                        R.drawable.ic_settings_notifications));
+
+        sResMap.put(TouchSoundSettings.class.getName(),
+                new SearchIndexableResource(RANK_NOTIFICATIONS,
+                        R.xml.touch_sound_settings,
+                        TouchSoundSettings.class.getName(),
+                        R.drawable.ic_settings_notifications));
+
         sResMap.put(ZenModeSettings.class.getName(),
                 new SearchIndexableResource(RANK_NOTIFICATIONS,
                         NO_DATA_RES_ID,
                         ZenModeSettings.class.getName(),
                         R.drawable.ic_settings_notifications));
 
+        sResMap.put(AppNotificationSettings.class.getName(),
+                new SearchIndexableResource(RANK_NOTIFICATIONS,
+                        NO_DATA_RES_ID,
+                        AppNotificationSettings.class.getName(),
+                        R.drawable.ic_settings_notifications));
+
         sResMap.put(Memory.class.getName(),
                 new SearchIndexableResource(RANK_MEMORY,
                         NO_DATA_RES_ID,