Merge "Fix bug #14228591 NPE in settings app when it is launched by UiAutomator"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9a85dc0..4ee0b21 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -564,7 +564,7 @@
                 <category android:name="com.android.settings.SHORTCUT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
-                android:value="com.android.settings.ZenModeSettings" />
+                android:value="com.android.settings.notification.ZenModeSettings" />
             <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
                 android:resource="@id/notification_settings" />
         </activity>
@@ -772,7 +772,7 @@
                 <category android:name="com.android.settings.SHORTCUT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
-                android:value="com.android.settings.NotificationStation" />
+                android:value="com.android.settings.notification.NotificationStation" />
         </activity>
 
         <!--
@@ -1690,7 +1690,7 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
-                       android:value="com.android.settings.NotificationAccessSettings" />
+                       android:value="com.android.settings.notification.NotificationAccessSettings" />
             <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
                        android:resource="@id/security_settings" />
         </activity>
@@ -1707,7 +1707,7 @@
                 <category android:name="com.android.settings.SHORTCUT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
-                android:value="com.android.settings.NotificationSettings" />
+                android:value="com.android.settings.notification.NotificationSettings" />
             <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
                 android:resource="@id/notification_settings" />
         </activity>
diff --git a/res/drawable-hdpi/ic_settings_generic.png b/res/drawable-hdpi/ic_settings_generic.png
new file mode 100644
index 0000000..0e577bf
--- /dev/null
+++ b/res/drawable-hdpi/ic_settings_generic.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_settings_generic.png b/res/drawable-mdpi/ic_settings_generic.png
new file mode 100644
index 0000000..a7ede7e
--- /dev/null
+++ b/res/drawable-mdpi/ic_settings_generic.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_settings_generic.png b/res/drawable-xhdpi/ic_settings_generic.png
new file mode 100644
index 0000000..6c907f4
--- /dev/null
+++ b/res/drawable-xhdpi/ic_settings_generic.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_settings_generic.png b/res/drawable-xxhdpi/ic_settings_generic.png
new file mode 100644
index 0000000..9ce3b08
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_settings_generic.png
Binary files differ
diff --git a/res/layout/notification_app.xml b/res/layout/notification_app.xml
index 4f61c13..414165a 100644
--- a/res/layout/notification_app.xml
+++ b/res/layout/notification_app.xml
@@ -18,67 +18,76 @@
     android:layout_height="wrap_content" >
 
     <RelativeLayout
-        android:layout_width="match_parent"
+        android:id="@android:id/button1"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_toStartOf="@+id/divider"
-        >
+        android:layout_alignWithParentIfMissing="true"
+        android:layout_toStartOf="@+id/settings_divider"
+        android:background="?android:attr/listChoiceBackgroundIndicator" >
 
         <ImageView
             android:id="@android:id/icon"
-            android:layout_width="@android:dimen/app_icon_size"
-            android:layout_height="@android:dimen/app_icon_size"
+            android:layout_width="@dimen/notification_app_icon_size"
+            android:layout_height="@dimen/notification_app_icon_size"
             android:layout_centerVertical="true"
-            android:layout_marginBottom="10dp"
-            android:layout_marginStart="0dp"
-            android:layout_marginEnd="6dp"
-            android:layout_marginTop="10dp"
             android:contentDescription="@null"
-            android:maxHeight="@android:dimen/app_icon_size"
-            android:maxWidth="@android:dimen/app_icon_size"
-            android:scaleType="fitCenter" />
+            android:scaleType="center" />
+
+        <ImageView
+            android:id="@android:id/icon1"
+            android:layout_width="@dimen/notification_app_icon_badge_size"
+            android:layout_height="@dimen/notification_app_icon_badge_size"
+            android:layout_marginLeft="@dimen/notification_app_icon_badge_margin"
+            android:layout_marginTop="@dimen/notification_app_icon_badge_margin"
+            android:background="#bb8b0000"
+            android:contentDescription="@null" />
+
+        <ImageView
+            android:id="@android:id/icon2"
+            android:layout_width="@dimen/notification_app_icon_badge_size"
+            android:layout_height="@dimen/notification_app_icon_badge_size"
+            android:layout_alignBottom="@android:id/icon"
+            android:layout_alignEnd="@android:id/icon"
+            android:layout_marginBottom="@dimen/notification_app_icon_badge_margin"
+            android:layout_marginEnd="@dimen/notification_app_icon_badge_margin"
+            android:background="#bb006400"
+            android:contentDescription="@null" />
 
         <TextView
             android:id="@android:id/title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_centerVertical="true"
-            android:layout_toStartOf="@android:id/button1"
             android:layout_toEndOf="@android:id/icon"
             android:ellipsize="end"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceMedium"
             android:textAlignment="viewStart"
-            android:labelFor="@android:id/button2" />
-
+            android:textAppearance="?android:attr/textAppearanceMedium" />
     </RelativeLayout>
 
-    <!-- Divider -->
-
-    <ImageView
-        android:id="@id/divider"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
+    <View
+        android:id="@+id/settings_divider"
+        android:layout_width="1dp"
+        android:layout_height="@dimen/notification_app_settings_divider_height"
         android:layout_centerVertical="true"
         android:layout_toStartOf="@android:id/button2"
-        android:contentDescription="@null"
-        android:src="@drawable/nav_divider" />
-
-    <!-- Settings icon -->
+        android:background="?android:attr/listDivider" />
 
     <ImageView
         android:id="@android:id/button2"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_alignBottom="@android:id/widget_frame"
+        android:layout_width="@dimen/notification_app_icon_size"
+        android:layout_height="@dimen/notification_app_icon_size"
         android:layout_alignParentEnd="true"
-        android:layout_alignTop="@android:id/widget_frame"
         android:layout_centerVertical="true"
-        android:layout_margin="0dip"
-        android:background="?android:attr/selectableItemBackground"
+        android:background="?android:attr/listChoiceBackgroundIndicator"
         android:contentDescription="@string/notification_app_settings_button"
-        android:padding="8dip"
-        android:clickable="true"
-        android:focusable="true"
-        android:src="@drawable/ic_bt_config" />
+        android:scaleType="center"
+        android:src="@drawable/ic_settings_generic" />
 
-</RelativeLayout>
+    <View
+        android:id="@+id/row_divider"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/listDivider" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/notification_app_dialog.xml b/res/layout/notification_app_dialog.xml
new file mode 100644
index 0000000..a8f7880
--- /dev/null
+++ b/res/layout/notification_app_dialog.xml
@@ -0,0 +1,47 @@
+<!--
+     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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" >
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="@dimen/notification_app_icon_size"
+        android:layout_height="@dimen/notification_app_icon_size"
+        android:contentDescription="@null"
+        android:scaleType="center" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/notification_app_icon_size"
+        android:layout_toEndOf="@android:id/icon"
+        android:ellipsize="end"
+        android:gravity="center_vertical"
+        android:singleLine="true"
+        android:textAlignment="viewStart"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <CheckBox
+        android:id="@android:id/button1"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/notification_app_icon_size"
+        android:layout_below="@android:id/icon"
+        android:layout_marginStart="@dimen/content_margin_left"
+        android:text="@string/app_notifications_dialog_show"
+        android:textAppearance="?android:attr/textAppearanceListItem" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/notification_app_list.xml b/res/layout/notification_app_list.xml
new file mode 100644
index 0000000..9d23a54
--- /dev/null
+++ b/res/layout/notification_app_list.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <ListView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:divider="#0000"
+        android:dividerHeight="0px"
+        android:fastScrollAlwaysVisible="true"
+        android:fastScrollEnabled="true"
+        android:listSelector="#0000"
+        android:scrollbarStyle="outsideInset" />
+
+    <TextView
+        android:id="@android:id/empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:text="@string/loading_notification_apps"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/notification_app_section.xml b/res/layout/notification_app_section.xml
new file mode 100644
index 0000000..628b524
--- /dev/null
+++ b/res/layout/notification_app_section.xml
@@ -0,0 +1,19 @@
+<!--
+     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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="?android:attr/listSeparatorTextViewStyle"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" />
diff --git a/res/layout/notification_info_row.xml b/res/layout/notification_info_row.xml
deleted file mode 100644
index bc71ef2..0000000
--- a/res/layout/notification_info_row.xml
+++ /dev/null
@@ -1,115 +0,0 @@
-<!--
-     Copyright (C) 2013 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.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content" >
-
-    <!-- Dream selectable row (icon, caption, radio button) -->
-
-    <RelativeLayout
-        android:id="@android:id/widget_frame"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_toStartOf="@+id/divider"
-        android:background="?android:attr/selectableItemBackground" >
-
-        <!-- Dream icon -->
-
-        <ImageView
-            android:id="@+id/pkgicon"
-            android:layout_width="@*android:dimen/status_bar_icon_size"
-            android:layout_height="@*android:dimen/status_bar_icon_size"
-            android:layout_centerVertical="true"
-            android:layout_marginBottom="6dp"
-            android:layout_marginStart="0dp"
-            android:layout_marginEnd="6dp"
-            android:layout_marginTop="6dp"
-            android:contentDescription="@null"
-            android:maxHeight="@*android:dimen/status_bar_icon_size"
-            android:maxWidth="@*android:dimen/status_bar_icon_size"
-            android:scaleType="fitCenter" />
-
-        <ImageView
-            android:id="@android:id/icon"
-            android:layout_width="@*android:dimen/status_bar_icon_size"
-            android:layout_height="@*android:dimen/status_bar_icon_size"
-            android:layout_centerVertical="true"
-            android:layout_toEndOf="@id/pkgicon"
-            android:layout_marginBottom="6dp"
-            android:layout_marginStart="0dp"
-            android:layout_marginEnd="8dp"
-            android:layout_marginTop="6dp"
-            android:contentDescription="@null"
-            android:maxHeight="@*android:dimen/status_bar_icon_size"
-            android:maxWidth="@*android:dimen/status_bar_icon_size"
-            android:scaleType="fitCenter" />
-
-        <!-- Dream caption -->
-
-        <TextView
-            android:id="@android:id/title"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_centerVertical="true"
-            android:layout_toStartOf="@android:id/button1"
-            android:layout_toEndOf="@android:id/icon"
-            android:ellipsize="end"
-            android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textAlignment="viewStart"
-            android:labelFor="@android:id/button2" />
-
-        <!-- Dream radio button -->
-
-        <!--<RadioButton
-            android:id="@android:id/button1"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_alignParentEnd="true"
-            android:layout_centerVertical="true"
-            android:duplicateParentState="true"
-            android:clickable="false"
-            android:focusable="false" />-->
-    </RelativeLayout>
-
-    <!-- Divider -->
-
-    <ImageView
-        android:id="@id/divider"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_centerVertical="true"
-        android:layout_toStartOf="@android:id/button2"
-        android:contentDescription="@null"
-        android:src="@drawable/nav_divider" />
-
-    <!-- Settings icon -->
-
-    <ImageView
-        android:id="@android:id/button2"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_alignBottom="@android:id/widget_frame"
-        android:layout_alignParentEnd="true"
-        android:layout_alignTop="@android:id/widget_frame"
-        android:layout_centerVertical="true"
-        android:layout_margin="0dip"
-        android:background="?android:attr/selectableItemBackground"
-        android:contentDescription="@string/screensaver_settings_button"
-        android:padding="8dip"
-        android:src="@drawable/ic_bt_config" />
-
-</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/notification_log_row.xml b/res/layout/notification_log_row.xml
index 284e9ea..702e6b8 100644
--- a/res/layout/notification_log_row.xml
+++ b/res/layout/notification_log_row.xml
@@ -33,7 +33,7 @@
             android:layout_width="@*android:dimen/status_bar_icon_size"
             android:layout_height="@*android:dimen/status_bar_icon_size"
             android:layout_centerVertical="true"
-            android:layout_toEndOf="@id/pkgicon"
+            android:layout_toEndOf="@+id/pkgicon"
             android:layout_marginStart="0dp"
             android:layout_marginEnd="8dp"
             android:contentDescription="@null"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3581d6a..64d4851 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -78,4 +78,9 @@
     <integer name="preferences_left_pane_weight">4</integer>
     <!-- Weight of the right pane in a multi-pane preference layout. So the split is 40:60 -->
     <integer name="preferences_right_pane_weight">6</integer>
+
+    <dimen name="notification_app_icon_size">64dp</dimen>
+    <dimen name="notification_app_icon_badge_size">20dp</dimen>
+    <dimen name="notification_app_icon_badge_margin">4dp</dimen>
+    <dimen name="notification_app_settings_divider_height">48dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 09bd6d6..c92bde2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1767,9 +1767,7 @@
     <!-- Sound settings screen, notification light repeat pulsing title -->
     <string name="notification_pulse_title">Pulse notification light</string>
     <!-- Display settings screen, notification popups are enabled [CHAR LIMIT=30] -->
-    <string name="heads_up_enabled_title">Heads Up Notifications</string>
-    <!-- Display settings screen, notification popups are explained [CHAR LIMIT=45]-->
-    <string name="heads_up_enabled_summary">Important notifications will pop up</string>
+    <string name="heads_up_enabled_title">Pop up if high priority</string>
     <!-- Sound settings screen, the title of the volume bar to adjust the incoming call volume -->
     <string name="incoming_call_volume_title">Ringtone</string>
     <!-- Sound settings screen, the title of the volume bar to adjust the notification volume -->
@@ -5027,38 +5025,31 @@
     <!-- Notifications on lockscreen -->
     <!-- Label for checkbox controlling the contents of notifications shown on
          the secure lockscreen [CHAR LIMIT=25] -->
-    <string name="lock_screen_notifications">Show when locked</string>
+    <string name="lock_screen_notifications">Show on lock screen</string>
     <!-- Summary for lock_screen_notifications: sensitive information will be
          hidden or redacted from notifications shown on a secure lock screen
          [CHAR LIMIT=50] -->
-    <string name="lock_screen_notifications_summary_off">Sensitive notification contents will be hidden on the lock screen</string>
+    <string name="lock_screen_notifications_summary_off">Unless content is sensitive</string>
     <!-- Summary for lock_screen_notifications: all information will be
          shown in notifications shown on a secure lock screen
          [CHAR LIMIT=50] -->
-    <string name="lock_screen_notifications_summary_on">All notification contents will be shown on the lock screen</string>
+    <string name="lock_screen_notifications_summary_on">All notifications</string>
 
-    <!-- [CHAR LIMIT=30] Sound settings screen, setting option name to change zen mode -->
-    <string name="title_zen_mode">Limited interruptions</string>
-    <!-- [CHAR LIMIT=30] Sound settings screen, description for configuring zen mode -->
-    <string name="configure_zen_mode_description">Configure limited interruptions</string>
+    <!-- [CHAR LIMIT=30] Notification settings screen, setting option name -->
+    <string name="title_zen_mode">Do not disturb</string>
+
     <!-- [CHAR LIMIT=30] Zen mode settings screen, activity title -->
-    <string name="zen_mode_settings_title">Limited Interruptions</string>
+    <string name="zen_mode_settings_title">Do not disturb</string>
 
     <!-- [CHAR LIMIT=20] Notifications settings header -->
     <string name="notification_settings">Notifications</string>
 
-    <!-- [CHAR LIMIT=20] Notifications settings: General section header -->
-    <string name="notification_settings_general">General</string>
-
-    <!-- [CHAR LIMIT=20] Notifications settings: Security section header -->
-    <string name="notification_settings_security">Security</string>
-
     <!-- [CHAR LIMIT=20] Notifications settings: Tweaks section header (eng
          builds only) -->
     <string name="notification_settings_tweaks">Tweaks</string>
 
     <!-- [CHAR LIMIT=20] Notifications settings: Apps section header -->
-    <string name="notification_settings_apps">Apps</string>
+    <string name="notification_settings_apps_title">App notifications</string>
 
     <!-- [CHAR LIMIT=NONE] Content description for per-app notification
          settings button -->
@@ -5081,5 +5072,21 @@
     <!-- Text displayed when tag is not writable -->
     <string name="status_tag_not_writable">NFC tag is not writable. Please use a different tag.</string>
 
+    <!-- Option title for the default sound, context based on screen -->
+    <string name="default_sound">Default sound</string>
 
+    <!-- [CHAR LIMIT=NONE] Text when loading app list in notification settings -->
+    <string name="loading_notification_apps">Loading apps...</string>
+
+    <!-- [CHAR LIMIT=40] Notification settings: App notifications screen title -->
+    <string name="app_notifications_title">App notifications</string>
+
+    <!-- [CHAR LIMIT=30] Notification settings: App notifications dialog show option -->
+    <string name="app_notifications_dialog_show">Show notifications</string>
+
+    <!-- [CHAR LIMIT=30] Notification settings: App notifications dialog priority option -->
+    <string name="app_notifications_dialog_priority">High priority</string>
+
+    <!-- [CHAR LIMIT=20] Notification settings: App notifications dialog dismiss button caption -->
+    <string name="app_notifications_dialog_done">Done</string>
 </resources>
diff --git a/res/xml/notification_settings.xml b/res/xml/notification_settings.xml
index 4979422..51b153e 100644
--- a/res/xml/notification_settings.xml
+++ b/res/xml/notification_settings.xml
@@ -19,67 +19,44 @@
         android:key="notification_settings"
         xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
 
-    <PreferenceCategory
-            android:key="category_general"
-            android:title="@string/notification_settings_general">
+    <com.android.settings.DefaultRingtonePreference
+            android:key="notification_sound"
+            android:title="@string/default_sound"
+            android:dialogTitle="@string/notification_sound_dialog_title"
+            android:persistent="false"
+            android:ringtoneType="notification" />
 
-        <com.android.settings.DefaultRingtonePreference
-                android:key="notification_sound"
-                android:title="@string/notification_sound_title"
-                android:dialogTitle="@string/notification_sound_dialog_title"
-                android:persistent="false"
-                android:ringtoneType="notification" />
+    <CheckBoxPreference
+            android:key="notification_pulse"
+            android:title="@string/notification_pulse_title"
+            android:persistent="false" />
 
-        <CheckBoxPreference
-                android:key="notification_pulse"
-                android:title="@string/notification_pulse_title"
-                android:persistent="false" />
+    <CheckBoxPreference
+            android:key="heads_up"
+            android:title="@string/heads_up_enabled_title"
+            android:persistent="false" />
 
-        <CheckBoxPreference
-                android:key="heads_up"
-                android:title="@string/heads_up_enabled_title"
-                android:summary="@string/heads_up_enabled_summary"
-                android:persistent="false" />
+    <CheckBoxPreference
+            android:key="toggle_lock_screen_notifications"
+            android:title="@string/lock_screen_notifications"
+            android:summaryOff="@string/lock_screen_notifications_summary_off"
+            android:summaryOn="@string/lock_screen_notifications_summary_on"
+            android:persistent="false" />
 
-        <PreferenceScreen
-                android:key="zen_mode"
-                android:title="@string/title_zen_mode"
-                android:fragment="com.android.settings.ZenModeSettings" />
+    <PreferenceScreen
+            android:key="configure"
+            android:title="@string/notification_settings_apps_title"
+            android:fragment="com.android.settings.notification.AppNotificationSettings" />
 
-    </PreferenceCategory>
-
-    <PreferenceCategory
-            android:key="category_security"
-            android:title="@string/notification_settings_security">
-
-        <CheckBoxPreference
-                android:key="toggle_lock_screen_notifications"
-                android:title="@string/lock_screen_notifications"
-                android:summaryOff="@string/lock_screen_notifications_summary_off"
-                android:summaryOn="@string/lock_screen_notifications_summary_on"
-                android:persistent="false" />
-
-        <Preference
-                android:key="manage_notification_access"
-                android:title="@string/manage_notification_access"
-                android:persistent="false"
-                android:fragment="com.android.settings.NotificationAccessSettings"/>
-
-    </PreferenceCategory>
-
-<!--
-    <PreferenceCategory
-            android:key="category_tweaks"
-            android:title="@string/notification_settings_tweaks"/>
+    <PreferenceScreen
+            android:key="zen_mode"
+            android:title="@string/title_zen_mode"
+            android:fragment="com.android.settings.notification.ZenModeSettings" />
 
     <Preference
-            android:title="Coming soon"
-            />
--->
-
-    <PreferenceCategory
-            android:key="category_apps"
-            android:title="@string/notification_settings_apps">
-    </PreferenceCategory>
+            android:key="manage_notification_access"
+            android:title="@string/manage_notification_access"
+            android:persistent="false"
+            android:fragment="com.android.settings.notification.NotificationAccessSettings" />
 
 </PreferenceScreen>
diff --git a/res/xml/settings_headers.xml b/res/xml/settings_headers.xml
index 73665cd..bf44854 100644
--- a/res/xml/settings_headers.xml
+++ b/res/xml/settings_headers.xml
@@ -85,7 +85,7 @@
     <header
         android:id="@+id/notification_settings"
         android:icon="@drawable/ic_settings_notifications"
-        android:fragment="com.android.settings.NotificationSettings"
+        android:fragment="com.android.settings.notification.NotificationSettings"
         android:title="@string/notification_settings" />
 
     <!-- Storage -->
diff --git a/src/com/android/settings/NotificationSettings.java b/src/com/android/settings/NotificationSettings.java
deleted file mode 100644
index d0b64a6..0000000
--- a/src/com/android/settings/NotificationSettings.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * 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;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.database.ContentObserver;
-import android.graphics.drawable.Drawable;
-import android.media.RingtoneManager;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.preference.CheckBoxPreference;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceScreen;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-
-public class NotificationSettings extends SettingsPreferenceFragment implements
-        Preference.OnPreferenceChangeListener, OnPreferenceClickListener {
-    private static final String TAG = "NotificationSettings";
-
-    private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT
-            = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_NOTIFICATION_PREFERENCES);
-
-    private static final String KEY_NOTIFICATION_SOUND = "notification_sound";
-    private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access";
-    private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "toggle_lock_screen_notifications";
-    private static final String KEY_HEADS_UP = "heads_up";
-    private static final String KEY_NOTIFICATION_PULSE = "notification_pulse";
-
-    private static final String KEY_SECURITY_CATEGORY = "category_security";
-    private static final String KEY_APPS_CATEGORY = "category_apps";
-    private static final String KEY_TWEAKS_CATEGORY = "category_tweaks"; // power toys, eng only
-
-    private static final int MSG_UPDATE_SOUND_SUMMARY = 2;
-
-    private Context mContext;
-    private PackageManager mPM;
-
-    private Preference mNotificationSoundPreference;
-    private Preference mNotificationAccess;
-    private CheckBoxPreference mLockscreenNotifications;
-    private CheckBoxPreference mHeadsUp;
-    private CheckBoxPreference mNotificationPulse;
-    private PreferenceGroup mAppsPreference;
-
-    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;
-            }
-        }
-    };
-
-    private final ArrayList<AppNotificationInfo> mAppNotificationInfo
-            = new ArrayList<AppNotificationInfo>();
-    private final HashSet<String> mAppNotificationInfoPackages = new HashSet<String>();
-    private final Comparator<AppNotificationInfo> mAppComparator = new Comparator<AppNotificationInfo>() {
-        private final Collator sCollator = Collator.getInstance();
-        @Override
-        public int compare(AppNotificationInfo lhs, AppNotificationInfo rhs) {
-            return sCollator.compare(lhs.label, rhs.label);
-        }
-    };
-
-    private final Runnable mCollectAppsRunnable = new Runnable() {
-        @Override
-        public void run() {
-            synchronized (mAppNotificationInfo) {
-                mAppNotificationInfo.clear();
-                mAppNotificationInfoPackages.clear();
-
-                final PackageManager pm = getPackageManager();
-
-                final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
-                        PackageManager.MATCH_DEFAULT_ONLY);
-
-                for (ResolveInfo ri : resolveInfos) {
-                    final ActivityInfo activityInfo = ri.activityInfo;
-                    final ApplicationInfo appInfo = activityInfo.applicationInfo;
-                    if (mAppNotificationInfoPackages.contains(activityInfo.packageName)) {
-                        Log.v(TAG, "Ignoring duplicate notification preference activity ("
-                                + activityInfo.name + ") for package "
-                                + activityInfo.packageName);
-                        continue;
-                    }
-                    final AppNotificationInfo info = new AppNotificationInfo();
-                    mAppNotificationInfoPackages.add(activityInfo.packageName);
-
-                    info.label = appInfo.loadLabel(pm);
-                    info.icon = appInfo.loadIcon(pm);
-                    info.name = activityInfo.name;
-                    info.pkg = activityInfo.packageName;
-                    mAppNotificationInfo.add(info);
-                }
-
-                Collections.sort(mAppNotificationInfo, mAppComparator);
-                mHandler.post(mRefreshAppsListRunnable);
-            }
-        }
-    };
-
-    private final Runnable mRefreshAppsListRunnable = new Runnable() {
-        @Override
-        public void run() {
-            synchronized (mAppNotificationInfo) {
-                mAppsPreference.removeAll();
-                Preference p = getPreferenceScreen().findPreference(mAppsPreference.getKey());
-                final int N = mAppNotificationInfo.size();
-                if (N == 0 && p != null) {
-                    getPreferenceScreen().removePreference(p);
-                } else if (N > 0 && p == null) {
-                    getPreferenceScreen().addPreference(mAppsPreference);
-                }
-                for (int i = 0; i < N; i++) {
-                    final AppNotificationInfo info = mAppNotificationInfo.get(i);
-                    Preference pref = new AppNotificationPreference(mContext);
-                    pref.setTitle(info.label);
-                    pref.setIcon(info.icon);
-                    pref.setIntent(new Intent(Intent.ACTION_MAIN)
-                            .setClassName(info.pkg, info.name));
-                    mAppsPreference.addPreference(pref);
-                }
-            }
-        }
-    };
-
-
-    @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();
-        final PreferenceGroup securityCategory = (PreferenceGroup)
-                root.findPreference(KEY_SECURITY_CATEGORY);
-
-        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);
-
-        mNotificationAccess = findPreference(KEY_NOTIFICATION_ACCESS);
-        refreshNotificationListeners();
-
-        mLockscreenNotifications
-                = (CheckBoxPreference) root.findPreference(KEY_LOCK_SCREEN_NOTIFICATIONS);
-        if (mLockscreenNotifications != null) {
-            if (!getDeviceLockscreenNotificationsEnabled()) {
-                if (securityCategory != null) {
-                    securityCategory.removePreference(mLockscreenNotifications);
-                }
-            } else {
-                mLockscreenNotifications.setChecked(getLockscreenAllowPrivateNotifications());
-            }
-        }
-
-        mHeadsUp = (CheckBoxPreference) 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 = (CheckBoxPreference) 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");
-            }
-        }
-        mAppsPreference = (PreferenceGroup) root.findPreference(KEY_APPS_CATEGORY);
-        root.removePreference(mAppsPreference);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        refreshNotificationListeners();
-        lookupRingtoneNames();
-        loadAppsList();
-    }
-
-    private void loadAppsList() {
-        AsyncTask.execute(mCollectAppsRunnable);
-    }
-
-    @Override
-    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
-        final String key = preference.getKey();
-
-        if (KEY_LOCK_SCREEN_NOTIFICATIONS.equals(key)) {
-            Settings.Secure.putInt(getContentResolver(),
-                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
-                    mLockscreenNotifications.isChecked() ? 1 : 0);
-        } else 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);
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean onPreferenceChange(Preference preference, Object objValue) {
-        return true;
-    }
-
-    @Override
-    public boolean onPreferenceClick(Preference preference) {
-        return false;
-    }
-
-    // === 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 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);
-    }
-
-    // === 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);
-    }
-
-    // === Notification listeners ===
-
-    private int getNumEnabledNotificationListeners() {
-        final String flat = Settings.Secure.getString(getContentResolver(),
-                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-        if (flat == null || "".equals(flat)) return 0;
-        final String[] components = flat.split(":");
-        return components.length;
-    }
-
-    private void refreshNotificationListeners() {
-        if (mNotificationAccess != null) {
-            final PreferenceGroup securityCategory
-                    = (PreferenceGroup) getPreferenceScreen().findPreference(KEY_SECURITY_CATEGORY);
-
-            final int total = NotificationAccessSettings.getListenersCount(mPM);
-            if (total == 0) {
-                if (securityCategory != null) {
-                    securityCategory.removePreference(mNotificationAccess);
-                }
-            } else {
-                final int n = getNumEnabledNotificationListeners();
-                if (n == 0) {
-                    mNotificationAccess.setSummary(getResources().getString(
-                            R.string.manage_notification_access_summary_zero));
-                } else {
-                    mNotificationAccess.setSummary(String.format(getResources().getQuantityString(
-                            R.plurals.manage_notification_access_summary_nonzero,
-                            n, n)));
-                }
-            }
-        }
-    }
-
-    // === Ringtone ===
-
-    private void lookupRingtoneNames() {
-        new Thread(mRingtoneLookupRunnable).start();
-    }
-
-    // === Per-app notification settings row ==
-
-    private static class AppNotificationPreference extends Preference {
-        private Intent mIntent;
-
-        public AppNotificationPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-            super(context, attrs, defStyleAttr, defStyleRes);
-
-            setLayoutResource(R.layout.notification_app);
-        }
-
-        public AppNotificationPreference(Context context, AttributeSet attrs, int defStyleAttr) {
-            this(context, attrs, defStyleAttr, 0);
-        }
-
-        public AppNotificationPreference(Context context, AttributeSet attrs) {
-            this(context, attrs, 0);
-        }
-
-        public AppNotificationPreference(Context context) {
-            this(context, null);
-        }
-
-        public void setIntent(Intent intent) {
-            mIntent = intent;
-        }
-
-        @Override
-        protected void onBindView(View view) {
-            super.onBindView(view);
-
-            ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
-            icon.setImageDrawable(getIcon());
-            TextView title = (TextView) view.findViewById(android.R.id.title);
-            title.setText(getTitle());
-            ImageView settingsButton = (ImageView) view.findViewById(android.R.id.button2);
-            settingsButton.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    getContext().startActivity(mIntent);
-                }
-            });
-        }
-    }
-
-    private static class AppNotificationInfo {
-        public Drawable icon;
-        public CharSequence label;
-        public String name;
-        public String pkg;
-    }
-}
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 9d6e740..964c444 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -93,6 +93,10 @@
 import com.android.settings.location.LocationSettings;
 import com.android.settings.nfc.AndroidBeam;
 import com.android.settings.nfc.PaymentSettings;
+import com.android.settings.notification.NotificationAccessSettings;
+import com.android.settings.notification.NotificationSettings;
+import com.android.settings.notification.NotificationStation;
+import com.android.settings.notification.ZenModeSettings;
 import com.android.settings.print.PrintJobSettingsFragment;
 import com.android.settings.print.PrintSettingsFragment;
 import com.android.settings.tts.TextToSpeechSettings;
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
new file mode 100644
index 0000000..172557d
--- /dev/null
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -0,0 +1,550 @@
+/*
+ * 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.animation.LayoutTransition;
+import android.app.AlertDialog;
+import android.app.INotificationManager;
+import android.app.ListFragment;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+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.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;
+import android.os.Parcelable;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.SectionIndexer;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class AppNotificationSettings extends ListFragment {
+    private static final String TAG = "AppNotificationSettings";
+    private static final boolean DEBUG = true;
+
+    private static final String SECTION_BEFORE_A = "*";
+    private static final String SECTION_AFTER_Z = "**";
+    private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT
+            = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_NOTIFICATION_PREFERENCES);
+
+    private final Handler mHandler = new Handler();
+    private final ArrayMap<String, AppRow> mRows = new ArrayMap<String, AppRow>();
+    private final ArrayList<AppRow> mSortedRows = new ArrayList<AppRow>();
+    private final ArrayList<String> mSections = new ArrayList<String>();
+
+    private Context mContext;
+    private LayoutInflater mInflater;
+    private NotificationAppAdapter mAdapter;
+    private Signature[] mSystemSignature;
+    private Parcelable mListViewState;
+    private Backend mBackend = new Backend();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mContext = getActivity();
+        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mAdapter = new NotificationAppAdapter(mContext);
+        getActivity().setTitle(R.string.app_notifications_title);
+    }
+
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.notification_app_list, container, false);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        repositionScrollbar();
+        getListView().setAdapter(mAdapter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (DEBUG) Log.d(TAG, "Saving listView state");
+        mListViewState = getListView().onSaveInstanceState();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        loadAppsList();
+    }
+
+    public void setBackend(Backend backend) {
+        mBackend = backend;
+    }
+
+    private void loadAppsList() {
+        AsyncTask.execute(mCollectAppsRunnable);
+    }
+
+    private String getSection(CharSequence label) {
+        if (label == null || label.length() == 0) return SECTION_BEFORE_A;
+        final char c = Character.toUpperCase(label.charAt(0));
+        if (c < 'A') return SECTION_BEFORE_A;
+        if (c > 'Z') return SECTION_AFTER_Z;
+        return Character.toString(c);
+    }
+
+    private void repositionScrollbar() {
+        final int sbWidthPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                getListView().getScrollBarSize(),
+                getResources().getDisplayMetrics());
+        final View parent = (View)getView().getParent();
+        final int eat = Math.min(sbWidthPx, parent.getPaddingEnd());
+        if (eat <= 0) return;
+        if (DEBUG) Log.d(TAG, String.format("Eating %dpx into %dpx padding for %dpx scroll, ld=%d",
+                eat, parent.getPaddingEnd(), sbWidthPx, getListView().getLayoutDirection()));
+        parent.setPaddingRelative(parent.getPaddingStart(), parent.getPaddingTop(),
+                parent.getPaddingEnd() - eat, parent.getPaddingBottom());
+    }
+
+    private boolean isSystemApp(PackageInfo pkg) {
+        if (mSystemSignature == null) {
+            mSystemSignature = new Signature[]{ getSystemSignature() };
+        }
+        return mSystemSignature[0] != null && mSystemSignature[0].equals(getFirstSignature(pkg));
+    }
+
+    private static Signature getFirstSignature(PackageInfo pkg) {
+        if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
+            return pkg.signatures[0];
+        }
+        return null;
+    }
+
+    private Signature getSystemSignature() {
+        final PackageManager pm = mContext.getPackageManager();
+        try {
+            final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
+            return getFirstSignature(sys);
+        } catch (NameNotFoundException e) {
+        }
+        return null;
+    }
+
+
+    private void showDialog(final View v, final AppRow row) {
+        final RelativeLayout layout = (RelativeLayout)
+                mInflater.inflate(R.layout.notification_app_dialog, null);
+        final ImageView icon = (ImageView) layout.findViewById(android.R.id.icon);
+        icon.setImageDrawable(row.icon);
+        final TextView title = (TextView) layout.findViewById(android.R.id.title);
+        title.setText(row.label);
+        final CheckBox showBox = (CheckBox) layout.findViewById(android.R.id.button1);
+        showBox.setChecked(!row.banned);
+        final OnCheckedChangeListener showListener = new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                boolean success = mBackend.setNotificationsBanned(row.pkg, row.uid, !isChecked);
+                if (success) {
+                    row.banned = !isChecked;
+                    mAdapter.bindView(v, row, true /*animate*/);
+                } else {
+                    showBox.setOnCheckedChangeListener(null);
+                    showBox.setChecked(!isChecked);
+                    showBox.setOnCheckedChangeListener(this);
+                }
+            }
+        };
+        showBox.setOnCheckedChangeListener(showListener);
+        final AlertDialog d = new AlertDialog.Builder(mContext)
+            .setView(layout)
+            .setPositiveButton(R.string.app_notifications_dialog_done, null)
+            .create();
+        d.show();
+    }
+
+    private static class ViewHolder {
+        ViewGroup row;
+        ViewGroup appButton;
+        ImageView icon;
+        ImageView banBadge;
+        ImageView priBadge;
+        TextView title;
+        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
+        public boolean hasStableIds() {
+            return true;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 2;
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            Row r = getItem(position);
+            return r instanceof AppRow ? 1 : 0;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            Row r = getItem(position);
+            View v;
+            if (convertView == null) {
+                v = newView(parent, r);
+            } else {
+                v = convertView;
+            }
+            bindView(v, r, false /*animate*/);
+            return v;
+        }
+
+        public View newView(ViewGroup parent, Row r) {
+            if (!(r instanceof AppRow)) {
+                return mInflater.inflate(R.layout.notification_app_section, parent, false);
+            }
+            final View v = mInflater.inflate(R.layout.notification_app, parent, false);
+            final ViewHolder vh = new ViewHolder();
+            vh.row = (ViewGroup) v;
+            vh.row.setLayoutTransition(new LayoutTransition());
+            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.settingsDivider = v.findViewById(R.id.settings_divider);
+            vh.settingsButton = (ImageView) v.findViewById(android.R.id.button2);
+            vh.rowDivider = v.findViewById(R.id.row_divider);
+            v.setTag(vh);
+            return v;
+        }
+
+        private void enableLayoutTransitions(ViewGroup vg, boolean enabled) {
+            if (enabled) {
+                vg.getLayoutTransition().enableTransitionType(LayoutTransition.APPEARING);
+                vg.getLayoutTransition().enableTransitionType(LayoutTransition.DISAPPEARING);
+            } else {
+                vg.getLayoutTransition().disableTransitionType(LayoutTransition.APPEARING);
+                vg.getLayoutTransition().disableTransitionType(LayoutTransition.DISAPPEARING);
+            }
+        }
+
+        public void bindView(final View view, Row r, boolean animate) {
+            if (!(r instanceof AppRow)) {
+                TextView tv = (TextView)view;
+                tv.setText(r.section);
+                return;
+            }
+
+            final AppRow row = (AppRow)r;
+            final ViewHolder vh = (ViewHolder) view.getTag();
+            enableLayoutTransitions(vh.row, animate);
+            vh.rowDivider.setVisibility(row.first ? View.GONE : View.VISIBLE);
+            vh.appButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    showDialog(view, row);
+                }
+            });
+            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 boolean showSettings = !row.banned && row.settingsIntent != null;
+            vh.settingsDivider.setVisibility(showSettings ? View.VISIBLE : View.GONE);
+            vh.settingsButton.setVisibility(showSettings ? View.VISIBLE : View.GONE);
+            vh.settingsButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (row.settingsIntent != null) {
+                        getContext().startActivity(row.settingsIntent);
+                    }
+                }
+            });
+        }
+
+        @Override
+        public Object[] getSections() {
+            return mSections.toArray(new Object[mSections.size()]);
+        }
+
+        @Override
+        public int getPositionForSection(int sectionIndex) {
+            final String section = mSections.get(sectionIndex);
+            final int n = getCount();
+            for (int i = 0; i < n; i++) {
+                final Row r = getItem(i);
+                if (r.section.equals(section)) {
+                    return i;
+                }
+            }
+            return 0;
+        }
+
+        @Override
+        public int getSectionForPosition(int position) {
+            Row row = getItem(position);
+            return mSections.indexOf(row.section);
+        }
+    }
+
+    private static class Row {
+        public String section;
+    }
+
+    private static class AppRow extends Row {
+        public String pkg;
+        public int uid;
+        public Drawable icon;
+        public CharSequence label;
+        public Intent settingsIntent;
+        public boolean banned;
+        public boolean priority;
+        public boolean first;
+    }
+
+    private static final Comparator<AppRow> mRowComparator = new Comparator<AppRow>() {
+        private final Collator sCollator = Collator.getInstance();
+        @Override
+        public int compare(AppRow lhs, AppRow rhs) {
+            return sCollator.compare(lhs.label, rhs.label);
+        }
+    };
+
+    private final Runnable mCollectAppsRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mRows) {
+                final long start = SystemClock.uptimeMillis();
+                if (DEBUG) Log.d(TAG, "Collecting apps...");
+                mRows.clear();
+                mSortedRows.clear();
+
+                // collect all non-system apps
+                final PackageManager pm = mContext.getPackageManager();
+                for (PackageInfo pkg : pm.getInstalledPackages(PackageManager.GET_SIGNATURES)) {
+                    if (pkg.applicationInfo == null || isSystemApp(pkg)) {
+                        if (DEBUG) Log.d(TAG, "Skipping " + pkg.packageName);
+                        continue;
+                    }
+                    final AppRow row = new AppRow();
+                    row.pkg = pkg.packageName;
+                    row.uid = pkg.applicationInfo.uid;
+                    try {
+                        row.label = pkg.applicationInfo.loadLabel(pm);
+                    } catch (Throwable t) {
+                        Log.e(TAG, "Error loading application label for " + row.pkg, t);
+                        row.label = row.pkg;
+                    }
+                    row.icon = pkg.applicationInfo.loadIcon(pm);
+                    row.banned = mBackend.getNotificationsBanned(row.pkg, row.uid);
+                    row.priority = mBackend.getHighPriority(row.pkg, row.uid);
+                    mRows.put(row.pkg, row);
+                }
+                // collect config activities
+                Log.d(TAG, "APP_NOTIFICATION_PREFS_CATEGORY_INTENT is " + APP_NOTIFICATION_PREFS_CATEGORY_INTENT);
+                final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(
+                        APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
+                        PackageManager.MATCH_DEFAULT_ONLY);
+                if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities");
+                for (ResolveInfo ri : resolveInfos) {
+                    final ActivityInfo activityInfo = ri.activityInfo;
+                    final ApplicationInfo appInfo = activityInfo.applicationInfo;
+                    final AppRow row = mRows.get(appInfo.packageName);
+                    if (row == null) {
+                        Log.v(TAG, "Ignoring notification preference activity ("
+                                + activityInfo.name + ") for unknown package "
+                                + activityInfo.packageName);
+                        continue;
+                    }
+                    if (row.settingsIntent != null) {
+                        Log.v(TAG, "Ignoring duplicate notification preference activity ("
+                                + activityInfo.name + ") for package "
+                                + activityInfo.packageName);
+                        continue;
+                    }
+                    row.settingsIntent = new Intent(Intent.ACTION_MAIN)
+                            .setClassName(activityInfo.packageName, activityInfo.name);
+                }
+                // sort rows
+                mSortedRows.addAll(mRows.values());
+                Collections.sort(mSortedRows, mRowComparator);
+                // compute sections
+                mSections.clear();
+                String section = null;
+                for (AppRow r : mSortedRows) {
+                    r.section = getSection(r.label);
+                    if (!r.section.equals(section)) {
+                        section = r.section;
+                        mSections.add(section);
+                    }
+                }
+                mHandler.post(mRefreshAppsListRunnable);
+                final long elapsed = SystemClock.uptimeMillis() - start;
+                if (DEBUG) Log.d(TAG, "Collected " + mRows.size() + " apps in " + elapsed + "ms");
+            }
+        }
+    };
+
+    private void refreshDisplayedItems() {
+        if (DEBUG) Log.d(TAG, "Refreshing apps...");
+        mAdapter.clear();
+        synchronized (mSortedRows) {
+            String section = null;
+            final int N = mSortedRows.size();
+            boolean first = true;
+            for (int i = 0; i < N; i++) {
+                final AppRow row = mSortedRows.get(i);
+                if (!row.section.equals(section)) {
+                    section = row.section;
+                    Row r = new Row();
+                    r.section = section;
+                    mAdapter.add(r);
+                    first = true;
+                }
+                row.first = first;
+                mAdapter.add(row);
+                first = false;
+            }
+        }
+        if (mListViewState != null) {
+            if (DEBUG) Log.d(TAG, "Restoring listView state");
+            getListView().onRestoreInstanceState(mListViewState);
+            mListViewState = null;
+        }
+        if (DEBUG) Log.d(TAG, "Refreshed " + mSortedRows.size() + " displayed items");
+    }
+
+    private final Runnable mRefreshAppsListRunnable = new Runnable() {
+        @Override
+        public void run() {
+            refreshDisplayedItems();
+        }
+    };
+
+    public static class Backend {
+        public boolean setNotificationsBanned(String pkg, int uid, boolean banned) {
+            INotificationManager nm = INotificationManager.Stub.asInterface(
+                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+            try {
+                nm.setNotificationsEnabledForPackage(pkg, uid, !banned);
+                return true;
+            } catch (Exception e) {
+               Log.w(TAG, "Error calling NoMan", e);
+               return false;
+            }
+        }
+
+        public boolean getNotificationsBanned(String pkg, int uid) {
+            INotificationManager nm = INotificationManager.Stub.asInterface(
+                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+            try {
+                final boolean enabled = nm.areNotificationsEnabledForPackage(pkg, uid);
+                return !enabled;
+            } catch (Exception e) {
+                Log.w(TAG, "Error calling NoMan", e);
+                return false;
+            }
+        }
+
+        public boolean getHighPriority(String pkg, int uid) {
+            // TODO get high-pri state from NoMan
+            return false;
+        }
+
+        public boolean setHighPriority(String pkg, int uid, boolean priority) {
+            // TODO save high-pri state to NoMan
+            return true;
+        }
+    }
+}
diff --git a/src/com/android/settings/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java
similarity index 99%
rename from src/com/android/settings/NotificationAccessSettings.java
rename to src/com/android/settings/notification/NotificationAccessSettings.java
index 07d4353..78ea2d8 100644
--- a/src/com/android/settings/NotificationAccessSettings.java
+++ b/src/com/android/settings/notification/NotificationAccessSettings.java
@@ -14,41 +14,42 @@
  * limitations under the License.
  */
 
-package com.android.settings;
+package com.android.settings.notification;
 
 import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
+import android.app.ListFragment;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.DialogInterface;
+import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Handler;
+import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.util.Slog;
-import android.widget.ArrayAdapter;
-
-import android.app.ListFragment;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Bundle;
-import android.provider.Settings;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
 import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
 
+import com.android.settings.R;
+
 import java.util.HashSet;
 import java.util.List;
 
diff --git a/src/com/android/settings/notification/NotificationSettings.java b/src/com/android/settings/notification/NotificationSettings.java
new file mode 100644
index 0000000..24863cd
--- /dev/null
+++ b/src/com/android/settings/notification/NotificationSettings.java
@@ -0,0 +1,252 @@
+/*
+ * 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.Intent;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.media.RingtoneManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceGroup;
+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.SoundSettings;
+
+public class NotificationSettings extends SettingsPreferenceFragment implements
+        Preference.OnPreferenceChangeListener, OnPreferenceClickListener {
+    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_NOTIFICATION_ACCESS = "manage_notification_access";
+
+    private static final String KEY_TWEAKS_CATEGORY = "category_tweaks"; // power toys, eng only
+
+    private static final int MSG_UPDATE_SOUND_SUMMARY = 2;
+
+    private Context mContext;
+    private PackageManager mPM;
+
+    private Preference mNotificationSoundPreference;
+    private Preference mNotificationAccess;
+    private TwoStatePreference mLockscreenNotifications;
+    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);
+
+        mNotificationAccess = findPreference(KEY_NOTIFICATION_ACCESS);
+        refreshNotificationListeners();
+
+        mLockscreenNotifications
+                = (TwoStatePreference) root.findPreference(KEY_LOCK_SCREEN_NOTIFICATIONS);
+        if (mLockscreenNotifications != null) {
+            if (!getDeviceLockscreenNotificationsEnabled()) {
+                root.removePreference(mLockscreenNotifications);
+            } else {
+                mLockscreenNotifications.setChecked(getLockscreenAllowPrivateNotifications());
+            }
+        }
+
+        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();
+    }
+
+    @Override
+    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+        final String key = preference.getKey();
+
+        if (KEY_LOCK_SCREEN_NOTIFICATIONS.equals(key)) {
+            Settings.Secure.putInt(getContentResolver(),
+                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+                    mLockscreenNotifications.isChecked() ? 1 : 0);
+        } else 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);
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object objValue) {
+        return true;
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        return false;
+    }
+
+    // === 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 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);
+    }
+
+    // === 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);
+    }
+
+    // === Notification listeners ===
+
+    private int getNumEnabledNotificationListeners() {
+        final String flat = Settings.Secure.getString(getContentResolver(),
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+        if (flat == null || "".equals(flat)) return 0;
+        final String[] components = flat.split(":");
+        return components.length;
+    }
+
+    private void refreshNotificationListeners() {
+        if (mNotificationAccess != null) {
+            final int total = NotificationAccessSettings.getListenersCount(mPM);
+            if (total == 0) {
+                getPreferenceScreen().removePreference(mNotificationAccess);
+            } else {
+                final int n = getNumEnabledNotificationListeners();
+                if (n == 0) {
+                    mNotificationAccess.setSummary(getResources().getString(
+                            R.string.manage_notification_access_summary_zero));
+                } else {
+                    mNotificationAccess.setSummary(String.format(getResources().getQuantityString(
+                            R.plurals.manage_notification_access_summary_nonzero,
+                            n, n)));
+                }
+            }
+        }
+    }
+
+    // === Ringtone ===
+
+    private void lookupRingtoneNames() {
+        new Thread(mRingtoneLookupRunnable).start();
+    }
+}
diff --git a/src/com/android/settings/NotificationStation.java b/src/com/android/settings/notification/NotificationStation.java
similarity index 98%
rename from src/com/android/settings/NotificationStation.java
rename to src/com/android/settings/notification/NotificationStation.java
index 5083e27..d8a3efb 100644
--- a/src/com/android/settings/NotificationStation.java
+++ b/src/com/android/settings/notification/NotificationStation.java
@@ -14,16 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.settings;
+package com.android.settings.notification;
 
 import android.app.Activity;
 import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.service.notification.INotificationListener;
 import android.app.INotificationManager;
 import android.app.Notification;
-import android.service.notification.StatusBarNotification;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -37,6 +35,8 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.service.notification.INotificationListener;
+import android.service.notification.StatusBarNotification;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -48,6 +48,9 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
diff --git a/src/com/android/settings/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
similarity index 98%
rename from src/com/android/settings/ZenModeSettings.java
rename to src/com/android/settings/notification/ZenModeSettings.java
index f6c7b8c..de020db 100644
--- a/src/com/android/settings/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.settings;
+package com.android.settings.notification;
 
 import android.app.ActionBar;
 import android.app.Activity;
 import android.content.Context;
-import android.database.ContentObserver;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -28,6 +28,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.provider.Settings.Global;
+import android.provider.SearchIndexableResource;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.Gravity;
@@ -45,6 +46,9 @@
 import android.widget.Switch;
 import android.widget.TextView;
 import com.android.settings.search.BaseSearchIndexProvider;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.search.Indexable;
 import com.android.settings.search.SearchIndexableRaw;
 
diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java
index 6f8efce..af04b5f 100644
--- a/src/com/android/settings/search/SearchIndexableResources.java
+++ b/src/com/android/settings/search/SearchIndexableResources.java
@@ -17,27 +17,27 @@
 package com.android.settings.search;
 
 import android.provider.SearchIndexableResource;
+
 import com.android.settings.DataUsageSummary;
 import com.android.settings.DateTimeSettings;
 import com.android.settings.DevelopmentSettings;
 import com.android.settings.DeviceInfoSettings;
 import com.android.settings.DisplaySettings;
 import com.android.settings.HomeSettings;
-import com.android.settings.NotificationSettings;
 import com.android.settings.PrivacySettings;
 import com.android.settings.R;
 import com.android.settings.SecuritySettings;
 import com.android.settings.SoundSettings;
 import com.android.settings.WallpaperTypeSettings;
 import com.android.settings.WirelessSettings;
-import com.android.settings.ZenModeSettings;
 import com.android.settings.accessibility.AccessibilitySettings;
 import com.android.settings.bluetooth.BluetoothSettings;
 import com.android.settings.deviceinfo.Memory;
 import com.android.settings.fuelgauge.PowerUsageSummary;
 import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
 import com.android.settings.location.LocationSettings;
-import com.android.settings.net.DataUsageMeteredSettings;
+import com.android.settings.notification.NotificationSettings;
+import com.android.settings.notification.ZenModeSettings;
 import com.android.settings.print.PrintSettingsFragment;
 import com.android.settings.users.UserSettings;
 import com.android.settings.wifi.WifiSettings;