Merge "Makes it possible to robo-test Settings app fragments."
diff --git a/res/drawable/ic_settings_24dp.xml b/res/drawable/ic_settings_24dp.xml
index 545bc2d..da34345 100644
--- a/res/drawable/ic_settings_24dp.xml
+++ b/res/drawable/ic_settings_24dp.xml
@@ -18,7 +18,8 @@
         android:width="24dp"
         android:height="24dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
     <path
         android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
         android:fillColor="#ffffffff" />
diff --git a/res/layout/activity_list.xml b/res/layout/activity_list.xml
new file mode 100644
index 0000000..ca9e12b
--- /dev/null
+++ b/res/layout/activity_list.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2016 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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent">
+
+    <ListView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+    <TextView
+        android:id="@android:id/empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:text="@string/activity_list_empty"
+        android:visibility="gone"
+        android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+</FrameLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 75449b2..4d872b1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -612,6 +612,8 @@
     <string name="settings_label_launcher">Settings</string>
     <!-- Label for option to select a settings panel as a shortcut -->
     <string name="settings_shortcut">Settings shortcut</string>
+    <!-- Shown in create shortcut activity when there is no shortcut that can be created. [CHAR_LIMIT=None] -->
+    <string name="activity_list_empty">No matching activities found.</string>
     <!-- Wireless controls settings screen, setting check box label -->
     <string name="airplane_mode">Airplane mode</string>
     <!-- Main Settings screen settings title for things like airplane mode, tethering, NFC, VPN.  This will take you to another screen with those settings.  [CHAR LIMIT=30] -->
diff --git a/src/com/android/settings/CreateShortcut.java b/src/com/android/settings/CreateShortcut.java
index 7317738..7cd6748 100644
--- a/src/com/android/settings/CreateShortcut.java
+++ b/src/com/android/settings/CreateShortcut.java
@@ -85,6 +85,11 @@
         return false;
     }
 
+    @Override
+    protected void onSetContentView() {
+        setContentView(R.layout.activity_list);
+    }
+
     /**
      * Perform query on package manager for list items.  The default
      * implementation queries for activities.
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index 2a8eaf6..06d8c2d 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -147,11 +147,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return null;
     }
diff --git a/src/com/android/settings/accounts/AddUserWhenLockedPreferenceController.java b/src/com/android/settings/accounts/AddUserWhenLockedPreferenceController.java
index 898d4a2..10e3610 100644
--- a/src/com/android/settings/accounts/AddUserWhenLockedPreferenceController.java
+++ b/src/com/android/settings/accounts/AddUserWhenLockedPreferenceController.java
@@ -71,11 +71,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         return mUserCaps.isAdmin() &&
                 (!mUserCaps.disallowAddUser() || mUserCaps.disallowAddUserSetByAdmin());
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 37b4b96..099d30e 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -767,6 +767,12 @@
         private boolean mHasReceivedLoadEntries;
         private boolean mHasReceivedBridgeCallback;
 
+        // These two variables are used to remember and restore the last scroll position when this
+        // fragment is paused. We need this special handling because app entries are added gradually
+        // when we rebuild the list after the user made some changes, like uninstalling an app.
+        private int mLastIndex = -1;
+        private int mLastTop;
+
         private AlphabeticIndex.ImmutableIndex<Locale> mIndex;
         private SectionInfo[] mSections = EMPTY_SECTIONS;
         private int[] mPositionToSectionIndex;
@@ -851,6 +857,10 @@
                     mExtraInfoBridge.pause();
                 }
             }
+            // Record the current scroll position before pausing.
+            mLastIndex = mManageApplications.mListView.getFirstVisiblePosition();
+            View v = mManageApplications.mListView.getChildAt(0);
+            mLastTop = (v == null) ? 0 : (v.getTop() - mManageApplications.mListView.getPaddingTop());
         }
 
         public void release() {
@@ -971,6 +981,12 @@
             }
 
             notifyDataSetChanged();
+            // Restore the last scroll position if the number of entries added so far is bigger than
+            // it.
+            if (mLastIndex != -1 && getCount() > mLastIndex) {
+                mManageApplications.mListView.setSelectionFromTop(mLastIndex, mLastTop);
+                mLastIndex = -1;
+            }
 
             if (mSession.getAllApps().size() != 0
                     && mManageApplications.mListContainer.getVisibility() != View.VISIBLE) {
diff --git a/src/com/android/settings/connecteddevice/UsbModePreferenceController.java b/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
index f782e9e..5f700bd 100644
--- a/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
@@ -58,11 +58,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         return true;
     }
diff --git a/src/com/android/settings/core/PreferenceController.java b/src/com/android/settings/core/PreferenceController.java
index 93ffe36..8f551de 100644
--- a/src/com/android/settings/core/PreferenceController.java
+++ b/src/com/android/settings/core/PreferenceController.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
+
 import com.android.settings.search.SearchIndexableRaw;
 
 import java.util.List;
@@ -27,7 +28,7 @@
  */
 public abstract class PreferenceController {
 
-    protected Context mContext;
+    protected final Context mContext;
 
     public PreferenceController(Context context) {
         mContext = context;
@@ -85,7 +86,9 @@
      * @param preference the preference being clicked
      * @return true if click is handled
      */
-    public abstract boolean handlePreferenceTreeClick(Preference preference);
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        return false;
+    }
 
     /**
      * Returns the key for this preference.
diff --git a/src/com/android/settings/dashboard/DashboardTilePlaceholderPreferenceController.java b/src/com/android/settings/dashboard/DashboardTilePlaceholderPreferenceController.java
index 6b0018c..eb99fb3 100644
--- a/src/com/android/settings/dashboard/DashboardTilePlaceholderPreferenceController.java
+++ b/src/com/android/settings/dashboard/DashboardTilePlaceholderPreferenceController.java
@@ -53,11 +53,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_PLACEHOLDER;
     }
diff --git a/src/com/android/settings/datetime/AutoTimePreferenceController.java b/src/com/android/settings/datetime/AutoTimePreferenceController.java
index a372a49..fdeef29 100644
--- a/src/com/android/settings/datetime/AutoTimePreferenceController.java
+++ b/src/com/android/settings/datetime/AutoTimePreferenceController.java
@@ -41,11 +41,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void updateState(Preference preference) {
         if (!(preference instanceof RestrictedSwitchPreference)) {
             return;
diff --git a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
index 760b2a0..c70289b 100644
--- a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
+++ b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
@@ -45,11 +45,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_AUTO_TIME_ZONE;
     }
diff --git a/src/com/android/settings/datetime/TimeZonePreferenceController.java b/src/com/android/settings/datetime/TimeZonePreferenceController.java
index 57c1bc7..f0b604e 100644
--- a/src/com/android/settings/datetime/TimeZonePreferenceController.java
+++ b/src/com/android/settings/datetime/TimeZonePreferenceController.java
@@ -49,11 +49,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_TIMEZONE;
     }
diff --git a/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java b/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
index 3435b53..8d35eca 100644
--- a/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
@@ -29,11 +29,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         return mContext.getResources().getBoolean(
                 com.android.settings.R.bool.config_additional_system_update_setting_enable);
diff --git a/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java b/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
index e64525b..f4dd14e 100644
--- a/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
@@ -35,11 +35,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         return mContext.getResources().getBoolean(R.bool.config_storage_manager_settings_enabled);
     }
diff --git a/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java b/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java
index 1029e20..0362bbc 100644
--- a/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java
@@ -56,11 +56,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_SERIAL_NUMBER;
     }
diff --git a/src/com/android/settings/display/AutoBrightnessPreferenceController.java b/src/com/android/settings/display/AutoBrightnessPreferenceController.java
index df2000e..1d644a4 100644
--- a/src/com/android/settings/display/AutoBrightnessPreferenceController.java
+++ b/src/com/android/settings/display/AutoBrightnessPreferenceController.java
@@ -46,11 +46,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void updateState(Preference preference) {
         int brightnessMode = Settings.System.getInt(mContext.getContentResolver(),
                 SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_MANUAL);
diff --git a/src/com/android/settings/display/AutoRotatePreferenceController.java b/src/com/android/settings/display/AutoRotatePreferenceController.java
index ee940a3..11c9333 100644
--- a/src/com/android/settings/display/AutoRotatePreferenceController.java
+++ b/src/com/android/settings/display/AutoRotatePreferenceController.java
@@ -68,11 +68,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         return RotationPolicy.isRotationLockToggleVisible(mContext);
     }
diff --git a/src/com/android/settings/display/CameraGesturePreferenceController.java b/src/com/android/settings/display/CameraGesturePreferenceController.java
index a3dc6cf..1b60721 100644
--- a/src/com/android/settings/display/CameraGesturePreferenceController.java
+++ b/src/com/android/settings/display/CameraGesturePreferenceController.java
@@ -38,11 +38,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void updateState(Preference preference) {
         int value = Settings.Secure.getInt(mContext.getContentResolver(),
                 CAMERA_GESTURE_DISABLED, 0);
diff --git a/src/com/android/settings/display/FontSizePreferenceController.java b/src/com/android/settings/display/FontSizePreferenceController.java
index 5014bda..7528f18 100644
--- a/src/com/android/settings/display/FontSizePreferenceController.java
+++ b/src/com/android/settings/display/FontSizePreferenceController.java
@@ -51,9 +51,4 @@
                 strEntryValues);
         preference.setSummary(entries[index]);
     }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
 }
diff --git a/src/com/android/settings/display/LiftToWakePreferenceController.java b/src/com/android/settings/display/LiftToWakePreferenceController.java
index 81ba5f5..e8be936 100644
--- a/src/com/android/settings/display/LiftToWakePreferenceController.java
+++ b/src/com/android/settings/display/LiftToWakePreferenceController.java
@@ -45,11 +45,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         boolean value = (Boolean) newValue;
         Settings.Secure.putInt(mContext.getContentResolver(), WAKE_GESTURE_ENABLED, value ? 1 : 0);
diff --git a/src/com/android/settings/display/NightDisplayPreferenceController.java b/src/com/android/settings/display/NightDisplayPreferenceController.java
index 9cf2409..4b18778 100644
--- a/src/com/android/settings/display/NightDisplayPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayPreferenceController.java
@@ -28,11 +28,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         return NightDisplayController.isAvailable(mContext);
     }
diff --git a/src/com/android/settings/display/NightModePreferenceController.java b/src/com/android/settings/display/NightModePreferenceController.java
index 874d84f..2eb64c0 100644
--- a/src/com/android/settings/display/NightModePreferenceController.java
+++ b/src/com/android/settings/display/NightModePreferenceController.java
@@ -62,11 +62,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         try {
             final int value = Integer.parseInt((String) newValue);
diff --git a/src/com/android/settings/display/ScreenSaverPreferenceController.java b/src/com/android/settings/display/ScreenSaverPreferenceController.java
index 7335b1f..fab9062 100644
--- a/src/com/android/settings/display/ScreenSaverPreferenceController.java
+++ b/src/com/android/settings/display/ScreenSaverPreferenceController.java
@@ -39,11 +39,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void updateState(Preference preference) {
         preference.setSummary(DreamSettings.getSummaryTextWithDreamName(mContext));
     }
diff --git a/src/com/android/settings/display/TapToWakePreferenceController.java b/src/com/android/settings/display/TapToWakePreferenceController.java
index 18c877a..1f24d74 100644
--- a/src/com/android/settings/display/TapToWakePreferenceController.java
+++ b/src/com/android/settings/display/TapToWakePreferenceController.java
@@ -41,11 +41,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void updateState(Preference preference) {
         int value = Settings.Secure.getInt(
                 mContext.getContentResolver(), Settings.Secure.DOUBLE_TAP_TO_WAKE, 0);
diff --git a/src/com/android/settings/display/TimeoutPreferenceController.java b/src/com/android/settings/display/TimeoutPreferenceController.java
index d33f813..d409656 100644
--- a/src/com/android/settings/display/TimeoutPreferenceController.java
+++ b/src/com/android/settings/display/TimeoutPreferenceController.java
@@ -52,11 +52,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void updateState(Preference preference) {
         final TimeoutListPreference timeoutListPreference = (TimeoutListPreference) preference;
         final long currentTimeout = Settings.System.getLong(mContext.getContentResolver(),
diff --git a/src/com/android/settings/display/VrDisplayPreferenceController.java b/src/com/android/settings/display/VrDisplayPreferenceController.java
index 61c3ed2..0eb1c88 100644
--- a/src/com/android/settings/display/VrDisplayPreferenceController.java
+++ b/src/com/android/settings/display/VrDisplayPreferenceController.java
@@ -74,9 +74,4 @@
         }
         return true;
     }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
 }
diff --git a/src/com/android/settings/display/WallpaperPreferenceController.java b/src/com/android/settings/display/WallpaperPreferenceController.java
index 8352377..aa29afc 100644
--- a/src/com/android/settings/display/WallpaperPreferenceController.java
+++ b/src/com/android/settings/display/WallpaperPreferenceController.java
@@ -46,11 +46,6 @@
         disablePreferenceIfManaged((RestrictedPreference) preference);
     }
 
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
     private void disablePreferenceIfManaged(RestrictedPreference pref) {
         final String restriction = DISALLOW_SET_WALLPAPER;
         if (pref != null) {
diff --git a/src/com/android/settings/enterprise/AdminActionPreferenceControllerBase.java b/src/com/android/settings/enterprise/AdminActionPreferenceControllerBase.java
index 67b1d13..99ff62e 100644
--- a/src/com/android/settings/enterprise/AdminActionPreferenceControllerBase.java
+++ b/src/com/android/settings/enterprise/AdminActionPreferenceControllerBase.java
@@ -50,9 +50,4 @@
     public boolean isAvailable() {
         return true;
     }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
 }
diff --git a/src/com/android/settings/enterprise/InstalledPackagesPreferenceController.java b/src/com/android/settings/enterprise/InstalledPackagesPreferenceController.java
index df1c6c4..a7afac0 100644
--- a/src/com/android/settings/enterprise/InstalledPackagesPreferenceController.java
+++ b/src/com/android/settings/enterprise/InstalledPackagesPreferenceController.java
@@ -51,11 +51,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_NUMBER_INSTALLED_PACKAGES;
     }
diff --git a/src/com/android/settings/gestures/GesturePreferenceController.java b/src/com/android/settings/gestures/GesturePreferenceController.java
index 345f7b7..ebfccb5 100644
--- a/src/com/android/settings/gestures/GesturePreferenceController.java
+++ b/src/com/android/settings/gestures/GesturePreferenceController.java
@@ -65,11 +65,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void onStop() {
         if (mVideoPreference != null) {
             mVideoPreference.onViewInvisible();
diff --git a/src/com/android/settings/gestures/SwipeToNotificationPreferenceController.java b/src/com/android/settings/gestures/SwipeToNotificationPreferenceController.java
index 01af974..08dc614 100644
--- a/src/com/android/settings/gestures/SwipeToNotificationPreferenceController.java
+++ b/src/com/android/settings/gestures/SwipeToNotificationPreferenceController.java
@@ -32,11 +32,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return PREF_KEY_SWIPE_DOWN_FINGERPRINT;
     }
diff --git a/src/com/android/settings/inputmethod/SpellCheckerPreferenceController.java b/src/com/android/settings/inputmethod/SpellCheckerPreferenceController.java
index 17d3fdc..8fcaa74 100644
--- a/src/com/android/settings/inputmethod/SpellCheckerPreferenceController.java
+++ b/src/com/android/settings/inputmethod/SpellCheckerPreferenceController.java
@@ -52,11 +52,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_SPELL_CHECKERS;
     }
diff --git a/src/com/android/settings/language/PhoneLanguagePreferenceController.java b/src/com/android/settings/language/PhoneLanguagePreferenceController.java
index 2b87fd9..cd2f539 100644
--- a/src/com/android/settings/language/PhoneLanguagePreferenceController.java
+++ b/src/com/android/settings/language/PhoneLanguagePreferenceController.java
@@ -36,11 +36,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void updateState(Preference preference) {
         if (preference == null) {
             return;
diff --git a/src/com/android/settings/language/TtsPreferenceController.java b/src/com/android/settings/language/TtsPreferenceController.java
index ffc1eb1..9b40b6d 100644
--- a/src/com/android/settings/language/TtsPreferenceController.java
+++ b/src/com/android/settings/language/TtsPreferenceController.java
@@ -49,11 +49,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_TTS_SETTINGS;
     }
diff --git a/src/com/android/settings/language/UserDictionaryPreferenceController.java b/src/com/android/settings/language/UserDictionaryPreferenceController.java
index d26761b..01ce3aa 100644
--- a/src/com/android/settings/language/UserDictionaryPreferenceController.java
+++ b/src/com/android/settings/language/UserDictionaryPreferenceController.java
@@ -44,11 +44,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_USER_DICTIONARY_SETTINGS;
     }
diff --git a/src/com/android/settings/network/MobileNetworkPreferenceController.java b/src/com/android/settings/network/MobileNetworkPreferenceController.java
index 588d80c..7c8cd40 100644
--- a/src/com/android/settings/network/MobileNetworkPreferenceController.java
+++ b/src/com/android/settings/network/MobileNetworkPreferenceController.java
@@ -40,11 +40,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         return !mIsSecondaryUser
                 && !Utils.isWifiOnly(mContext)
diff --git a/src/com/android/settings/network/NetworkResetPreferenceController.java b/src/com/android/settings/network/NetworkResetPreferenceController.java
index 2842139..e357fbe 100644
--- a/src/com/android/settings/network/NetworkResetPreferenceController.java
+++ b/src/com/android/settings/network/NetworkResetPreferenceController.java
@@ -32,11 +32,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         return !RestrictedLockUtils.hasBaseUserRestriction(mContext,
                 UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId());
diff --git a/src/com/android/settings/network/ProxyPreferenceController.java b/src/com/android/settings/network/ProxyPreferenceController.java
index 54b8ca9..edec247 100644
--- a/src/com/android/settings/network/ProxyPreferenceController.java
+++ b/src/com/android/settings/network/ProxyPreferenceController.java
@@ -31,11 +31,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         // proxy UI disabled until we have better app support
         return false;
diff --git a/src/com/android/settings/network/TetherPreferenceController.java b/src/com/android/settings/network/TetherPreferenceController.java
index f6ef678..e24c873 100644
--- a/src/com/android/settings/network/TetherPreferenceController.java
+++ b/src/com/android/settings/network/TetherPreferenceController.java
@@ -49,11 +49,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         final Preference preference = screen.findPreference(KEY_TETHER_SETTINGS);
diff --git a/src/com/android/settings/network/VpnPreferenceController.java b/src/com/android/settings/network/VpnPreferenceController.java
index 146b400..f7e230f 100644
--- a/src/com/android/settings/network/VpnPreferenceController.java
+++ b/src/com/android/settings/network/VpnPreferenceController.java
@@ -41,11 +41,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         // Manually set dependencies for Wifi when not toggleable.
diff --git a/src/com/android/settings/network/WifiCallingPreferenceController.java b/src/com/android/settings/network/WifiCallingPreferenceController.java
index 5036c46..b35d476 100644
--- a/src/com/android/settings/network/WifiCallingPreferenceController.java
+++ b/src/com/android/settings/network/WifiCallingPreferenceController.java
@@ -35,11 +35,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         final Preference pref = screen.findPreference(KEY_WFC_SETTINGS);
diff --git a/src/com/android/settings/nfc/NfcPreferenceController.java b/src/com/android/settings/nfc/NfcPreferenceController.java
index 6303d5b..65c2d4c 100644
--- a/src/com/android/settings/nfc/NfcPreferenceController.java
+++ b/src/com/android/settings/nfc/NfcPreferenceController.java
@@ -96,11 +96,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public boolean isAvailable() {
         return mNfcAdapter != null;
     }
diff --git a/src/com/android/settings/notification/AlarmRingtonePreferenceController.java b/src/com/android/settings/notification/AlarmRingtonePreferenceController.java
new file mode 100644
index 0000000..2e7aab0
--- /dev/null
+++ b/src/com/android/settings/notification/AlarmRingtonePreferenceController.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.media.RingtoneManager;
+
+public class AlarmRingtonePreferenceController extends RingtonePreferenceControllerBase {
+
+    private static final String KEY_ALARM_RINGTONE = "alarm_ringtone";
+
+    public AlarmRingtonePreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_ALARM_RINGTONE;
+    }
+
+    @Override
+    public int getRingtoneType() {
+        return RingtoneManager.TYPE_ALARM;
+    }
+}
diff --git a/src/com/android/settings/notification/CastPreferenceController.java b/src/com/android/settings/notification/CastPreferenceController.java
index 2ec7821..7de5c48 100644
--- a/src/com/android/settings/notification/CastPreferenceController.java
+++ b/src/com/android/settings/notification/CastPreferenceController.java
@@ -32,11 +32,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_WIFI_DISPLAY;
     }
diff --git a/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java b/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java
new file mode 100644
index 0000000..1154493
--- /dev/null
+++ b/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.v7.preference.Preference;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.accounts.AccountRestrictionHelper;
+import com.android.settings.core.PreferenceController;
+import com.android.settingslib.RestrictedPreference;
+
+/**
+ * Base class for preference controller that handles preference that enforce adjust volume
+ * restriction
+ */
+public class EmergencyBroadcastPreferenceController extends PreferenceController {
+
+    private static final String KEY_CELL_BROADCAST_SETTINGS = "cell_broadcast_settings";
+
+    private AccountRestrictionHelper mHelper;
+    private UserManager mUserManager;
+    private PackageManager mPm;
+    private boolean mCellBroadcastAppLinkEnabled;
+
+    public EmergencyBroadcastPreferenceController(Context context) {
+        this(context, new AccountRestrictionHelper(context));
+    }
+
+    @VisibleForTesting
+    EmergencyBroadcastPreferenceController(Context context, AccountRestrictionHelper helper) {
+        super(context);
+        mHelper = helper;
+        mUserManager = UserManager.get(context);
+        mPm = mContext.getPackageManager();
+        // Enable link to CMAS app settings depending on the value in config.xml.
+        mCellBroadcastAppLinkEnabled = isCellBroadcastAppLinkEnabled();
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (!(preference instanceof RestrictedPreference)) {
+            return;
+        }
+        ((RestrictedPreference) preference).checkRestrictionAndSetDisabled(
+            UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        return false;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_CELL_BROADCAST_SETTINGS;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mUserManager.isAdminUser() && mCellBroadcastAppLinkEnabled
+            && !mHelper.hasBaseUserRestriction(
+                UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, UserHandle.myUserId());
+    }
+
+    private boolean isCellBroadcastAppLinkEnabled() {
+        boolean enabled = mContext.getResources().getBoolean(
+            com.android.internal.R.bool.config_cellBroadcastAppLinks);
+        if (enabled) {
+            try {
+                if (mPm.getApplicationEnabledSetting("com.android.cellbroadcastreceiver")
+                    == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
+                    enabled = false;  // CMAS app disabled
+                }
+            } catch (IllegalArgumentException ignored) {
+                enabled = false;  // CMAS app not installed
+            }
+        }
+        return enabled;
+    }
+
+}
\ No newline at end of file
diff --git a/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java b/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java
index 15f8c9f..a7ebbe1 100644
--- a/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java
+++ b/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java
@@ -76,11 +76,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         mLockscreen =
diff --git a/src/com/android/settings/notification/NotificationRingtonePreferenceController.java b/src/com/android/settings/notification/NotificationRingtonePreferenceController.java
new file mode 100644
index 0000000..72e8d8f
--- /dev/null
+++ b/src/com/android/settings/notification/NotificationRingtonePreferenceController.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.media.RingtoneManager;
+
+public class NotificationRingtonePreferenceController extends RingtonePreferenceControllerBase {
+
+    private static final String KEY_NOTIFICATION_RINGTONE = "notification_ringtone";
+
+    public NotificationRingtonePreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_NOTIFICATION_RINGTONE;
+    }
+
+    @Override
+    public int getRingtoneType() {
+        return RingtoneManager.TYPE_NOTIFICATION;
+    }
+}
diff --git a/src/com/android/settings/notification/PhoneRingtonePreferenceController.java b/src/com/android/settings/notification/PhoneRingtonePreferenceController.java
new file mode 100644
index 0000000..cb11151
--- /dev/null
+++ b/src/com/android/settings/notification/PhoneRingtonePreferenceController.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.media.RingtoneManager;
+import com.android.settings.Utils;
+
+public class PhoneRingtonePreferenceController extends RingtonePreferenceControllerBase {
+
+    private static final String KEY_PHONE_RINGTONE = "ringtone";
+
+    public PhoneRingtonePreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_PHONE_RINGTONE;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return Utils.isVoiceCapable(mContext);
+    }
+
+    @Override
+    public int getRingtoneType() {
+        return RingtoneManager.TYPE_RINGTONE;
+    }
+}
diff --git a/src/com/android/settings/notification/PulseNotificationPreferenceController.java b/src/com/android/settings/notification/PulseNotificationPreferenceController.java
index de365f1..3e37ab0 100644
--- a/src/com/android/settings/notification/PulseNotificationPreferenceController.java
+++ b/src/com/android/settings/notification/PulseNotificationPreferenceController.java
@@ -69,11 +69,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_NOTIFICATION_PULSE;
     }
diff --git a/src/com/android/settings/notification/RingtonePreferenceControllerBase.java b/src/com/android/settings/notification/RingtonePreferenceControllerBase.java
new file mode 100644
index 0000000..333f08a
--- /dev/null
+++ b/src/com/android/settings/notification/RingtonePreferenceControllerBase.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.core.PreferenceController;
+
+public abstract class RingtonePreferenceControllerBase extends PreferenceController {
+
+    public RingtonePreferenceControllerBase(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        return false;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        Uri ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(mContext, getRingtoneType());
+        final CharSequence summary = Ringtone.getTitle(
+            mContext, ringtoneUri, false /* followSettingsUri */, true /* allowRemote */);
+        if (summary != null) {
+            preference.setSummary(summary);
+        }
+    }
+
+    public abstract int getRingtoneType();
+
+}
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index 1adfdd8..9166377 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -23,19 +23,15 @@
 import android.app.FragmentManager;
 import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -63,8 +59,6 @@
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.dashboard.SummaryLoader;
 import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.RestrictedPreference;
 
 import com.android.settingslib.drawer.CategoryKey;
 import java.text.NumberFormat;
@@ -76,12 +70,6 @@
         implements OnPreferenceChangeListener {
     private static final String TAG = "SoundSettings";
 
-    private static final String KEY_PHONE_RINGTONE = "ringtone";
-    private static final String KEY_NOTIFICATION_RINGTONE = "notification_ringtone";
-    private static final String KEY_ALARM_RINGTONE = "alarm_ringtone";
-    private static final String KEY_VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
-    private static final String KEY_CELL_BROADCAST_SETTINGS = "cell_broadcast_settings";
-
     private static final String KEY_WORK_CATEGORY = "sound_work_settings_section";
     private static final String KEY_WORK_USE_PERSONAL_SOUNDS = "work_use_personal_sounds";
     private static final String KEY_WORK_PHONE_RINGTONE = "work_ringtone";
@@ -95,23 +83,16 @@
 
     private final VolumePreferenceCallback mVolumeCallback = new VolumePreferenceCallback();
     private final H mHandler = new H();
-    private final SettingsObserver mSettingsObserver = new SettingsObserver();
 
     private Context mContext;
     private boolean mVoiceCapable;
 
-    private Preference mPhoneRingtonePreference;
-    private Preference mNotificationRingtonePreference;
-    private Preference mAlarmRingtonePreference;
-    private TwoStatePreference mVibrateWhenRinging;
-
     private PreferenceGroup mWorkPreferenceCategory;
     private TwoStatePreference mWorkUsePersonalSounds;
     private Preference mWorkPhoneRingtonePreference;
     private Preference mWorkNotificationRingtonePreference;
     private Preference mWorkAlarmRingtonePreference;
 
-    private PackageManager mPm;
     private UserManager mUserManager;
     private RingtonePreference mRequestPreference;
 
@@ -126,31 +107,9 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mContext = getActivity();
-        mPm = getPackageManager();
         mUserManager = UserManager.get(getContext());
         mVoiceCapable = Utils.isVoiceCapable(mContext);
 
-        // Enable link to CMAS app settings depending on the value in config.xml.
-        boolean isCellBroadcastAppLinkEnabled = this.getResources().getBoolean(
-                com.android.internal.R.bool.config_cellBroadcastAppLinks);
-        try {
-            if (isCellBroadcastAppLinkEnabled) {
-                if (mPm.getApplicationEnabledSetting("com.android.cellbroadcastreceiver")
-                        == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
-                    isCellBroadcastAppLinkEnabled = false;  // CMAS app disabled
-                }
-            }
-        } catch (IllegalArgumentException ignored) {
-            isCellBroadcastAppLinkEnabled = false;  // CMAS app not installed
-        }
-        if (!mUserManager.isAdminUser() || !isCellBroadcastAppLinkEnabled ||
-                RestrictedLockUtils.hasBaseUserRestriction(mContext,
-                        UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, UserHandle.myUserId())) {
-            removePreference(KEY_CELL_BROADCAST_SETTINGS);
-        }
-        initRingtones();
-        initVibrateWhenRinging();
-
         if (savedInstanceState != null) {
             String selectedPreference = savedInstanceState.getString(SELECTED_PREFERENCE_KEY, null);
             if (!TextUtils.isEmpty(selectedPreference)) {
@@ -162,15 +121,6 @@
     @Override
     public void onResume() {
         super.onResume();
-        lookupRingtoneNames();
-        mSettingsObserver.register(true);
-
-        RestrictedPreference broadcastSettingsPref = (RestrictedPreference) findPreference(
-                KEY_CELL_BROADCAST_SETTINGS);
-        if (broadcastSettingsPref != null) {
-            broadcastSettingsPref.checkRestrictionAndSetDisabled(
-                    UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
-        }
 
         mManagedProfileId = Utils.getManagedProfileId(mUserManager, UserHandle.myUserId());
         if (mManagedProfileId != UserHandle.USER_NULL && shouldShowRingtoneSettings()) {
@@ -191,7 +141,6 @@
     public void onPause() {
         super.onPause();
         mVolumeCallback.stopSample();
-        mSettingsObserver.register(false);
     }
 
     @Override
@@ -226,12 +175,21 @@
         Lifecycle lifecycle = getLifecycle();
         controllers.add(new CastPreferenceController(context));
         controllers.add(new ZenModePreferenceController(context));
+        controllers.add(new EmergencyBroadcastPreferenceController(context));
+        controllers.add(new VibrateWhenRingPreferenceController(context));
+
         // === Volumes ===
         controllers.add(new AlarmVolumePreferenceController(context, mVolumeCallback, lifecycle));
         controllers.add(new MediaVolumePreferenceController(context, mVolumeCallback, lifecycle));
         controllers.add(
             new NotificationVolumePreferenceController(context, mVolumeCallback, lifecycle));
         controllers.add(new RingVolumePreferenceController(context, mVolumeCallback, lifecycle));
+
+        // === Phone & notification ringtone ===
+        controllers.add(new PhoneRingtonePreferenceController(context));
+        controllers.add(new AlarmRingtonePreferenceController(context));
+        controllers.add(new NotificationRingtonePreferenceController(context));
+
         return controllers;
     }
 
@@ -314,48 +272,6 @@
         return !AudioSystem.isSingleVolume(mContext);
     }
 
-    private void initRingtones() {
-        mPhoneRingtonePreference = getPreferenceScreen().findPreference(KEY_PHONE_RINGTONE);
-        if (mPhoneRingtonePreference != null && !mVoiceCapable) {
-            getPreferenceScreen().removePreference(mPhoneRingtonePreference);
-            mPhoneRingtonePreference = null;
-        }
-        mNotificationRingtonePreference =
-                getPreferenceScreen().findPreference(KEY_NOTIFICATION_RINGTONE);
-        mAlarmRingtonePreference = getPreferenceScreen().findPreference(KEY_ALARM_RINGTONE);
-    }
-
-    private void lookupRingtoneNames() {
-        AsyncTask.execute(mLookupRingtoneNames);
-    }
-
-    private final Runnable mLookupRingtoneNames = new Runnable() {
-        @Override
-        public void run() {
-            if (mPhoneRingtonePreference != null) {
-                final CharSequence summary = updateRingtoneName(
-                        mContext, RingtoneManager.TYPE_RINGTONE);
-                if (summary != null) {
-                    mHandler.obtainMessage(H.UPDATE_PHONE_RINGTONE, summary).sendToTarget();
-                }
-            }
-            if (mNotificationRingtonePreference != null) {
-                final CharSequence summary = updateRingtoneName(
-                        mContext, RingtoneManager.TYPE_NOTIFICATION);
-                if (summary != null) {
-                    mHandler.obtainMessage(H.UPDATE_NOTIFICATION_RINGTONE, summary).sendToTarget();
-                }
-            }
-            if (mAlarmRingtonePreference != null) {
-                final CharSequence summary =
-                        updateRingtoneName(mContext, RingtoneManager.TYPE_ALARM);
-                if (summary != null) {
-                    mHandler.obtainMessage(H.UPDATE_ALARM_RINGTONE, summary).sendToTarget();
-                }
-            }
-        }
-    };
-
     private static CharSequence updateRingtoneName(Context context, int type) {
         if (context == null) {
             Log.e(TAG, "Unable to update ringtone name, no context provided");
@@ -366,74 +282,11 @@
                 true /* allowRemote */);
     }
 
-    // === Vibrate when ringing ===
-
-    private void initVibrateWhenRinging() {
-        mVibrateWhenRinging =
-                (TwoStatePreference) getPreferenceScreen().findPreference(KEY_VIBRATE_WHEN_RINGING);
-        if (mVibrateWhenRinging == null) {
-            Log.i(TAG, "Preference not found: " + KEY_VIBRATE_WHEN_RINGING);
-            return;
-        }
-        if (!mVoiceCapable) {
-            getPreferenceScreen().removePreference(mVibrateWhenRinging);
-            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);
-            }
-        });
-    }
-
-    private void updateVibrateWhenRinging() {
-        if (mVibrateWhenRinging == null) return;
-        mVibrateWhenRinging.setChecked(Settings.System.getInt(getContentResolver(),
-                Settings.System.VIBRATE_WHEN_RINGING, 0) != 0);
-    }
-
     // === Callbacks ===
 
-    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 static final int UPDATE_EFFECTS_SUPPRESSOR = 4;
-        private static final int UPDATE_RINGER_MODE = 5;
-        private static final int UPDATE_ALARM_RINGTONE = 6;
+        private static final int STOP_SAMPLE = 1;
 
         private H() {
             super(Looper.getMainLooper());
@@ -442,18 +295,9 @@
         @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;
-                case UPDATE_ALARM_RINGTONE:
-                    mAlarmRingtonePreference.setSummary((CharSequence) msg.obj);
-                    break;
             }
         }
     }
@@ -539,30 +383,9 @@
             new RingVolumePreferenceController(
                 context, null /* Callback */, null /* Lifecycle */).updateNonIndexableKeys(rt);
             new CastPreferenceController(context).updateNonIndexableKeys(rt);
-            if (!Utils.isVoiceCapable(context)) {
-                rt.add(KEY_PHONE_RINGTONE);
-                rt.add(KEY_VIBRATE_WHEN_RINGING);
-            }
-
-            final PackageManager pm = context.getPackageManager();
-            final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
-
-            // Enable link to CMAS app settings depending on the value in config.xml.
-            boolean isCellBroadcastAppLinkEnabled = context.getResources().getBoolean(
-                    com.android.internal.R.bool.config_cellBroadcastAppLinks);
-            try {
-                if (isCellBroadcastAppLinkEnabled) {
-                    if (pm.getApplicationEnabledSetting("com.android.cellbroadcastreceiver")
-                            == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
-                        isCellBroadcastAppLinkEnabled = false;  // CMAS app disabled
-                    }
-                }
-            } catch (IllegalArgumentException ignored) {
-                isCellBroadcastAppLinkEnabled = false;  // CMAS app not installed
-            }
-            if (!um.isAdminUser() || !isCellBroadcastAppLinkEnabled) {
-                rt.add(KEY_CELL_BROADCAST_SETTINGS);
-            }
+            new PhoneRingtonePreferenceController(context).updateNonIndexableKeys(rt);
+            new VibrateWhenRingPreferenceController(context).updateNonIndexableKeys(rt);
+            new EmergencyBroadcastPreferenceController(context).updateNonIndexableKeys(rt);
 
             return rt;
         }
diff --git a/src/com/android/settings/notification/VibrateWhenRingPreferenceController.java b/src/com/android/settings/notification/VibrateWhenRingPreferenceController.java
new file mode 100644
index 0000000..2160f3d
--- /dev/null
+++ b/src/com/android/settings/notification/VibrateWhenRingPreferenceController.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 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.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.TwoStatePreference;
+
+import com.android.settings.Utils;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.core.lifecycle.LifecycleObserver;
+import com.android.settings.core.lifecycle.events.OnPause;
+import com.android.settings.core.lifecycle.events.OnResume;
+
+import static android.provider.Settings.System.VIBRATE_WHEN_RINGING;
+
+public class VibrateWhenRingPreferenceController extends PreferenceController implements
+        Preference.OnPreferenceChangeListener, LifecycleObserver, OnResume, OnPause {
+
+    private static final String KEY_VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
+    private SettingObserver mSettingObserver;
+
+    public VibrateWhenRingPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        Preference preference = screen.findPreference(KEY_VIBRATE_WHEN_RINGING);
+        if (preference != null) {
+            mSettingObserver = new SettingObserver(preference);
+            preference.setPersistent(false);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        if (mSettingObserver != null) {
+            mSettingObserver.register(true /* register */);
+        }
+    }
+
+    @Override
+    public void onPause() {
+        if (mSettingObserver != null) {
+            mSettingObserver.register(false /* register */);
+        }
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        return false;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_VIBRATE_WHEN_RINGING;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return Utils.isVoiceCapable(mContext);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        ((TwoStatePreference) preference).setChecked(
+            Settings.System.getInt(mContext.getContentResolver(), VIBRATE_WHEN_RINGING, 0) != 0);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean val = (Boolean) newValue;
+        return Settings.System.putInt(mContext.getContentResolver(),
+            VIBRATE_WHEN_RINGING, val ? 1 : 0);
+    }
+
+    private final class SettingObserver extends ContentObserver {
+
+        private final Uri VIBRATE_WHEN_RINGING_URI =
+            Settings.System.getUriFor(VIBRATE_WHEN_RINGING);
+
+        private final Preference mPreference;
+
+        public SettingObserver(Preference preference) {
+            super(new Handler());
+            mPreference = preference;
+        }
+
+        public void register(boolean register) {
+            final ContentResolver cr = mContext.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)) {
+                updateState(mPreference);
+            }
+        }
+    }
+
+}
diff --git a/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java b/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java
index adc86b8..eeb9c28 100644
--- a/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java
+++ b/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java
@@ -17,8 +17,6 @@
 package com.android.settings.notification;
 
 import android.content.Context;
-
-import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.core.lifecycle.Lifecycle;
@@ -31,13 +29,13 @@
  * Base class for preference controller that handles VolumeSeekBarPreference
  */
 public abstract class VolumeSeekBarPreferenceController extends
-    AdjustVolumeRestrictedPreferenceController implements LifecycleObserver, OnResume, OnPause {
+        AdjustVolumeRestrictedPreferenceController implements LifecycleObserver, OnResume, OnPause {
 
     protected VolumeSeekBarPreference mPreference;
     protected VolumeSeekBarPreference.Callback mVolumePreferenceCallback;
 
     public VolumeSeekBarPreferenceController(Context context, Callback callback,
-        Lifecycle lifecycle) {
+            Lifecycle lifecycle) {
         super(context);
         mVolumePreferenceCallback = callback;
         if (lifecycle != null) {
@@ -70,11 +68,6 @@
         }
     }
 
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
     protected abstract int getAudioStream();
 
     protected abstract int getMuteIcon();
diff --git a/src/com/android/settings/notification/ZenModePreferenceController.java b/src/com/android/settings/notification/ZenModePreferenceController.java
index e554732..61bbe9a 100644
--- a/src/com/android/settings/notification/ZenModePreferenceController.java
+++ b/src/com/android/settings/notification/ZenModePreferenceController.java
@@ -17,7 +17,6 @@
 package com.android.settings.notification;
 
 import android.content.Context;
-import android.support.v7.preference.Preference;
 
 public class ZenModePreferenceController extends AdjustVolumeRestrictedPreferenceController {
 
@@ -28,11 +27,6 @@
     }
 
     @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    @Override
     public String getPreferenceKey() {
         return KEY_ZEN_MODE;
     }
diff --git a/tests/app/src/com/android/settings/CreateShortcutTest.java b/tests/app/src/com/android/settings/CreateShortcutTest.java
new file mode 100644
index 0000000..9481a64
--- /dev/null
+++ b/tests/app/src/com/android/settings/CreateShortcutTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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.app.Instrumentation;
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CreateShortcutTest {
+
+    @Test
+    public void test_layoutDoesNotHaveCancelButton() {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.startActivitySync(new Intent(Intent.ACTION_CREATE_SHORTCUT)
+                .setClassName(instrumentation.getTargetContext(),
+                        CreateShortcut.class.getName()));
+        onView(withText(R.string.cancel)).check(doesNotExist());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/AdjustVolumeRestrictedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/AdjustVolumeRestrictedPreferenceControllerTest.java
index 76e5a22..994582c 100644
--- a/tests/robotests/src/com/android/settings/notification/AdjustVolumeRestrictedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/AdjustVolumeRestrictedPreferenceControllerTest.java
@@ -28,7 +28,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
diff --git a/tests/robotests/src/com/android/settings/notification/AlarmRingtonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/AlarmRingtonePreferenceControllerTest.java
new file mode 100644
index 0000000..4ac9179
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/AlarmRingtonePreferenceControllerTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.media.RingtoneManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AlarmRingtonePreferenceControllerTest {
+
+    @Mock
+    private Context mContext;
+    private AlarmRingtonePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new AlarmRingtonePreferenceController(mContext);
+    }
+
+    @Test
+    public void getRingtoneType_shouldReturnAlarm() {
+        assertThat(mController.getRingtoneType()).isEqualTo(RingtoneManager.TYPE_ALARM);
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/notification/AlarmVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/AlarmVolumePreferenceControllerTest.java
index 11370e3..a08ec17 100644
--- a/tests/robotests/src/com/android/settings/notification/AlarmVolumePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/AlarmVolumePreferenceControllerTest.java
@@ -25,7 +25,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
diff --git a/tests/robotests/src/com/android/settings/notification/CastPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/CastPreferenceControllerTest.java
index 7f1888a..5fe4c42 100644
--- a/tests/robotests/src/com/android/settings/notification/CastPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/CastPreferenceControllerTest.java
@@ -28,7 +28,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
diff --git a/tests/robotests/src/com/android/settings/notification/EmergencyBroadcastPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/EmergencyBroadcastPreferenceControllerTest.java
new file mode 100644
index 0000000..98951d1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/EmergencyBroadcastPreferenceControllerTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.content.pm.PackageManager;
+import android.os.UserManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.accounts.AccountRestrictionHelper;
+import com.android.settingslib.RestrictedPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EmergencyBroadcastPreferenceControllerTest {
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    @Mock
+    private AccountRestrictionHelper mAccountHelper;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private RestrictedPreference mPreference;
+
+    private EmergencyBroadcastPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        mController = new EmergencyBroadcastPreferenceController(mContext, mAccountHelper);
+    }
+
+    @Test
+    public void updateState_shouldCheckRestriction() {
+        mController.updateState(mPreference);
+
+        verify(mPreference).checkRestrictionAndSetDisabled(anyString());
+    }
+
+    @Test
+    public void isAvailable_notAdminUser_shouldReturnFalse() {
+        when(mUserManager.isAdminUser()).thenReturn(false);
+        when(mContext.getResources().getBoolean(
+            com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(true);
+        when(mPackageManager.getApplicationEnabledSetting(anyString()))
+            .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+        when(mAccountHelper.hasBaseUserRestriction(anyString(), anyInt())).thenReturn(false);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_hasConfigCellBroadcastRestriction_shouldReturnFalse() {
+        when(mUserManager.isAdminUser()).thenReturn(true);
+        when(mContext.getResources().getBoolean(
+            com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(true);
+        when(mPackageManager.getApplicationEnabledSetting(anyString()))
+            .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+        when(mAccountHelper.hasBaseUserRestriction(
+            eq(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS), anyInt())).thenReturn(true);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_cellBroadcastAppLinkDisabled_shouldReturnFalse() {
+        when(mUserManager.isAdminUser()).thenReturn(true);
+        when(mContext.getResources().getBoolean(
+            com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(false);
+        when(mPackageManager.getApplicationEnabledSetting(anyString()))
+            .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+        when(mAccountHelper.hasBaseUserRestriction(anyString(), anyInt())).thenReturn(false);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_cellBroadcastReceiverDisabled_shouldReturnFalse() {
+        when(mUserManager.isAdminUser()).thenReturn(true);
+        when(mContext.getResources().getBoolean(
+            com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(true);
+        when(mPackageManager.getApplicationEnabledSetting(anyString()))
+            .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+        when(mAccountHelper.hasBaseUserRestriction(anyString(), anyInt())).thenReturn(false);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java
index 9c16937..9944379 100644
--- a/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/MediaVolumePreferenceControllerTest.java
@@ -25,7 +25,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationRingtonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationRingtonePreferenceControllerTest.java
new file mode 100644
index 0000000..841367f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/NotificationRingtonePreferenceControllerTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.media.RingtoneManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class NotificationRingtonePreferenceControllerTest {
+
+    @Mock
+    private Context mContext;
+    private NotificationRingtonePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new NotificationRingtonePreferenceController(mContext);
+    }
+
+    @Test
+    public void getRingtoneType_shouldReturnNotification() {
+        assertThat(mController.getRingtoneType()).isEqualTo(RingtoneManager.TYPE_NOTIFICATION);
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationVolumePreferenceControllerTest.java
index e0aa88e..e6d8a41 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationVolumePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationVolumePreferenceControllerTest.java
@@ -27,7 +27,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
diff --git a/tests/robotests/src/com/android/settings/notification/PhoneRingtonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/PhoneRingtonePreferenceControllerTest.java
new file mode 100644
index 0000000..85e74b0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/PhoneRingtonePreferenceControllerTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.media.RingtoneManager;
+import android.telephony.TelephonyManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class PhoneRingtonePreferenceControllerTest {
+
+    @Mock
+    private TelephonyManager mTelephonyManager;
+
+    private Context mContext;
+    private PhoneRingtonePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowContext = ShadowApplication.getInstance();
+        shadowContext.setSystemService(Context.TELEPHONY_SERVICE, mTelephonyManager);
+        mContext = shadowContext.getApplicationContext();
+        mController = new PhoneRingtonePreferenceController(mContext);
+    }
+
+    @Test
+    public void isAvailable_notVoiceCapable_shouldReturnFalse() {
+        when(mTelephonyManager.isVoiceCapable()).thenReturn(false);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_VoiceCapable_shouldReturnTrue() {
+        when(mTelephonyManager.isVoiceCapable()).thenReturn(true);
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void getRingtoneType_shouldReturnRingtone() {
+        assertThat(mController.getRingtoneType()).isEqualTo(RingtoneManager.TYPE_RINGTONE);
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/notification/RingVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/RingVolumePreferenceControllerTest.java
index 2d54cef..4780e5c 100644
--- a/tests/robotests/src/com/android/settings/notification/RingVolumePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/RingVolumePreferenceControllerTest.java
@@ -30,7 +30,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
diff --git a/tests/robotests/src/com/android/settings/notification/RingtonePreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/notification/RingtonePreferenceControllerBaseTest.java
new file mode 100644
index 0000000..d680c38
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/RingtonePreferenceControllerBaseTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.support.v7.preference.Preference;
+import android.media.RingtoneManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class RingtonePreferenceControllerBaseTest {
+
+    @Mock
+    private Context mContext;
+
+    private RingtonePreferenceControllerBase mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new RingtonePreferenceControllerBaseTestable(mContext);
+    }
+
+    @Test
+    public void isAlwaysAvailable() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+
+    @Test
+    public void updateState_shouldSetSummary() {
+        Preference preference = mock(Preference.class);
+
+        mController.updateState(preference);
+
+        verify(preference).setSummary(anyString());
+    }
+
+    private class RingtonePreferenceControllerBaseTestable extends
+        RingtonePreferenceControllerBase {
+        RingtonePreferenceControllerBaseTestable(Context context) {
+            super(context);
+        }
+
+        @Override
+        public String getPreferenceKey() {
+            return null;
+        }
+
+        @Override
+        public int getRingtoneType() {
+            return RingtoneManager.TYPE_RINGTONE;
+        }
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/notification/VibrateWhenRingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/VibrateWhenRingPreferenceControllerTest.java
new file mode 100644
index 0000000..3c3f212
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/VibrateWhenRingPreferenceControllerTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.provider.Settings;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.TwoStatePreference;
+import android.telephony.TelephonyManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import static android.provider.Settings.System.VIBRATE_WHEN_RINGING;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class VibrateWhenRingPreferenceControllerTest {
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+
+    private VibrateWhenRingPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
+        mController = new VibrateWhenRingPreferenceController(mContext);
+    }
+
+    @Test
+    public void display_voiceCapable_shouldDisplay() {
+        when(mTelephonyManager.isVoiceCapable()).thenReturn(true);
+        when(mScreen.findPreference(mController.getPreferenceKey()))
+            .thenReturn(mock(Preference.class));
+
+        mController.displayPreference(mScreen);
+
+        verify(mScreen, never()).removePreference(any(Preference.class));
+    }
+
+    @Test
+    public void display_notVoiceCapable_shouldNotDisplay() {
+        when(mTelephonyManager.isVoiceCapable()).thenReturn(false);
+        when(mScreen.findPreference(mController.getPreferenceKey()))
+                .thenReturn(mock(Preference.class));
+
+        mController.displayPreference(mScreen);
+
+        verify(mScreen).removePreference(any(Preference.class));
+    }
+
+    @Test
+    public void updateState_settingIsOn_preferenceShouldBeChecked() {
+        final TwoStatePreference preference = mock(TwoStatePreference.class);
+        final Context context = ShadowApplication.getInstance().getApplicationContext();
+        Settings.System.putInt(context.getContentResolver(), VIBRATE_WHEN_RINGING, 1);
+
+        mController = new VibrateWhenRingPreferenceController(context);
+        mController.updateState(preference);
+
+        verify(preference).setChecked(true);
+    }
+
+    @Test
+    public void updateState_settingIsOff_preferenceShouldNotBeChecked() {
+        final TwoStatePreference preference = mock(TwoStatePreference.class);
+        final Context context = ShadowApplication.getInstance().getApplicationContext();
+        Settings.System.putInt(context.getContentResolver(), VIBRATE_WHEN_RINGING, 0);
+
+        mController = new VibrateWhenRingPreferenceController(context);
+        mController.updateState(preference);
+
+        verify(preference).setChecked(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java
index 2d0aaeb..581ed47 100644
--- a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java
@@ -27,7 +27,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModePreferenceControllerTest.java
index 7b53a86..155e6ea 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModePreferenceControllerTest.java
@@ -24,7 +24,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;