Merge "Emulator: Have the Settings page say "About emulated device""
diff --git a/res/drawable/ic_settings_lock_outline.xml b/res/drawable/ic_settings_lock_outline.xml
deleted file mode 100644
index a13700b..0000000
--- a/res/drawable/ic_settings_lock_outline.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 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.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="21dp"
-        android:height="21dp"
-        android:viewportWidth="21.0"
-        android:viewportHeight="21.0"
-        android:tint="?android:attr/colorAccent">
-    <path
-            android:fillColor="@android:color/white"
-            android:pathData="M8,16c1.1,0,2-0.9,2-2s-0.9-2-2-2s-2,0.9-2,2S6.9,16,8,16zM14,7h-1V5c0-2.8-2.2-5-5-5S3,2.2,3,5v2H2C0.9,7,0,7.9,0,9v10c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V9C16,7.9,15.1,7,14,7z M4.9,5c0-1.7,1.4-3.1,3.1-3.1s3.1,1.4,3.1,3.1v2H4.9V5z M14,19H2V9h12V19z" />
-</vector>
diff --git a/res/layout/font_size_activity.xml b/res/layout/font_size_activity.xml
new file mode 100644
index 0000000..9072d38
--- /dev/null
+++ b/res/layout/font_size_activity.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="16dp"
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/font_size_preview_height"
+            android:background="?android:attr/colorBackgroundFloating"
+            android:elevation="2dp">
+
+            <view class="com.android.settings.TouchBlockingFrameLayout"
+                android:id="@+id/preview_frame"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
+            <TextView
+                android:id="@+id/current_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal|bottom"
+                android:padding="8dp"
+                android:theme="@android:style/Theme.Material"
+                android:background="?android:attr/colorBackgroundFloating"
+                android:textAppearance="@android:style/TextAppearance.Material.Caption"
+                android:textAllCaps="true"
+                android:elevation="2dp" />
+        </FrameLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="8dp">
+
+            <ImageView
+                android:id="@+id/smaller"
+                android:layout_width="48dp"
+                android:layout_height="48dp"
+                android:background="?android:attr/selectableItemBackgroundBorderless"
+                android:src="@drawable/ic_remove_24dp"
+                android:tint="?android:attr/colorControlNormal"
+                android:tintMode="src_in"
+                android:scaleType="center"
+                android:focusable="true"
+                android:contentDescription="@string/font_size_make_smaller_desc" />
+
+            <SeekBar
+                android:id="@+id/seek_bar"
+                android:layout_width="0dp"
+                android:layout_height="48dp"
+                android:layout_weight="1"
+                style="@android:style/Widget.Material.SeekBar.Discrete"/>
+
+            <ImageView
+                android:id="@+id/larger"
+                android:layout_width="48dp"
+                android:layout_height="48dp"
+                android:background="?android:attr/selectableItemBackgroundBorderless"
+                android:src="@drawable/ic_add_24dp"
+                android:tint="?android:attr/colorControlNormal"
+                android:tintMode="src_in"
+                android:scaleType="center"
+                android:focusable="true"
+                android:contentDescription="@string/font_size_make_larger_desc" />
+        </LinearLayout>
+    </LinearLayout>
+</ScrollView>
diff --git a/res/layout/font_size_preview.xml b/res/layout/font_size_preview.xml
new file mode 100644
index 0000000..1e3f69a
--- /dev/null
+++ b/res/layout/font_size_preview.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/font_size_preview_text_title"
+        android:textAppearance="@android:style/TextAppearance.Material.Title"/>
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/font_size_preview_text_subhead"
+        android:textAppearance="@android:style/TextAppearance.Material.Subhead"/>
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/font_size_preview_text_body"
+        android:textAppearance="@android:style/TextAppearance.Material.Body1"/>
+</LinearLayout>
diff --git a/res/layout/screen_zoom_activity.xml b/res/layout/screen_zoom_activity.xml
index 81ce102..a00e7bd 100644
--- a/res/layout/screen_zoom_activity.xml
+++ b/res/layout/screen_zoom_activity.xml
@@ -23,7 +23,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:paddingTop="16dp"
-        android:paddingLeft="?android:attr/listPreferredItemPaddingStart"
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
         android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
 
         <TextView
@@ -39,13 +39,13 @@
             android:background="?android:attr/colorBackgroundFloating"
             android:elevation="2dp">
 
-            <com.android.settings.display.TouchBlockingFrameLayout
+            <view class="com.android.settings.TouchBlockingFrameLayout"
                 android:id="@+id/preview_frame"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent" />
 
             <TextView
-                android:id="@+id/current_density"
+                android:id="@+id/current_label"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal|bottom"
@@ -78,7 +78,8 @@
                 android:id="@+id/seek_bar"
                 android:layout_width="0dp"
                 android:layout_height="48dp"
-                android:layout_weight="1" />
+                android:layout_weight="1"
+                style="@android:style/Widget.Material.SeekBar.Discrete"/>
 
             <ImageView
                 android:id="@+id/larger"
diff --git a/res/layout/spinner_dropdown_restricted_item.xml b/res/layout/spinner_dropdown_restricted_item.xml
deleted file mode 100644
index a965ad8..0000000
--- a/res/layout/spinner_dropdown_restricted_item.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@android:id/text1"
-        style="?android:attr/spinnerDropDownItemStyle"
-        android:singleLine="true"
-        android:layout_width="wrap_content"
-        android:layout_height="?android:attr/listPreferredItemHeightSmall"
-        android:ellipsize="marquee" />
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 5d7758b..f2b6305 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -109,8 +109,4 @@
     <!-- Confirm device credentials screen -->
     <attr name="confirmDeviceCredentialsSideMargin" format="dimension" />
     <attr name="confirmDeviceCredentialsTopMargin" format="dimension" />
-
-    <declare-styleable name="RestrictedPreference">
-        <attr name="userRestriction" format="string"/>
-    </declare-styleable>
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 5cf98fe..f3fea10 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -102,6 +102,4 @@
     <!-- Accent color that matches the settings launcher icon -->
     <color name="icon_accent">#ffabffec</color>
 
-    <color name="disabled_text_color">#66000000</color> <!-- 38% black -->
-
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f7c3437..6140c78 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -252,10 +252,6 @@
     <dimen name="shortcut_size">40dp</dimen>
     <dimen name="badge_size">10dp</dimen>
 
-    <!-- Lock icon for preferences locked by admin -->
-    <dimen name="restricted_lock_icon_size">16dp</dimen>
-    <dimen name="restricted_lock_icon_padding">4dp</dimen>
-
     <!-- Admin support contact details dialog. -->
     <dimen name="admin_details_dialog_padding">24dp</dimen>
     <dimen name="admin_details_dialog_icon_size">48dp</dimen>
@@ -270,4 +266,7 @@
     <!-- Accessibility Settings -->
     <dimen name="accessibility_layout_margin_start_end">24dp</dimen>
     <dimen name="accessibility_button_preference_padding_top_bottom">18dp</dimen>
+
+    <!-- Accessibility, Font size -->
+    <dimen name="font_size_preview_height">240dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 80fe71a..fb2b1e0 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -154,8 +154,16 @@
     <!-- choice for the font size spinner -->
     <string name="large_font">Large</string>
 
+    <!-- Description for the button that makes interface elements smaller. [CHAR_LIMIT=NONE] -->
+    <string name="font_size_make_smaller_desc">Make smaller</string>
+    <!-- Description for the button that makes interface elements larger. [CHAR_LIMIT=NONE] -->
+    <string name="font_size_make_larger_desc">Make larger</string>
+
     <!-- Do not translate. label for font size preview.  Does not need to be translated. -->
     <string name="font_size_preview_text">Servez à ce monsieur une bière et des kiwis.</string>
+    <string name="font_size_preview_text_title" translatable="false">Twenty Thousand Leagues Under The Sea</string>
+    <string name="font_size_preview_text_subhead" translatable="false">Chapter 23: The Coral Kingdom</string>
+    <string name="font_size_preview_text_body" translatable="false">The next day I woke with my head singularly clear. To my great surprise, I was in my own room. My companions, no doubt, had been reinstated in their cabin, without having perceived it any more than I. Of what had passed during the night they were as ignorant as I was, and to penetrate this mystery I only reckoned upon the chances of the future.</string>
     <!-- Button. Chosen when they want to save the chosen text size. -->
     <string name="font_size_save">OK</string>
 
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index 591bdad..42537b0 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -44,6 +44,11 @@
             android:title="@string/accessibility_screen_magnification_title"/>
 
         <PreferenceScreen
+                android:fragment="com.android.settings.accessibility.ToggleFontSizePreferenceFragment"
+                android:key="font_size_preference_screen"
+                android:title="@string/title_font_size"/>
+
+        <PreferenceScreen
             android:fragment="com.android.settings.accessibility.ToggleAutoclickPreferenceFragment"
             android:key="autoclick_preference_screen"
             android:title="@string/accessibility_autoclick_preference_title"/>
diff --git a/res/xml/accessibility_settings_for_setup_wizard.xml b/res/xml/accessibility_settings_for_setup_wizard.xml
index 742b897..f35d708 100644
--- a/res/xml/accessibility_settings_for_setup_wizard.xml
+++ b/res/xml/accessibility_settings_for_setup_wizard.xml
@@ -30,7 +30,7 @@
         android:layout="@layout/preference_button"
         android:title="@string/title_font_size" />
 
-    <com.android.settings.DisplayDensityPreference
+    <com.android.settings.display.ScreenZoomPreference
         android:key="force_density_preference"
         android:layout="@layout/preference_button"
         settings:keywords="@string/screen_zoom_keywords"
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index f9980dd..4ba0d39 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -26,7 +26,7 @@
             android:persistent="false" />
 
     <!-- When device is locked -->
-    <com.android.settings.RestrictedDropDownPreference
+    <com.android.settingslib.RestrictedDropDownPreference
             android:key="lock_screen_notifications"
             android:title="@string/lock_screen_notifications_title"
             android:summary="%s"
diff --git a/res/xml/privacy_settings.xml b/res/xml/privacy_settings.xml
index e014420..470edc2 100644
--- a/res/xml/privacy_settings.xml
+++ b/res/xml/privacy_settings.xml
@@ -54,7 +54,7 @@
         android:fragment="com.android.settings.ResetNetwork" />
 
     <!-- Factory reset -->
-    <com.android.settings.RestrictedPreference
+    <com.android.settingslib.RestrictedPreference
         android:key="factory_reset"
         android:title="@string/master_clear_title"
         settings:keywords="@string/keywords_factory_data_reset"
diff --git a/res/xml/security_settings_misc.xml b/res/xml/security_settings_misc.xml
index 41daa02..e0828e5 100644
--- a/res/xml/security_settings_misc.xml
+++ b/res/xml/security_settings_misc.xml
@@ -52,7 +52,7 @@
                 android:persistent="false"
                 android:fragment="com.android.settings.DeviceAdminSettings"/>
 
-        <com.android.settings.RestrictedSwitchPreference android:key="toggle_install_applications"
+        <com.android.settingslib.RestrictedSwitchPreference android:key="toggle_install_applications"
                 android:title="@string/install_applications"
                 android:summaryOff="@string/install_unknown_applications"
                 android:summaryOn="@string/install_unknown_applications"
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index 69dacf4..34bf00e 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -23,6 +23,7 @@
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.PackageOps;
 import android.app.Dialog;
+import android.app.DialogFragment;
 import android.app.UiModeManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.backup.IBackupManager;
@@ -1863,6 +1864,38 @@
                 requestCode, resources.getString(R.string.oem_unlock_enable));
     }
 
+    private boolean isPackageEnabled(String packageName) {
+        try {
+            PackageManager pm = getActivity().getPackageManager();
+            int enabled_state = pm.getApplicationEnabledSetting(packageName);
+            switch (enabled_state) {
+                case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
+                    return true;
+                case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
+                    return pm.getPackageInfo(packageName, 0).applicationInfo.enabled;
+                default:
+                    return false;
+            }
+        } catch (NameNotFoundException e) {
+            // Thrown by PackageManager.getPackageInfo if the package does not exist
+        } catch (IllegalArgumentException e) {
+            // Thrown by PackageManager.getApplicationEnabledSetting if the package does not exist
+        }
+        return false;
+    }
+
+    private void enableAndSetWebViewPackage(String packageName) {
+        getActivity().getPackageManager().setApplicationEnabledSetting(packageName,
+                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+        mWebViewProvider.setValue(packageName);
+        writeWebViewProviderOptions(packageName);
+    }
+
+    private void showEnableWebViewProviderAlert(final String packageName) {
+        EnableWebViewProviderDialogFragment.newInstance(packageName).show(
+                getChildFragmentManager(), EnableWebViewProviderDialogFragment.TAG);
+    }
+
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         if (HDCP_CHECKING_KEY.equals(preference.getKey())) {
@@ -1871,8 +1904,24 @@
             pokeSystemProperties();
             return true;
         } else if (preference == mWebViewProvider) {
-            writeWebViewProviderOptions(newValue);
-            return true;
+            if (newValue == null) {
+                Log.e(TAG, "Tried to set a null WebView provider");
+                return false;
+            }
+            String newWebViewPackageName = (String) newValue;
+            if (isPackageEnabled(newWebViewPackageName)) {
+                writeWebViewProviderOptions(newValue);
+                return true;
+            }
+            // Package is disabled or uninstalled, if it is simply disabled, check if the user wants
+            // to enable it
+            if (isPackageInstalled(getActivity(), newWebViewPackageName)) {
+                showEnableWebViewProviderAlert(newWebViewPackageName);
+                return false;
+            }
+            // Package has been uninstalled (could happen if the package was uninstalled between
+            // opening and closing the setting).
+            return false;
         } else if (preference == mLogdSize) {
             writeLogdSizeOption(newValue);
             return true;
@@ -2030,6 +2079,37 @@
         }
     }
 
+    public static class EnableWebViewProviderDialogFragment extends DialogFragment {
+        public static final String TAG = "EnableWebViewProviderDialogFragment";
+        private static final String PACKAGE_NAME_TAG = "packageName";
+
+        public static EnableWebViewProviderDialogFragment newInstance(String packageName) {
+            EnableWebViewProviderDialogFragment fragment
+                = new EnableWebViewProviderDialogFragment();
+            Bundle args = new Bundle();
+            args.putString(PACKAGE_NAME_TAG, packageName);
+            fragment.setArguments(args);
+            return fragment;
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final String packageName = getArguments().getString(PACKAGE_NAME_TAG);
+
+            return new AlertDialog.Builder(getActivity())
+                .setMessage(R.string.select_webview_provider_confirmation_text)
+                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        ((DevelopmentSettings)getParentFragment()).enableAndSetWebViewPackage(
+                            packageName);
+                    }
+                })
+                .setNegativeButton(android.R.string.cancel, null)
+                .create();
+        }
+    }
+
+
     /**
      * For Search.
      */
diff --git a/src/com/android/settings/InstrumentedFragment.java b/src/com/android/settings/InstrumentedFragment.java
index cc0014d..2d39961 100644
--- a/src/com/android/settings/InstrumentedFragment.java
+++ b/src/com/android/settings/InstrumentedFragment.java
@@ -33,6 +33,7 @@
     public static final int CONFIGURE_NOTIFICATION = UNDECLARED + 3;
     public static final int CONFIGURE_WIFI = UNDECLARED + 4;
     public static final int DISPLAY_SCREEN_ZOOM = UNDECLARED + 5;
+    public static final int ACCESSIBILITY_FONT_SIZE = UNDECLARED + 6;
 
     /**
      * Declare the view of this category.
diff --git a/src/com/android/settings/PreviewSeekBarPreferenceFragment.java b/src/com/android/settings/PreviewSeekBarPreferenceFragment.java
new file mode 100644
index 0000000..7a9efd3
--- /dev/null
+++ b/src/com/android/settings/PreviewSeekBarPreferenceFragment.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2015 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.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TextView;
+
+
+/**
+ * Preference fragment shows a preview and a seek bar to adjust a specific settings.
+ */
+public abstract class PreviewSeekBarPreferenceFragment extends SettingsPreferenceFragment {
+
+    /** List of entries corresponding the settings being set. */
+    protected String[] mEntries;
+
+    /** Index of the entry corresponding to initial value of the settings. */
+    protected int mInitialIndex;
+
+    /** Index of the entry corresponding to current value of the settings. */
+    protected int mCurrentIndex;
+
+    /** Resource id of the layout for this preference fragment. */
+    protected int mActivityLayoutResId;
+
+    /** Resource id of the layout that defines the contents instide preview screen. */
+    protected int mPreviewSampleResId;
+
+    /** Duration to use when cross-fading between previews. */
+    private static final long CROSS_FADE_DURATION_MS = 400;
+
+    /** Interpolator to use when cross-fading between previews. */
+    private static final Interpolator FADE_IN_INTERPOLATOR = new DecelerateInterpolator();
+
+    /** Interpolator to use when cross-fading between previews. */
+    private static final Interpolator FADE_OUT_INTERPOLATOR = new AccelerateInterpolator();
+
+    private ViewGroup mPreviewFrame;
+    private TextView mLabel;
+    private View mLarger;
+    private View mSmaller;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        final View root = super.onCreateView(inflater, container, savedInstanceState);
+        final ViewGroup listContainer = (ViewGroup) root.findViewById(android.R.id.list_container);
+        listContainer.removeAllViews();
+
+        final View content = inflater.inflate(mActivityLayoutResId, listContainer, false);
+        listContainer.addView(content);
+
+        mLabel = (TextView) content.findViewById(R.id.current_label);
+
+        // The maximum SeekBar value always needs to be non-zero. If there's
+        // only one available value, we'll handle this by disabling the
+        // seek bar.
+        final int max = Math.max(1, mEntries.length - 1);
+
+        final SeekBar seekBar = (SeekBar) content.findViewById(R.id.seek_bar);
+        seekBar.setMax(max);
+        seekBar.setProgress(mInitialIndex);
+        seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                setPreviewLayer(progress, true);
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {}
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {}
+        });
+
+        mSmaller = content.findViewById(R.id.smaller);
+        mSmaller.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                final int progress = seekBar.getProgress();
+                if (progress > 0) {
+                    seekBar.setProgress(progress - 1, true);
+                }
+            }
+        });
+
+        mLarger = content.findViewById(R.id.larger);
+        mLarger.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                final int progress = seekBar.getProgress();
+                if (progress < seekBar.getMax()) {
+                    seekBar.setProgress(progress + 1, true);
+                }
+            }
+        });
+
+        if (mEntries.length == 1) {
+            // The larger and smaller buttons will be disabled when we call
+            // setPreviewLayer() later in this method.
+            seekBar.setEnabled(false);
+        }
+
+        mPreviewFrame = (FrameLayout) content.findViewById(R.id.preview_frame);
+
+        // Populate the sample layouts.
+        final Context context = getContext();
+        final Configuration origConfig = context.getResources().getConfiguration();
+        for (int i = 0; i < mEntries.length; ++i) {
+            final Configuration config = createConfig(origConfig, i);
+
+            // Create a new configuration for the specified value. It won't
+            // have any theme set, so manually apply the current theme.
+            final Context configContext = context.createConfigurationContext(config);
+            configContext.setTheme(context.getThemeResId());
+
+            final LayoutInflater configInflater = LayoutInflater.from(configContext);
+            final View sampleView = configInflater.inflate(mPreviewSampleResId, mPreviewFrame, false);
+            sampleView.setAlpha(0);
+            sampleView.setVisibility(View.INVISIBLE);
+
+            mPreviewFrame.addView(sampleView);
+        }
+
+        setPreviewLayer(mInitialIndex, false);
+
+        return root;
+    }
+
+    @Override
+    public void onDetach() {
+        super.onDetach();
+
+        // This will commit the change SLIGHTLY after the activity has
+        // finished, which could be considered a feature or a bug...
+        commit();
+    }
+
+    /**
+     * Creates new configuration based on the current position of the SeekBar.
+     */
+    protected abstract Configuration createConfig(Configuration origConfig, int index);
+
+    private void setPreviewLayer(int index, boolean animate) {
+        mLabel.setText(mEntries[index]);
+
+        if (mCurrentIndex >= 0) {
+            final View lastLayer = mPreviewFrame.getChildAt(mCurrentIndex);
+            if (animate) {
+                lastLayer.animate()
+                        .alpha(0)
+                        .setInterpolator(FADE_OUT_INTERPOLATOR)
+                        .setDuration(CROSS_FADE_DURATION_MS)
+                        .withEndAction(new Runnable() {
+                            @Override
+                            public void run() {
+                                lastLayer.setVisibility(View.INVISIBLE);
+                            }
+                        });
+            } else {
+                lastLayer.setAlpha(0);
+                lastLayer.setVisibility(View.INVISIBLE);
+            }
+        }
+
+        final View nextLayer = mPreviewFrame.getChildAt(index);
+        if (animate) {
+            nextLayer.animate()
+                    .alpha(1)
+                    .setInterpolator(FADE_IN_INTERPOLATOR)
+                    .setDuration(CROSS_FADE_DURATION_MS)
+                    .withStartAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            nextLayer.setVisibility(View.VISIBLE);
+                        }
+                    });
+        } else {
+            nextLayer.setVisibility(View.VISIBLE);
+            nextLayer.setAlpha(1);
+        }
+
+        mSmaller.setEnabled(index > 0);
+        mLarger.setEnabled(index < mEntries.length - 1);
+
+        mCurrentIndex = index;
+    }
+
+    /**
+     * Persists the selected value and sends a configuration change.
+     */
+    protected abstract void commit();
+}
diff --git a/src/com/android/settings/RestrictedDropDownPreference.java b/src/com/android/settings/RestrictedDropDownPreference.java
deleted file mode 100644
index bed45fc..0000000
--- a/src/com/android/settings/RestrictedDropDownPreference.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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.content.Context;
-import android.graphics.drawable.Drawable;
-import android.support.v7.preference.DropDownPreference;
-import android.support.v7.preference.PreferenceViewHolder;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.android.settings.RestrictedLockUtils;
-
-import static com.android.settings.RestrictedLockUtils.EnforcedAdmin;
-
-public class RestrictedDropDownPreference extends DropDownPreference {
-    private Spinner mSpinner;
-    private final Drawable mRestrictedPadlock;
-    private final int mRestrictedPadlockPadding;
-    private List<RestrictedItem> mRestrictedItems = new ArrayList<>();
-
-    public RestrictedDropDownPreference(Context context) {
-        this(context, null);
-    }
-
-    public RestrictedDropDownPreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(context);
-        mRestrictedPadlockPadding = context.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_padding);
-    }
-
-    private final OnItemSelectedListener mItemSelectedListener = new OnItemSelectedListener() {
-        @Override
-        public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
-            if (position >= 0) {
-                String value = getEntryValues()[position].toString();
-                RestrictedItem item = getRestrictedItemForEntryValue(value);
-                if (item != null) {
-                    RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
-                            item.enforcedAdmin);
-                    mSpinner.setSelection(findIndexOfValue(getValue()));
-                } else if (!value.equals(getValue()) && callChangeListener(value)) {
-                    setValue(value);
-                }
-            }
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            // noop
-        }
-    };
-
-    @Override
-    protected ArrayAdapter createAdapter() {
-        return new RestrictedArrayItemAdapter(getContext());
-    }
-
-    @Override
-    public void setValue(String value) {
-        if (getRestrictedItemForEntryValue(value) != null) {
-            return;
-        }
-        super.setValue(value);
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder view) {
-        super.onBindViewHolder(view);
-        mSpinner = (Spinner) view.itemView.findViewById(R.id.spinner);
-        mSpinner.setOnItemSelectedListener(mItemSelectedListener);
-    }
-
-    private class RestrictedArrayItemAdapter extends ArrayAdapter<String> {
-        public RestrictedArrayItemAdapter(Context context) {
-            super(context, R.layout.spinner_dropdown_restricted_item);
-        }
-
-        @Override
-        public View getDropDownView(int position, View convertView, ViewGroup parent) {
-            TextView view = (TextView) super.getView(position, convertView, parent);
-            CharSequence entry = getItem(position);
-            boolean isEntryRestricted = isRestrictedForEntry(entry);
-            RestrictedLockUtils.setTextViewPadlock(getContext(), view, isEntryRestricted);
-            view.setEnabled(!isEntryRestricted);
-            return view;
-        }
-    }
-
-    private boolean isRestrictedForEntry(CharSequence entry) {
-        if (entry == null) {
-            return false;
-        }
-        for (RestrictedItem item : mRestrictedItems) {
-            if (entry.equals(item.entry)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private RestrictedItem getRestrictedItemForEntryValue(CharSequence entryValue) {
-        if (entryValue == null) {
-            return null;
-        }
-        for (RestrictedItem item : mRestrictedItems) {
-            if (entryValue.equals(item.entryValue)) {
-                return item;
-            }
-        }
-        return null;
-    }
-
-    public void addRestrictedItem(RestrictedItem item) {
-        mRestrictedItems.add(item);
-    }
-
-    public static class RestrictedItem {
-        public CharSequence entry;
-        public CharSequence entryValue;
-        public EnforcedAdmin enforcedAdmin;
-
-        public RestrictedItem(CharSequence entry, CharSequence entryValue,
-                EnforcedAdmin enforcedAdmin) {
-            this.entry = entry;
-            this.entryValue = entryValue;
-            this.enforcedAdmin = enforcedAdmin;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/settings/RestrictedLockImageSpan.java b/src/com/android/settings/RestrictedLockImageSpan.java
deleted file mode 100644
index 66c60cb..0000000
--- a/src/com/android/settings/RestrictedLockImageSpan.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.text.style.ImageSpan;
-
-import java.lang.ref.WeakReference;
-
-/**
- * An extension of ImageSpan which adds a padding before the image.
- */
-public class RestrictedLockImageSpan extends ImageSpan {
-    private Context mContext;
-    private final float mExtraPadding;
-    private final Drawable mRestrictedPadlock;
-
-    public RestrictedLockImageSpan(Context context) {
-        // we are overriding getDrawable, so passing null to super class here.
-        super((Drawable) null);
-
-        mContext = context;
-        mExtraPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_padding);
-        mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
-    }
-
-    @Override
-    public Drawable getDrawable() {
-        return mRestrictedPadlock;
-    }
-
-    @Override
-    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
-            int bottom, Paint paint) {
-        Drawable drawable = getDrawable();
-        canvas.save();
-
-        // Add extra padding before the padlock.
-        float transX = x + mExtraPadding;
-        float transY = bottom - drawable.getBounds().bottom - paint.getFontMetricsInt().descent;
-
-        canvas.translate(transX, transY);
-        drawable.draw(canvas);
-        canvas.restore();
-    }
-
-    @Override
-    public int getSize(Paint paint, CharSequence text, int start, int end,
-            Paint.FontMetricsInt fontMetrics) {
-        int size = super.getSize(paint, text, start, end, fontMetrics);
-        size += 2 * mExtraPadding;
-        return size;
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/settings/RestrictedLockUtils.java b/src/com/android/settings/RestrictedLockUtils.java
deleted file mode 100644
index 1a38763..0000000
--- a/src/com/android/settings/RestrictedLockUtils.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * 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.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.text.Spanned;
-import android.text.SpannableStringBuilder;
-import android.text.style.ForegroundColorSpan;
-import android.text.style.ImageSpan;
-import android.view.MenuItem;
-import android.widget.TextView;
-
-import java.util.List;
-
-/**
- * Utility class to host methods usable in adding a restricted padlock icon and showing admin
- * support message dialog.
- */
-public class RestrictedLockUtils {
-    /**
-     * @return drawables for displaying with settings that are locked by a device admin.
-     */
-    public static Drawable getRestrictedPadlock(Context context) {
-        Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_settings_lock_outline);
-        final int iconSize = context.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_size);
-        restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
-        return restrictedPadlock;
-    }
-
-    /**
-     * Checks if a restriction is enforced on a user and returns the enforced admin and
-     * admin userId.
-     *
-     * @param userRestriction Restriction to check
-     * @param userId User which we need to check if restriction is enforced on.
-     * @return EnforcedAdmin Object containing the enforce admin and admin user details, or
-     * {@code null} If the restriction is not set. If the restriction is set by both device owner
-     * and profile owner, then the admin will be set to {@code null} and userId to
-     * {@link UserHandle#USER_NULL}.
-     */
-    public static EnforcedAdmin checkIfRestrictionEnforced(Context context,
-            String userRestriction, int userId) {
-        DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
-                Context.DEVICE_POLICY_SERVICE);
-        ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnAnyUser();
-        int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
-        boolean enforcedByDeviceOwner = false;
-        if (deviceOwner != null && deviceOwnerUserId != UserHandle.USER_NULL) {
-            Bundle enforcedRestrictions = dpm.getUserRestrictions(deviceOwner, deviceOwnerUserId);
-            if (enforcedRestrictions != null
-                    && enforcedRestrictions.getBoolean(userRestriction, false)) {
-                enforcedByDeviceOwner = true;
-            }
-        }
-
-        ComponentName profileOwner = null;
-        boolean enforcedByProfileOwner = false;
-        if (userId != UserHandle.USER_NULL) {
-            profileOwner = dpm.getProfileOwnerAsUser(userId);
-            if (profileOwner != null) {
-                Bundle enforcedRestrictions = dpm.getUserRestrictions(profileOwner, userId);
-                if (enforcedRestrictions != null
-                        && enforcedRestrictions.getBoolean(userRestriction, false)) {
-                    enforcedByProfileOwner = true;
-                }
-            }
-        }
-
-        if (!enforcedByDeviceOwner && !enforcedByProfileOwner) {
-            return null;
-        }
-
-        EnforcedAdmin admin = null;
-        if (enforcedByDeviceOwner && enforcedByProfileOwner) {
-            admin = new EnforcedAdmin();
-        } else if (enforcedByDeviceOwner) {
-            admin = new EnforcedAdmin(deviceOwner, deviceOwnerUserId);
-        } else {
-            admin = new EnforcedAdmin(profileOwner, userId);
-        }
-        return admin;
-    }
-
-    /**
-     * Checks if lock screen notification features are disabled by policy. This should be
-     * only used for keyguard notification features but not the keyguard features
-     * (e.g. KEYGUARD_DISABLE_FINGERPRINT) where a profile owner can set them on the parent user
-     * as it won't work for that case.
-     *
-     * @param keyguardNotificationFeatures Could be any of notification features that can be
-     * disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}.
-     * @return EnforcedAdmin Object containing the enforce admin and admin user details, or
-     * {@code null} If the notification features are not disabled. If the restriction is set by
-     * multiple admins, then the admin will be set to {@code null} and userId to
-     * {@link UserHandle#USER_NULL}.
-     */
-    public static EnforcedAdmin checkIfKeyguardNotificationFeaturesDisabled(Context context,
-            int keyguardNotificationFeatures) {
-        final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
-                Context.DEVICE_POLICY_SERVICE);
-        boolean isDisabledByMultipleAdmins = false;
-        ComponentName adminComponent = null;
-        List<ComponentName> admins = dpm.getActiveAdmins();
-        int disabledKeyguardFeatures;
-        for (ComponentName admin : admins) {
-            disabledKeyguardFeatures = dpm.getKeyguardDisabledFeatures(admin);
-            if ((disabledKeyguardFeatures & keyguardNotificationFeatures) != 0) {
-                if (adminComponent == null) {
-                    adminComponent = admin;
-                } else {
-                    isDisabledByMultipleAdmins = true;
-                    break;
-                }
-            }
-        }
-        EnforcedAdmin enforcedAdmin = null;
-        if (adminComponent != null) {
-            if (!isDisabledByMultipleAdmins) {
-                enforcedAdmin = new EnforcedAdmin(adminComponent, UserHandle.myUserId());
-            } else {
-                enforcedAdmin = new EnforcedAdmin();
-            }
-        }
-        return enforcedAdmin;
-    }
-
-    /**
-     * Set the menu item as disabled by admin by adding a restricted padlock at the end of the
-     * text and set the click listener which will send an intent to show the admin support details
-     * dialog.
-     */
-    public static void setMenuItemAsDisabledByAdmin(final Context context,
-            final MenuItem item, final EnforcedAdmin admin) {
-        SpannableStringBuilder sb = new SpannableStringBuilder(item.getTitle());
-        removeExistingRestrictedSpans(sb);
-
-        final int disabledColor = context.getColor(R.color.disabled_text_color);
-        sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
-                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-        ImageSpan image = new RestrictedLockImageSpan(context);
-        sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-        item.setTitle(sb);
-
-        item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-            @Override
-            public boolean onMenuItemClick(MenuItem item) {
-                sendShowAdminSupportDetailsIntent(context, admin);
-                return true;
-            }
-        });
-    }
-
-    private static void removeExistingRestrictedSpans(SpannableStringBuilder sb) {
-        final int length = sb.length();
-        RestrictedLockImageSpan[] imageSpans = sb.getSpans(length - 1, length,
-                RestrictedLockImageSpan.class);
-        for (ImageSpan span : imageSpans) {
-            sb.removeSpan(span);
-        }
-        ForegroundColorSpan[] colorSpans = sb.getSpans(0, length, ForegroundColorSpan.class);
-        for (ForegroundColorSpan span : colorSpans) {
-            sb.removeSpan(span);
-        }
-    }
-
-    /**
-     * Send the intent to trigger the {@link android.settings.ShowAdminSupportDetailsDialog}.
-     */
-    public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
-        Intent intent = new Intent(context, ShowAdminSupportDetailsDialog.class);
-        int adminUserId = UserHandle.myUserId();
-        if (admin != null) {
-            if (admin.component != null) {
-                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
-            }
-            if (admin.userId != UserHandle.USER_NULL) {
-                adminUserId = admin.userId;
-            }
-            intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
-        }
-        context.startActivityAsUser(intent, new UserHandle(adminUserId));
-    }
-
-    public static void setTextViewPadlock(Context context,
-            TextView textView, boolean showPadlock) {
-        final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
-        removeExistingRestrictedSpans(sb);
-        if (showPadlock) {
-            final ImageSpan image = new RestrictedLockImageSpan(context);
-            sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-        }
-        textView.setText(sb);
-    }
-
-    public static class EnforcedAdmin {
-        public ComponentName component = null;
-        public int userId = UserHandle.USER_NULL;
-
-        public EnforcedAdmin(ComponentName component, int userId) {
-            this.component = component;
-            this.userId = userId;
-        }
-
-        public EnforcedAdmin() {}
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/settings/RestrictedPreference.java b/src/com/android/settings/RestrictedPreference.java
deleted file mode 100644
index 5ac52cb..0000000
--- a/src/com/android/settings/RestrictedPreference.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.settings;
-
-import android.content.Context;
-import android.os.UserHandle;
-import android.support.v4.content.res.TypedArrayUtils;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceManager;
-import android.support.v7.preference.PreferenceViewHolder;
-import android.util.AttributeSet;
-
-import static com.android.settings.RestrictedLockUtils.EnforcedAdmin;
-
-/**
- * Preference class that supports being disabled by a user restriction
- * set by a device admin.
- */
-public class RestrictedPreference extends Preference {
-    RestrictedPreferenceHelper mHelper;
-
-    public RestrictedPreference(Context context, AttributeSet attrs,
-            int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mHelper = new RestrictedPreferenceHelper(context, this, attrs);
-    }
-
-    public RestrictedPreference(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public RestrictedPreference(Context context, AttributeSet attrs) {
-        this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.preferenceStyle,
-                android.R.attr.preferenceStyle));
-    }
-
-    public RestrictedPreference(Context context) {
-        this(context, null);
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder holder) {
-        super.onBindViewHolder(holder);
-        mHelper.onBindViewHolder(holder);
-    }
-
-    @Override
-    public void performClick() {
-        if (!mHelper.performClick()) {
-            super.performClick();
-        }
-    }
-
-    @Override
-    protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
-        mHelper.onAttachedToHierarchy();
-        super.onAttachedToHierarchy(preferenceManager);
-    }
-
-    public void checkRestrictionAndSetDisabled(String userRestriction) {
-        mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
-    }
-
-    public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
-        mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
-    }
-
-    public void setDisabledByAdmin(EnforcedAdmin admin) {
-        if (mHelper.setDisabledByAdmin(admin)) {
-            notifyChanged();
-        }
-    }
-
-    public boolean isDisabledByAdmin() {
-        return mHelper.isDisabledByAdmin();
-    }
-}
diff --git a/src/com/android/settings/RestrictedPreferenceHelper.java b/src/com/android/settings/RestrictedPreferenceHelper.java
deleted file mode 100644
index f0c0bf7..0000000
--- a/src/com/android/settings/RestrictedPreferenceHelper.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.settings;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceViewHolder;
-import android.text.Spanned;
-import android.text.SpannableStringBuilder;
-import android.text.style.ImageSpan;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.widget.TextView;
-
-import static com.android.settings.RestrictedLockUtils.EnforcedAdmin;
-
-/**
- * Helper class for managing settings preferences that can be disabled
- * by device admins via user restrictions.
- */
-public class RestrictedPreferenceHelper {
-    private final Context mContext;
-    private final Preference mPreference;
-    private final Drawable mRestrictedPadlock;
-    private final int mRestrictedPadlockPadding;
-
-    private boolean mDisabledByAdmin;
-    private EnforcedAdmin mEnforcedAdmin;
-    private String mAttrUserRestriction = null;
-
-    RestrictedPreferenceHelper(Context context, Preference preference,
-            AttributeSet attrs) {
-        mContext = context;
-        mPreference = preference;
-
-        mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
-        mRestrictedPadlockPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_padding);
-
-        mAttrUserRestriction = attrs.getAttributeValue(
-                R.styleable.RestrictedPreference_userRestriction);
-        final TypedArray attributes = context.obtainStyledAttributes(attrs,
-                R.styleable.RestrictedPreference);
-        final TypedValue userRestriction =
-                attributes.peekValue(R.styleable.RestrictedPreference_userRestriction);
-        CharSequence data = null;
-        if (userRestriction != null && userRestriction.type == TypedValue.TYPE_STRING) {
-            if (userRestriction.resourceId != 0) {
-                data = context.getText(userRestriction.resourceId);
-            } else {
-                data = userRestriction.string;
-            }
-        }
-        mAttrUserRestriction = data == null ? null : data.toString();
-    }
-
-    /**
-     * Modify PreferenceViewHolder to add padlock if restriction is disabled.
-     */
-    public void onBindViewHolder(PreferenceViewHolder holder) {
-        final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
-        if (titleView != null) {
-            RestrictedLockUtils.setTextViewPadlock(mContext, titleView, mDisabledByAdmin);
-            if (mDisabledByAdmin) {
-                holder.itemView.setEnabled(true);
-            }
-        }
-    }
-
-    /**
-     * Check if the preference is disabled if so handle the click by informing the user.
-     *
-     * @return true if the method handled the click.
-     */
-    public boolean performClick() {
-        if (mDisabledByAdmin) {
-            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mEnforcedAdmin);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Disable / enable if we have been passed the restriction in the xml.
-     */
-    protected void onAttachedToHierarchy() {
-        if (mAttrUserRestriction != null) {
-            checkRestrictionAndSetDisabled(mAttrUserRestriction, UserHandle.myUserId());
-        }
-    }
-
-    /**
-     * Set the user restriction that is used to disable this preference.
-     *
-     * @param userRestriction constant from {@link android.os.UserManager}
-     * @param userId user to check the restriction for.
-     */
-    public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
-        EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
-                userRestriction, userId);
-        setDisabledByAdmin(admin);
-    }
-
-    /**
-     * Disable this preference based on the enforce admin.
-     *
-     * @param EnforcedAdmin Details of the admin who enforced the restriction. If it
-     * is {@code null}, then this preference will be enabled. Otherwise, it will be disabled.
-     * @return true if the disabled state was changed.
-     */
-    public boolean setDisabledByAdmin(EnforcedAdmin admin) {
-        final boolean disabled = (admin != null ? true : false);
-        mEnforcedAdmin = (disabled ? admin : null);
-        if (mDisabledByAdmin != disabled) {
-            mDisabledByAdmin = disabled;
-            mPreference.setEnabled(!disabled);
-            return true;
-        }
-        return false;
-    }
-
-    public boolean isDisabledByAdmin() {
-        return mDisabledByAdmin;
-    }
-}
diff --git a/src/com/android/settings/RestrictedSwitchPreference.java b/src/com/android/settings/RestrictedSwitchPreference.java
deleted file mode 100644
index f0c3315..0000000
--- a/src/com/android/settings/RestrictedSwitchPreference.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.settings;
-
-import android.content.Context;
-import android.os.UserHandle;
-import android.support.v4.content.res.TypedArrayUtils;
-import android.support.v7.preference.PreferenceManager;
-import android.support.v7.preference.PreferenceViewHolder;
-import android.support.v14.preference.SwitchPreference;
-import android.util.AttributeSet;
-
-import static com.android.settings.RestrictedLockUtils.EnforcedAdmin;
-
-/**
- * Version of SwitchPreference that can be disabled by a device admin
- * using a user restriction.
- */
-public class RestrictedSwitchPreference extends SwitchPreference {
-    RestrictedPreferenceHelper mHelper;
-
-    public RestrictedSwitchPreference(Context context, AttributeSet attrs,
-            int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mHelper = new RestrictedPreferenceHelper(context, this, attrs);
-    }
-
-    public RestrictedSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public RestrictedSwitchPreference(Context context, AttributeSet attrs) {
-        this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.switchPreferenceStyle,
-                android.R.attr.switchPreferenceStyle));
-    }
-
-    public RestrictedSwitchPreference(Context context) {
-        this(context, null);
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder holder) {
-        super.onBindViewHolder(holder);
-        mHelper.onBindViewHolder(holder);
-    }
-
-    @Override
-    public void performClick() {
-        if (!mHelper.performClick()) {
-            super.performClick();
-        }
-    }
-
-    @Override
-    protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
-        mHelper.onAttachedToHierarchy();
-        super.onAttachedToHierarchy(preferenceManager);
-    }
-
-    public void checkRestrictionAndSetDisabled(String userRestriction) {
-        mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
-    }
-
-    public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
-        mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
-    }
-
-    public void setDisabledByAdmin(EnforcedAdmin admin) {
-        if (mHelper.setDisabledByAdmin(admin)) {
-            notifyChanged();
-        }
-    }
-
-    public boolean isDisabledByAdmin() {
-        return mHelper.isDisabledByAdmin();
-    }
-}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 4e9447e..9ffa1f2 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -61,6 +61,7 @@
 import com.android.settings.search.Index;
 import com.android.settings.search.Indexable;
 import com.android.settings.search.SearchIndexableRaw;
+import com.android.settingslib.RestrictedSwitchPreference;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/com/android/settings/display/TouchBlockingFrameLayout.java b/src/com/android/settings/TouchBlockingFrameLayout.java
similarity index 96%
rename from src/com/android/settings/display/TouchBlockingFrameLayout.java
rename to src/com/android/settings/TouchBlockingFrameLayout.java
index 3f5483d..8b36635 100644
--- a/src/com/android/settings/display/TouchBlockingFrameLayout.java
+++ b/src/com/android/settings/TouchBlockingFrameLayout.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settings.display;
+package com.android.settings;
 
 import android.annotation.Nullable;
 import android.content.Context;
diff --git a/src/com/android/settings/accessibility/ToggleFontSizePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFontSizePreferenceFragment.java
new file mode 100644
index 0000000..8b9e27b
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleFontSizePreferenceFragment.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 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.accessibility;
+
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+import com.android.settings.PreviewSeekBarPreferenceFragment;
+
+import android.annotation.Nullable;
+import android.app.ActivityManagerNative;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Preference fragment used to control font size.
+ */
+public class ToggleFontSizePreferenceFragment extends PreviewSeekBarPreferenceFragment {
+    private static final String LOG_TAG = "ToggleFontSizePreferenceFragment";
+
+    private float[] mValues;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mActivityLayoutResId = R.layout.font_size_activity;
+        mPreviewSampleResId = R.layout.font_size_preview;
+
+        Resources res = getContext().getResources();
+        // Mark the appropriate item in the preferences list.
+        final Configuration origConfig = res.getConfiguration();
+        mEntries = res.getStringArray(R.array.entries_font_size);
+        final String[] strEntryValues = res.getStringArray(R.array.entryvalues_font_size);
+        mInitialIndex = floatToIndex(origConfig.fontScale, strEntryValues);
+        mValues = new float[strEntryValues.length];
+        for (int i = 0; i < strEntryValues.length; ++i) {
+            mValues[i] = Float.parseFloat(strEntryValues[i]);
+        }
+    }
+
+    @Override
+    protected Configuration createConfig(Configuration origConfig, int index) {
+        // Populate the sample layouts.
+        final Configuration config = new Configuration(origConfig);
+        config.fontScale = mValues[index];
+        return config;
+    }
+
+    /**
+     * Persists the selected font size and sends a configuration change.
+     */
+    @Override
+    protected void commit() {
+        Configuration config = getContext().getResources().getConfiguration();
+        config.fontScale = mValues[mCurrentIndex];
+        try {
+            ActivityManagerNative.getDefault().updatePersistentConfiguration(config);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Unable to save font size setting");
+        }
+    }
+
+    @Override
+    protected int getMetricsCategory() {
+        return InstrumentedFragment.ACCESSIBILITY_FONT_SIZE;
+    }
+
+    private int floatToIndex(float val, String[] indices) {
+        float lastVal = Float.parseFloat(indices[0]);
+        for (int i=1; i<indices.length; i++) {
+            float thisVal = Float.parseFloat(indices[i]);
+            if (val < (lastVal + (thisVal-lastVal)*.5f)) {
+                return i-1;
+            }
+            lastVal = thisVal;
+        }
+        return indices.length-1;
+    }
+
+}
\ No newline at end of file
diff --git a/src/com/android/settings/accounts/AccountSyncSettings.java b/src/com/android/settings/accounts/AccountSyncSettings.java
index a060c76..ded97d3 100644
--- a/src/com/android/settings/accounts/AccountSyncSettings.java
+++ b/src/com/android/settings/accounts/AccountSyncSettings.java
@@ -54,9 +54,9 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.settings.R;
-import com.android.settings.RestrictedLockUtils;
 import com.android.settings.ShowAdminSupportDetailsDialog;
 import com.android.settings.Utils;
+import com.android.settingslib.RestrictedLockUtils;
 import com.google.android.collect.Lists;
 
 import java.io.IOException;
@@ -65,7 +65,7 @@
 import java.util.Date;
 import java.util.List;
 
-import static com.android.settings.RestrictedLockUtils.EnforcedAdmin;
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
 public class AccountSyncSettings extends AccountPreferenceBase {
 
diff --git a/src/com/android/settings/display/ScreenZoomSettings.java b/src/com/android/settings/display/ScreenZoomSettings.java
index 1ddcaab..7e8ac22 100644
--- a/src/com/android/settings/display/ScreenZoomSettings.java
+++ b/src/com/android/settings/display/ScreenZoomSettings.java
@@ -18,7 +18,7 @@
 
 import com.android.settings.InstrumentedFragment;
 import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.PreviewSeekBarPreferenceFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settings.search.SearchIndexableRaw;
@@ -29,17 +29,6 @@
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.view.Display;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
-import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
-import android.widget.TextView;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -47,32 +36,17 @@
 /**
  * Preference fragment used to control screen zoom.
  */
-public class ScreenZoomSettings extends SettingsPreferenceFragment implements Indexable {
-    /** Duration to use when cross-fading between previews. */
-    private static final long CROSS_FADE_DURATION_MS = 400;
+public class ScreenZoomSettings extends PreviewSeekBarPreferenceFragment implements Indexable {
 
-    /** Interpolator to use when cross-fading between previews. */
-    private static final Interpolator FADE_IN_INTERPOLATOR = new DecelerateInterpolator();
-
-    /** Interpolator to use when cross-fading between previews. */
-    private static final Interpolator FADE_OUT_INTERPOLATOR = new AccelerateInterpolator();
-
-    private ViewGroup mPreviewFrame;
-    private TextView mLabel;
-    private View mLarger;
-    private View mSmaller;
-
-    private String[] mEntries;
-    private int[] mValues;
     private int mNormalDensity;
-    private int mInitialIndex;
-
-    private int mCurrentIndex;
+    private int[] mValues;
 
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        mActivityLayoutResId = R.layout.screen_zoom_activity;
+        mPreviewSampleResId = R.layout.screen_zoom_preview;
         final DisplayDensityUtils density = new DisplayDensityUtils(getContext());
 
         final int initialIndex = density.getCurrentIndex();
@@ -94,152 +68,18 @@
     }
 
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        final View root = super.onCreateView(inflater, container, savedInstanceState);
-        final ViewGroup list_container = (ViewGroup) root.findViewById(android.R.id.list_container);
-        list_container.removeAllViews();
-
-        final View content = inflater.inflate(R.layout.screen_zoom_activity, list_container, false);
-        list_container.addView(content);
-
-        mLabel = (TextView) content.findViewById(R.id.current_density);
-
-        // The maximum SeekBar value always needs to be non-zero. If there's
-        // only one available zoom level, we'll handle this by disabling the
-        // seek bar.
-        final int max = Math.max(1, mValues.length - 1);
-
-        final SeekBar seekBar = (SeekBar) content.findViewById(R.id.seek_bar);
-        seekBar.setMax(max);
-        seekBar.setProgress(mInitialIndex);
-        seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
-            @Override
-            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                setPreviewLayer(progress, true);
-            }
-
-            @Override
-            public void onStartTrackingTouch(SeekBar seekBar) {}
-
-            @Override
-            public void onStopTrackingTouch(SeekBar seekBar) {}
-        });
-
-        mSmaller = content.findViewById(R.id.smaller);
-        mSmaller.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                final int progress = seekBar.getProgress();
-                if (progress > 0) {
-                    seekBar.setProgress(progress - 1, true);
-                }
-            }
-        });
-
-        mLarger = content.findViewById(R.id.larger);
-        mLarger.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                final int progress = seekBar.getProgress();
-                if (progress < seekBar.getMax()) {
-                    seekBar.setProgress(progress + 1, true);
-                }
-            }
-        });
-
-        if (mValues.length == 1) {
-            // The larger and smaller buttons will be disabled when we call
-            // setPreviewLayer() later in this method.
-            seekBar.setEnabled(false);
-        }
-
-        mPreviewFrame = (FrameLayout) content.findViewById(R.id.preview_frame);
-
+    protected Configuration createConfig(Configuration origConfig, int index) {
         // Populate the sample layouts.
-        final Context context = getContext();
-        final Configuration origConfig = context.getResources().getConfiguration();
-        for (int mValue : mValues) {
-            final Configuration config = new Configuration(origConfig);
-            config.densityDpi = mValue;
-
-            // Create a new configuration for the specified density. It won't
-            // have any theme set, so manually apply the current theme.
-            final Context configContext = context.createConfigurationContext(config);
-            configContext.setTheme(context.getThemeResId());
-
-            final LayoutInflater configInflater = LayoutInflater.from(configContext);
-            final View sampleView = configInflater.inflate(
-                    R.layout.screen_zoom_preview, mPreviewFrame, false);
-            sampleView.setAlpha(0);
-            sampleView.setVisibility(View.INVISIBLE);
-
-            mPreviewFrame.addView(sampleView);
-        }
-
-        setPreviewLayer(mInitialIndex, false);
-
-        return root;
-    }
-
-    @Override
-    public void onDetach() {
-        super.onDetach();
-
-        // This will adjust the density SLIGHTLY after the activity has
-        // finished, which could be considered a feature or a bug...
-        commit();
-    }
-
-    private void setPreviewLayer(int index, boolean animate) {
-        mLabel.setText(mEntries[index]);
-
-        if (mCurrentIndex >= 0) {
-            final View lastLayer = mPreviewFrame.getChildAt(mCurrentIndex);
-            if (animate) {
-                lastLayer.animate()
-                        .alpha(0)
-                        .setInterpolator(FADE_OUT_INTERPOLATOR)
-                        .setDuration(CROSS_FADE_DURATION_MS)
-                        .withEndAction(new Runnable() {
-                            @Override
-                            public void run() {
-                                lastLayer.setVisibility(View.INVISIBLE);
-                            }
-                        });
-            } else {
-                lastLayer.setAlpha(0);
-                lastLayer.setVisibility(View.INVISIBLE);
-            }
-        }
-
-        final View nextLayer = mPreviewFrame.getChildAt(index);
-        if (animate) {
-            nextLayer.animate()
-                    .alpha(1)
-                    .setInterpolator(FADE_IN_INTERPOLATOR)
-                    .setDuration(CROSS_FADE_DURATION_MS)
-                    .withStartAction(new Runnable() {
-                @Override
-                public void run() {
-                    nextLayer.setVisibility(View.VISIBLE);
-                }
-            });
-        } else {
-            nextLayer.setVisibility(View.VISIBLE);
-            nextLayer.setAlpha(1);
-        }
-
-        mSmaller.setEnabled(index > 0);
-        mLarger.setEnabled(index < mEntries.length - 1);
-
-        mCurrentIndex = index;
+        final Configuration config = new Configuration(origConfig);
+        config.densityDpi = mValues[index];
+        return config;
     }
 
     /**
      * Persists the selected density and sends a configuration change.
      */
-    private void commit() {
+    @Override
+    protected void commit() {
         final int densityDpi = mValues[mCurrentIndex];
         if (densityDpi == mNormalDensity) {
             DisplayDensityUtils.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java
index 9f0767b..3c49d82 100644
--- a/src/com/android/settings/notification/ConfigureNotificationSettings.java
+++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java
@@ -16,14 +16,6 @@
 
 package com.android.settings.notification;
 
-import com.android.internal.widget.LockPatternUtils;
-import com.android.settings.InstrumentedFragment;
-import com.android.settings.R;
-import com.android.settings.RestrictedDropDownPreference;
-import com.android.settings.RestrictedDropDownPreference.RestrictedItem;
-import com.android.settings.RestrictedLockUtils;
-import com.android.settings.SettingsPreferenceFragment;
-
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
@@ -37,13 +29,21 @@
 import android.support.v7.preference.TwoStatePreference;
 import android.util.Log;
 
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settingslib.RestrictedDropDownPreference;
+import com.android.settingslib.RestrictedDropDownPreference.RestrictedItem;
+import com.android.settingslib.RestrictedLockUtils;
+
 import java.util.ArrayList;
 import java.util.List;
 
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
 
-import static com.android.settings.RestrictedLockUtils.EnforcedAdmin;
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
 public class ConfigureNotificationSettings extends SettingsPreferenceFragment {
     private static final String TAG = "ConfigNotiSettings";
diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java
index c747de3..8e105c8 100644
--- a/src/com/android/settings/users/AppRestrictionsFragment.java
+++ b/src/com/android/settings/users/AppRestrictionsFragment.java
@@ -17,7 +17,6 @@
 package com.android.settings.users;
 
 import android.app.Activity;
-import android.appwidget.AppWidgetManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -30,10 +29,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -48,13 +44,10 @@
 import android.support.v7.preference.Preference.OnPreferenceClickListener;
 import android.support.v7.preference.PreferenceGroup;
 import android.support.v7.preference.PreferenceViewHolder;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.CompoundButton;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 import android.widget.Switch;
@@ -63,19 +56,19 @@
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
+import com.android.settingslib.users.AppRestrictionsHelper;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
 
 public class AppRestrictionsFragment extends SettingsPreferenceFragment implements
-        OnPreferenceChangeListener, OnClickListener, OnPreferenceClickListener {
+        OnPreferenceChangeListener, OnClickListener, OnPreferenceClickListener,
+        AppRestrictionsHelper.OnDisableUiForPackageListener {
 
     private static final String TAG = AppRestrictionsFragment.class.getSimpleName();
 
@@ -89,6 +82,8 @@
     protected UserHandle mUser;
     private PackageInfo mSysPackageInfo;
 
+    private AppRestrictionsHelper mHelper;
+
     private PreferenceGroup mAppList;
 
     private static final int MAX_APP_RESTRICTIONS = 100;
@@ -101,7 +96,6 @@
     /** Key for extra passed in from calling fragment to indicate if this is a newly created user */
     public static final String EXTRA_NEW_USER = "new_user";
 
-    HashMap<String,Boolean> mSelectedPackages = new HashMap<String,Boolean>();
     private boolean mFirstTime = true;
     private boolean mNewUser;
     private boolean mAppListChanged;
@@ -110,11 +104,8 @@
     private static final int CUSTOM_REQUEST_CODE_START = 1000;
     private int mCustomRequestCode = CUSTOM_REQUEST_CODE_START;
 
-    private HashMap<Integer, AppRestrictionsPreference> mCustomRequestMap =
-            new HashMap<Integer,AppRestrictionsPreference>();
+    private HashMap<Integer, AppRestrictionsPreference> mCustomRequestMap = new HashMap<>();
 
-    private List<SelectableAppInfo> mVisibleApps;
-    private List<ApplicationInfo> mUserApps;
     private AsyncTask mAppLoadingTask;
 
     private BroadcastReceiver mUserBackgrounding = new BroadcastReceiver() {
@@ -125,7 +116,7 @@
             // have been scheduled during user startup.
             if (mAppListChanged) {
                 if (DEBUG) Log.d(TAG, "User backgrounding, update app list");
-                applyUserAppsStates();
+                mHelper.applyUserAppsStates(AppRestrictionsFragment.this);
                 if (DEBUG) Log.d(TAG, "User backgrounding, done updating app list");
             }
         }
@@ -138,27 +129,13 @@
         }
     };
 
-    static class SelectableAppInfo {
-        String packageName;
-        CharSequence appName;
-        CharSequence activityName;
-        Drawable icon;
-        SelectableAppInfo masterEntry;
-
-        @Override
-        public String toString() {
-            return packageName + ": appName=" + appName + "; activityName=" + activityName
-                    + "; icon=" + icon + "; masterEntry=" + masterEntry;
-        }
-    }
-
     static class AppRestrictionsPreference extends SwitchPreference {
         private boolean hasSettings;
         private OnClickListener listener;
         private ArrayList<RestrictionEntry> restrictions;
         private boolean panelOpen;
         private boolean immutable;
-        private List<Preference> mChildren = new ArrayList<Preference>();
+        private List<Preference> mChildren = new ArrayList<>();
 
         AppRestrictionsPreference(Context context, OnClickListener listener) {
             super(context);
@@ -248,6 +225,7 @@
             mUser = android.os.Process.myUserHandle();
         }
 
+        mHelper = new AppRestrictionsHelper(getContext(), mUser);
         mPackageManager = getActivity().getPackageManager();
         mIPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
         mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
@@ -260,6 +238,7 @@
         }
         addPreferencesFromResource(R.xml.app_restrictions);
         mAppList = getAppPreferenceGroup();
+        mAppList.setOrderingAsAdded(false);
     }
 
     @Override
@@ -287,7 +266,7 @@
 
         mAppListChanged = false;
         if (mAppLoadingTask == null || mAppLoadingTask.getStatus() == AsyncTask.Status.FINISHED) {
-            mAppLoadingTask = new AppLoadingTask().execute((Void[]) null);
+            mAppLoadingTask = new AppLoadingTask().execute();
         }
     }
 
@@ -298,11 +277,13 @@
         getActivity().unregisterReceiver(mUserBackgrounding);
         getActivity().unregisterReceiver(mPackageObserver);
         if (mAppListChanged) {
-            new Thread() {
-                public void run() {
-                    applyUserAppsStates();
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... params) {
+                    mHelper.applyUserAppsStates(AppRestrictionsFragment.this);
+                    return null;
                 }
-            }.start();
+            }.execute();
         }
     }
 
@@ -324,68 +305,8 @@
         return getPreferenceScreen();
     }
 
-    private void applyUserAppsStates() {
-        final int userId = mUser.getIdentifier();
-        if (!mUserManager.getUserInfo(userId).isRestricted() && userId != UserHandle.myUserId()) {
-            Log.e(TAG, "Cannot apply application restrictions on another user!");
-            return;
-        }
-        for (Map.Entry<String,Boolean> entry : mSelectedPackages.entrySet()) {
-            String packageName = entry.getKey();
-            boolean enabled = entry.getValue();
-            applyUserAppState(packageName, enabled);
-        }
-    }
-
-    private void applyUserAppState(String packageName, boolean enabled) {
-        final int userId = mUser.getIdentifier();
-        if (enabled) {
-            // Enable selected apps
-            try {
-                ApplicationInfo info = mIPm.getApplicationInfo(packageName,
-                        PackageManager.GET_UNINSTALLED_PACKAGES, userId);
-                if (info == null || info.enabled == false
-                        || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
-                    mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
-                    if (DEBUG) {
-                        Log.d(TAG, "Installing " + packageName);
-                    }
-                }
-                if (info != null && (info.privateFlags&ApplicationInfo.PRIVATE_FLAG_HIDDEN) != 0
-                        && (info.flags&ApplicationInfo.FLAG_INSTALLED) != 0) {
-                    disableUiForPackage(packageName);
-                    mIPm.setApplicationHiddenSettingAsUser(packageName, false, userId);
-                    if (DEBUG) {
-                        Log.d(TAG, "Unhiding " + packageName);
-                    }
-                }
-            } catch (RemoteException re) {
-            }
-        } else {
-            // Blacklist all other apps, system or downloaded
-            try {
-                ApplicationInfo info = mIPm.getApplicationInfo(packageName, 0, userId);
-                if (info != null) {
-                    if (mRestrictedProfile) {
-                        mIPm.deletePackageAsUser(packageName, null, mUser.getIdentifier(),
-                                PackageManager.DELETE_SYSTEM_APP);
-                        if (DEBUG) {
-                            Log.d(TAG, "Uninstalling " + packageName);
-                        }
-                    } else {
-                        disableUiForPackage(packageName);
-                        mIPm.setApplicationHiddenSettingAsUser(packageName, true, userId);
-                        if (DEBUG) {
-                            Log.d(TAG, "Hiding " + packageName);
-                        }
-                    }
-                }
-            } catch (RemoteException re) {
-            }
-        }
-    }
-
-    private void disableUiForPackage(String packageName) {
+    @Override
+    public void onDisableUiForPackage(String packageName) {
         AppRestrictionsPreference pref = (AppRestrictionsPreference) findPreference(
                 getKeyForPackage(packageName));
         if (pref != null) {
@@ -393,106 +314,11 @@
         }
     }
 
-    private boolean isSystemPackage(String packageName) {
-        try {
-            final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
-            if (pi.applicationInfo == null) return false;
-            final int flags = pi.applicationInfo.flags;
-            if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0
-                    || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
-                return true;
-            }
-        } catch (NameNotFoundException nnfe) {
-            // Missing package?
-        }
-        return false;
-    }
-
-    /**
-     * Find all pre-installed input methods that are marked as default
-     * and add them to an exclusion list so that they aren't
-     * presented to the user for toggling.
-     * Don't add non-default ones, as they may include other stuff that we
-     * don't need to auto-include.
-     * @param excludePackages the set of package names to append to
-     */
-    private void addSystemImes(Set<String> excludePackages) {
-        final Context context = getActivity();
-        if (context == null) return;
-        InputMethodManager imm = (InputMethodManager)
-                context.getSystemService(Context.INPUT_METHOD_SERVICE);
-        List<InputMethodInfo> imis = imm.getInputMethodList();
-        for (InputMethodInfo imi : imis) {
-            try {
-                if (imi.isDefault(context) && isSystemPackage(imi.getPackageName())) {
-                    excludePackages.add(imi.getPackageName());
-                }
-            } catch (Resources.NotFoundException rnfe) {
-                // Not default
-            }
-        }
-    }
-
-    /**
-     * Add system apps that match an intent to the list, excluding any packages in the exclude list.
-     * @param visibleApps list of apps to append the new list to
-     * @param intent the intent to match
-     * @param excludePackages the set of package names to be excluded, since they're required
-     */
-    private void addSystemApps(List<SelectableAppInfo> visibleApps, Intent intent,
-            Set<String> excludePackages) {
-        if (getActivity() == null) return;
-        final PackageManager pm = mPackageManager;
-        List<ResolveInfo> launchableApps = pm.queryIntentActivities(intent,
-                PackageManager.GET_DISABLED_COMPONENTS | PackageManager.GET_UNINSTALLED_PACKAGES);
-        for (ResolveInfo app : launchableApps) {
-            if (app.activityInfo != null && app.activityInfo.applicationInfo != null) {
-                final String packageName = app.activityInfo.packageName;
-                int flags = app.activityInfo.applicationInfo.flags;
-                if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0
-                        || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
-                    // System app
-                    // Skip excluded packages
-                    if (excludePackages.contains(packageName)) continue;
-                    int enabled = pm.getApplicationEnabledSetting(packageName);
-                    if (enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
-                            || enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
-                        // Check if the app is already enabled for the target user
-                        ApplicationInfo targetUserAppInfo = getAppInfoForUser(packageName,
-                                0, mUser);
-                        if (targetUserAppInfo == null
-                                || (targetUserAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
-                            continue;
-                        }
-                    }
-                    SelectableAppInfo info = new SelectableAppInfo();
-                    info.packageName = app.activityInfo.packageName;
-                    info.appName = app.activityInfo.applicationInfo.loadLabel(pm);
-                    info.icon = app.activityInfo.loadIcon(pm);
-                    info.activityName = app.activityInfo.loadLabel(pm);
-                    if (info.activityName == null) info.activityName = info.appName;
-
-                    visibleApps.add(info);
-                }
-            }
-        }
-    }
-
-    private ApplicationInfo getAppInfoForUser(String packageName, int flags, UserHandle user) {
-        try {
-            ApplicationInfo targetUserAppInfo = mIPm.getApplicationInfo(packageName, flags,
-                    user.getIdentifier());
-            return targetUserAppInfo;
-        } catch (RemoteException re) {
-            return null;
-        }
-    }
-
     private class AppLoadingTask extends AsyncTask<Void, Void, Void> {
 
         @Override
         protected Void doInBackground(Void... params) {
-            fetchAndMergeApps();
+            mHelper.fetchAndMergeApps();
             return null;
         }
 
@@ -500,117 +326,6 @@
         protected void onPostExecute(Void result) {
             populateApps();
         }
-
-        @Override
-        protected void onPreExecute() {
-        }
-    }
-
-    private void fetchAndMergeApps() {
-        mAppList.setOrderingAsAdded(false);
-        mVisibleApps = new ArrayList<SelectableAppInfo>();
-        final Context context = getActivity();
-        if (context == null) return;
-        final PackageManager pm = mPackageManager;
-        final IPackageManager ipm = mIPm;
-
-        final HashSet<String> excludePackages = new HashSet<String>();
-        addSystemImes(excludePackages);
-
-        // Add launchers
-        Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
-        launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-        addSystemApps(mVisibleApps, launcherIntent, excludePackages);
-
-        // Add widgets
-        Intent widgetIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
-        addSystemApps(mVisibleApps, widgetIntent, excludePackages);
-
-        List<ApplicationInfo> installedApps = pm.getInstalledApplications(
-                PackageManager.GET_UNINSTALLED_PACKAGES);
-        for (ApplicationInfo app : installedApps) {
-            // If it's not installed, skip
-            if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
-
-            if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0
-                    && (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
-                // Downloaded app
-                SelectableAppInfo info = new SelectableAppInfo();
-                info.packageName = app.packageName;
-                info.appName = app.loadLabel(pm);
-                info.activityName = info.appName;
-                info.icon = app.loadIcon(pm);
-                mVisibleApps.add(info);
-            } else {
-                try {
-                    PackageInfo pi = pm.getPackageInfo(app.packageName, 0);
-                    // If it's a system app that requires an account and doesn't see restricted
-                    // accounts, mark for removal. It might get shown in the UI if it has an icon
-                    // but will still be marked as false and immutable.
-                    if (mRestrictedProfile
-                            && pi.requiredAccountType != null && pi.restrictedAccountType == null) {
-                        mSelectedPackages.put(app.packageName, false);
-                    }
-                } catch (NameNotFoundException re) {
-                }
-            }
-        }
-
-        // Get the list of apps already installed for the user
-        mUserApps = null;
-        try {
-            ParceledListSlice listSlice = ipm.getInstalledApplications(
-                    PackageManager.GET_UNINSTALLED_PACKAGES, mUser.getIdentifier());
-            if (listSlice != null) {
-                mUserApps = listSlice.getList();
-            }
-        } catch (RemoteException re) {
-        }
-
-        if (mUserApps != null) {
-            for (ApplicationInfo app : mUserApps) {
-                if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
-
-                if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0
-                        && (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
-                    // Downloaded app
-                    SelectableAppInfo info = new SelectableAppInfo();
-                    info.packageName = app.packageName;
-                    info.appName = app.loadLabel(pm);
-                    info.activityName = info.appName;
-                    info.icon = app.loadIcon(pm);
-                    mVisibleApps.add(info);
-                }
-            }
-        }
-
-        // Sort the list of visible apps
-        Collections.sort(mVisibleApps, new AppLabelComparator());
-
-        // Remove dupes
-        Set<String> dedupPackageSet = new HashSet<String>();
-        for (int i = mVisibleApps.size() - 1; i >= 0; i--) {
-            SelectableAppInfo info = mVisibleApps.get(i);
-            if (DEBUG) Log.i(TAG, info.toString());
-            String both = info.packageName + "+" + info.activityName;
-            if (!TextUtils.isEmpty(info.packageName)
-                    && !TextUtils.isEmpty(info.activityName)
-                    && dedupPackageSet.contains(both)) {
-                mVisibleApps.remove(i);
-            } else {
-                dedupPackageSet.add(both);
-            }
-        }
-
-        // Establish master/slave relationship for entries that share a package name
-        HashMap<String,SelectableAppInfo> packageMap = new HashMap<String,SelectableAppInfo>();
-        for (SelectableAppInfo info : mVisibleApps) {
-            if (packageMap.containsKey(info.packageName)) {
-                info.masterEntry = packageMap.get(info.packageName);
-            } else {
-                packageMap.put(info.packageName, info);
-            }
-        }
     }
 
     private boolean isPlatformSigned(PackageInfo pi) {
@@ -641,7 +356,7 @@
         mAppList.removeAll();
         Intent restrictionsIntent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES);
         final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(restrictionsIntent, 0);
-        for (SelectableAppInfo app : mVisibleApps) {
+        for (AppRestrictionsHelper.SelectableAppInfo app : mHelper.getVisibleApps()) {
             String packageName = app.packageName;
             if (packageName == null) continue;
             final boolean isSettingsApp = packageName.equals(context.getPackageName());
@@ -650,15 +365,16 @@
             if (isSettingsApp) {
                 addLocationAppRestrictionsPreference(app, p);
                 // Settings app should be available to restricted user
-                mSelectedPackages.put(packageName, true);
+                mHelper.setPackageSelected(packageName, true);
                 continue;
             }
             PackageInfo pi = null;
             try {
                 pi = ipm.getPackageInfo(packageName,
-                        PackageManager.GET_UNINSTALLED_PACKAGES
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES
                         | PackageManager.GET_SIGNATURES, userId);
             } catch (RemoteException e) {
+                // Ignore
             }
             if (pi == null) {
                 continue;
@@ -692,10 +408,10 @@
             }
             if (app.masterEntry != null) {
                 p.setImmutable(true);
-                p.setChecked(mSelectedPackages.get(packageName));
+                p.setChecked(mHelper.isPackageSelected(packageName));
             }
             p.setOrder(MAX_APP_RESTRICTIONS * (mAppList.getPreferenceCount() + 2));
-            mSelectedPackages.put(packageName, p.isChecked());
+            mHelper.setPackageSelected(packageName, p.isChecked());
             mAppList.addPreference(p);
         }
         mAppListChanged = true;
@@ -703,11 +419,11 @@
         // to avoid taking the hit in onPause(), which can cause race conditions on user switch.
         if (mNewUser && mFirstTime) {
             mFirstTime = false;
-            applyUserAppsStates();
+            mHelper.applyUserAppsStates(this);
         }
     }
 
-    private String getPackageSummary(PackageInfo pi, SelectableAppInfo app) {
+    private String getPackageSummary(PackageInfo pi, AppRestrictionsHelper.SelectableAppInfo app) {
         // Check for 3 cases:
         // - Slave entry that can see primary user accounts
         // - Slave entry that cannot see primary user accounts
@@ -730,7 +446,7 @@
         return pi.requiredAccountType != null && pi.restrictedAccountType == null;
     }
 
-    private void addLocationAppRestrictionsPreference(SelectableAppInfo app,
+    private void addLocationAppRestrictionsPreference(AppRestrictionsHelper.SelectableAppInfo app,
             AppRestrictionsPreference p) {
         String packageName = app.packageName;
         p.setIcon(R.drawable.ic_settings_location);
@@ -752,16 +468,6 @@
         return PKG_PREFIX + packageName;
     }
 
-    private class AppLabelComparator implements Comparator<SelectableAppInfo> {
-
-        @Override
-        public int compare(SelectableAppInfo lhs, SelectableAppInfo rhs) {
-            String lhsLabel = lhs.activityName.toString();
-            String rhsLabel = rhs.activityName.toString();
-            return lhsLabel.toLowerCase().compareTo(rhsLabel.toLowerCase());
-        }
-    }
-
     private boolean resolveInfoListHasPackage(List<ResolveInfo> receivers, String packageName) {
         for (ResolveInfo info : receivers) {
             if (info.activityInfo.packageName.equals(packageName)) {
@@ -797,7 +503,7 @@
                     RestrictionUtils.setRestrictions(getActivity(), pref.restrictions, mUser);
                     return;
                 }
-                mSelectedPackages.put(packageName, pref.isChecked());
+                mHelper.setPackageSelected(packageName, pref.isChecked());
                 if (pref.isChecked() && pref.hasSettings
                         && pref.restrictions == null) {
                     // The restrictions have not been initialized, get and save them
@@ -806,7 +512,7 @@
                 mAppListChanged = true;
                 // If it's not a restricted profile, apply the changes immediately
                 if (!mRestrictedProfile) {
-                    applyUserAppState(packageName, pref.isChecked());
+                    mHelper.applyUserAppState(packageName, pref.isChecked(), this);
                 }
                 updateAllEntries(pref.getKey(), pref.isChecked());
             }
@@ -917,9 +623,9 @@
             Bundle results = getResultExtras(true);
             final ArrayList<RestrictionEntry> restrictions = results.getParcelableArrayList(
                     Intent.EXTRA_RESTRICTIONS_LIST);
-            Intent restrictionsIntent = (Intent) results.getParcelable(CUSTOM_RESTRICTIONS_INTENT);
+            Intent restrictionsIntent = results.getParcelable(CUSTOM_RESTRICTIONS_INTENT);
             if (restrictions != null && restrictionsIntent == null) {
-                onRestrictionsReceived(preference, packageName, restrictions);
+                onRestrictionsReceived(preference, restrictions);
                 if (mRestrictedProfile) {
                     mUserManager.setApplicationRestrictions(packageName,
                             RestrictionsManager.convertRestrictionsToBundle(restrictions), mUser);
@@ -952,16 +658,15 @@
             if (!packageName.equals(activityInfo.packageName)) {
                 throw new SecurityException("Application " + packageName
                         + " is not allowed to start activity " + intent);
-            };
+            }
         }
     }
 
-    private void onRestrictionsReceived(AppRestrictionsPreference preference, String packageName,
+    private void onRestrictionsReceived(AppRestrictionsPreference preference,
             ArrayList<RestrictionEntry> restrictions) {
         // Remove any earlier restrictions
         removeRestrictionsForApp(preference);
         // Non-custom-activity case - expand the restrictions in-place
-        final Context context = preference.getContext();
         int count = 1;
         for (RestrictionEntry entry : restrictions) {
             Preference p = null;
@@ -992,7 +697,7 @@
                 p.setTitle(entry.getTitle());
                 ((MultiSelectListPreference)p).setEntryValues(entry.getChoiceValues());
                 ((MultiSelectListPreference)p).setEntries(entry.getChoiceEntries());
-                HashSet<String> set = new HashSet<String>();
+                HashSet<String> set = new HashSet<>();
                 Collections.addAll(set, entry.getAllSelectedStrings());
                 ((MultiSelectListPreference)p).setValues(set);
                 ((MultiSelectListPreference)p).setDialogTitle(entry.getTitle());
@@ -1025,8 +730,6 @@
     /**
      * Generates a request code that is stored in a map to retrieve the associated
      * AppRestrictionsPreference.
-     * @param preference
-     * @return
      */
     private int generateCustomActivityRequestCode(AppRestrictionsPreference preference) {
         mCustomRequestCode++;
@@ -1081,10 +784,10 @@
                 final String packageName = arp.getKey().substring(PKG_PREFIX.length());
                 final boolean newEnabledState = !arp.isChecked();
                 arp.setChecked(newEnabledState);
-                mSelectedPackages.put(packageName, newEnabledState);
+                mHelper.setPackageSelected(packageName, newEnabledState);
                 updateAllEntries(arp.getKey(), newEnabledState);
                 mAppListChanged = true;
-                applyUserAppState(packageName, newEnabledState);
+                mHelper.applyUserAppState(packageName, newEnabledState, this);
             }
             return true;
         }
diff --git a/src/com/android/settings/users/RestrictionUtils.java b/src/com/android/settings/users/RestrictionUtils.java
index fbdc7596..33b6a95 100644
--- a/src/com/android/settings/users/RestrictionUtils.java
+++ b/src/com/android/settings/users/RestrictionUtils.java
@@ -81,14 +81,6 @@
 
         for (RestrictionEntry entry : entries) {
             um.setUserRestriction(entry.getKey(), !entry.getSelectedState());
-
-            // TODO This will no longer be needed once b/23902097 is fixed. um.setUserRestriction
-            // should do it.
-            if (entry.getKey().equals(UserManager.DISALLOW_SHARE_LOCATION)
-                    && !entry.getSelectedState()) {
-                Secure.putIntForUser(context.getContentResolver(),
-                        Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF, user.getIdentifier());
-            }
         }
     }
 }