Merge "Add WebView provider setting to developer settings."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 43fe796..3bbc667 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2646,5 +2646,15 @@
                 android:value="com.android.settings.applications.WriteSettingsDetails" />
         </activity>
 
+        <activity android:name="ShowAdminSupportDetailsDialog"
+                android:theme="@style/Transparent"
+                android:excludeFromRecents="true">
+
+            <intent-filter>
+                <action android:name="android.app.action.SHOW_ADMIN_SUPPORT_DETAILS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
     </application>
 </manifest>
diff --git a/res/drawable/ic_settings_lock_outline.xml b/res/drawable/ic_settings_lock_outline.xml
new file mode 100644
index 0000000..1c4202c
--- /dev/null
+++ b/res/drawable/ic_settings_lock_outline.xml
@@ -0,0 +1,27 @@
+<?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="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="22.0"
+        android:tint="?android:attr/colorAccent">
+    <path
+            android:fillColor="@android:color/white"
+            android:pathData="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM8.9 6c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1v2H8.9V6zM18 20H6V10h12v10z" />
+</vector>
diff --git a/res/layout/admin_support_details_dialog.xml b/res/layout/admin_support_details_dialog.xml
new file mode 100644
index 0000000..0d857df
--- /dev/null
+++ b/res/layout/admin_support_details_dialog.xml
@@ -0,0 +1,70 @@
+<?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="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="@dimen/admin_details_dialog_padding"
+        android:orientation="vertical">
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:paddingBottom="@dimen/admin_details_dialog_padding">
+        <ImageView
+                android:layout_width="@dimen/admin_details_dialog_icon_size"
+                android:layout_height="@dimen/admin_details_dialog_icon_size"
+                android:src="@drawable/ic_settings_lock_outline"
+                android:scaleType="fitCenter"
+                android:contentDescription="@null" />
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="@dimen/admin_details_dialog_padding"
+                android:text="@string/disabled_by_policy_title"
+                android:textAppearance="@android:style/TextAppearance.Material.Title" />
+    </LinearLayout>
+
+    <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fadeScrollbars="false">
+        <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+            <TextView android:id="@+id/disabled_by_admin_msg"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                    android:textColor="?android:attr/textColorSecondary" />
+            <TextView android:id="@+id/admin_support_msg"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                    android:textColor="?android:attr/textColorSecondary" />
+            <TextView android:id="@+id/admins_policies_list"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:paddingTop="@dimen/admin_details_dialog_link_padding_top"
+                    android:text="@string/list_of_administrators"
+                    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                    android:textColor="?android:attr/colorAccent"
+                    android:clickable="true"
+                    android:background="?android:attr/selectableItemBackground" />
+        </LinearLayout>
+    </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 62c34ea..2381ed8 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -114,4 +114,8 @@
         <attr name="android:entries" />
         <attr name="android:entryValues" />
     </declare-styleable>
+
+    <declare-styleable name="RestrictedPreference">
+        <attr name="userRestriction" format="string"/>
+    </declare-styleable>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 481cc73..86030ff 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -250,6 +250,15 @@
     <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>
+    <dimen name="admin_details_dialog_link_padding_top">36dp</dimen>
+
     <!-- Button bar padding for unmount button. -->
     <dimen name="unmount_button_padding">8dp</dimen>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a1a1901..7120163 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3660,7 +3660,7 @@
     <!-- Title for the accessibility preference to speak passwords. [CHAR LIMIT=35] -->
     <string name="accessibility_toggle_speak_password_preference_title">Speak passwords</string>
     <!-- Title for the accessibility preference for enabling/disabling large icons for mouse/trackpad pointers. [CHAR LIMIT=35] -->
-    <string name="accessibility_toggle_large_pointer_icon_title">Large mouse/trackpad pointer icons</string>
+    <string name="accessibility_toggle_large_pointer_icon_title">Large mouse pointer</string>
     <!-- Title for accessibility preference to choose long-press delay i.e. timeout before it is detected. [CHAR LIMIT=35] -->
     <string name="accessibility_long_press_timeout_preference_title">Touch &amp; hold delay</string>
     <!-- Title for the accessibility preference to configure display color inversion. [CHAR LIMIT=NONE] -->
@@ -6684,4 +6684,11 @@
 
     <!-- Summary of device info page [CHAR LIMIT=NONE] -->
     <string name="about_summary">Android <xliff:g id="version" example="6.0">%1$s</xliff:g></string>
+
+    <!-- TODO: Update these strings with the finalized ones. -->
+    <string name="disabled_by_policy_title">Disabled by policy</string>
+    <string name="disabled_by_admin_msg">Disabled by your <xliff:g id="organisation_name" example="organisation">%s</xliff:g>\'s administrator.</string>
+    <string name="default_organisation_name">organisation</string>
+    <string name="default_admin_support_msg">Contact them to learn more.</string>
+    <string name="list_of_administrators">List of administrators</string>
 </resources>
diff --git a/res/xml/privacy_settings.xml b/res/xml/privacy_settings.xml
index 721a3bf..e014420 100644
--- a/res/xml/privacy_settings.xml
+++ b/res/xml/privacy_settings.xml
@@ -54,10 +54,11 @@
         android:fragment="com.android.settings.ResetNetwork" />
 
     <!-- Factory reset -->
-    <PreferenceScreen
+    <com.android.settings.RestrictedPreference
         android:key="factory_reset"
         android:title="@string/master_clear_title"
         settings:keywords="@string/keywords_factory_data_reset"
+        settings:userRestriction="no_factory_reset"
         android:fragment="com.android.settings.MasterClear" />
 
 </PreferenceScreen>
diff --git a/res/xml/security_settings_misc.xml b/res/xml/security_settings_misc.xml
index 62b6fa3..41daa02 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"/>
 
-        <SwitchPreference android:key="toggle_install_applications"
+        <com.android.settings.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/AirplaneModeVoiceActivity.java b/src/com/android/settings/AirplaneModeVoiceActivity.java
index e0649e4..21bfef2 100644
--- a/src/com/android/settings/AirplaneModeVoiceActivity.java
+++ b/src/com/android/settings/AirplaneModeVoiceActivity.java
@@ -16,7 +16,9 @@
 
 package com.android.settings;
 
+import android.content.Context;
 import android.content.Intent;
+import android.net.ConnectivityManager;
 import android.provider.Settings;
 import android.util.Log;
 
@@ -31,9 +33,10 @@
 
     protected boolean onVoiceSettingInteraction(Intent intent) {
         if (intent.hasExtra(Settings.EXTRA_AIRPLANE_MODE_ENABLED)) {
-            Settings.Global.putInt(getContentResolver(),
-                    Settings.Global.AIRPLANE_MODE_ON,
-                    intent.getBooleanExtra(Settings.EXTRA_AIRPLANE_MODE_ENABLED, false) ? 1 : 0);
+            ConnectivityManager mgr = (ConnectivityManager) getSystemService(
+                    Context.CONNECTIVITY_SERVICE);
+            mgr.setAirplaneMode(intent.getBooleanExtra(
+                    Settings.EXTRA_AIRPLANE_MODE_ENABLED, false));
         } else {
             Log.v(TAG, "Missing airplane mode extra");
         }
diff --git a/src/com/android/settings/PrivacySettings.java b/src/com/android/settings/PrivacySettings.java
index 2344a33..0735b11 100644
--- a/src/com/android/settings/PrivacySettings.java
+++ b/src/com/android/settings/PrivacySettings.java
@@ -291,10 +291,6 @@
             nonVisibleKeys.add(CONFIGURE_ACCOUNT);
         }
         if (UserManager.get(context).hasUserRestriction(
-                UserManager.DISALLOW_FACTORY_RESET)) {
-            nonVisibleKeys.add(FACTORY_RESET);
-        }
-        if (UserManager.get(context).hasUserRestriction(
                 UserManager.DISALLOW_NETWORK_RESET)) {
             nonVisibleKeys.add(NETWORK_RESET);
         }
diff --git a/src/com/android/settings/RestrictedPreference.java b/src/com/android/settings/RestrictedPreference.java
new file mode 100644
index 0000000..7903f93
--- /dev/null
+++ b/src/com/android/settings/RestrictedPreference.java
@@ -0,0 +1,94 @@
+/*
+ * 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.ComponentName;
+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;
+
+/**
+ * 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(boolean disabled) {
+        mHelper.setDisabledByAdmin(disabled, null, UserHandle.USER_NULL);
+    }
+
+    public void setDisabledByAdmin(boolean disabled, ComponentName admin, int userId) {
+        if (mHelper.setDisabledByAdmin(disabled, admin, userId)) {
+            notifyChanged();
+        }
+    }
+
+    public boolean isDisabledByAdmin() {
+        return mHelper.isDisabledByAdmin();
+    }
+}
diff --git a/src/com/android/settings/RestrictedPreferenceHelper.java b/src/com/android/settings/RestrictedPreferenceHelper.java
new file mode 100644
index 0000000..0918887
--- /dev/null
+++ b/src/com/android/settings/RestrictedPreferenceHelper.java
@@ -0,0 +1,195 @@
+/*
+ * 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.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * 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 final DevicePolicyManager mDevicePolicyManager;
+
+    private boolean mDisabledByAdmin;
+    private ComponentName mEnforcedAdmin;
+    private int mUserId = UserHandle.USER_NULL;
+    private String mAttrUserRestriction = null;
+
+    RestrictedPreferenceHelper(Context context, Preference preference,
+            AttributeSet attrs) {
+        mContext = context;
+        mPreference = preference;
+
+        mRestrictedPadlock = mContext.getDrawable(R.drawable.ic_settings_lock_outline);
+        final int iconSize = mContext.getResources().getDimensionPixelSize(
+                R.dimen.restricted_lock_icon_size);
+        mRestrictedPadlock.setBounds(0, 0, iconSize, iconSize);
+        mRestrictedPadlockPadding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.restricted_lock_icon_padding);
+
+        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+
+        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) {
+            if (mDisabledByAdmin) {
+                titleView.setCompoundDrawablesRelative(null, null, mRestrictedPadlock, null);
+                titleView.setCompoundDrawablePadding(mRestrictedPadlockPadding);
+                holder.itemView.setEnabled(true);
+            } else {
+                titleView.setCompoundDrawablesRelative(null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     * 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) {
+            Intent intent = new Intent(mContext, ShowAdminSupportDetailsDialog.class);
+            if (mEnforcedAdmin != null) {
+                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mEnforcedAdmin);
+            }
+            if (mUserId != UserHandle.USER_NULL) {
+                intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
+            }
+            mContext.startActivity(intent);
+            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) {
+        ComponentName deviceOwner = mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser();
+        int deviceOwnerUserId = mDevicePolicyManager.getDeviceOwnerUserId();
+        boolean enforcedByDeviceOwner = false;
+        if (deviceOwner != null && deviceOwnerUserId != UserHandle.USER_NULL) {
+            enforcedByDeviceOwner = isEnforcedByAdmin(
+                    deviceOwner, userRestriction, deviceOwnerUserId);
+        }
+
+        ComponentName profileOwner = mDevicePolicyManager.getProfileOwnerAsUser(userId);
+        boolean enforcedByProfileOwner = false;
+        if (profileOwner != null && userId != UserHandle.USER_NULL) {
+            enforcedByProfileOwner = isEnforcedByAdmin(
+                    profileOwner, userRestriction, userId);
+        }
+
+        if (!enforcedByDeviceOwner && !enforcedByProfileOwner) {
+            setDisabledByAdmin(false, null, UserHandle.USER_NULL);
+            return;
+        }
+
+        if (enforcedByDeviceOwner && enforcedByProfileOwner) {
+            setDisabledByAdmin(true, null, UserHandle.USER_NULL);
+        } else if (enforcedByDeviceOwner) {
+            setDisabledByAdmin(true, deviceOwner, deviceOwnerUserId);
+        } else {
+            setDisabledByAdmin(true, profileOwner, userId);
+        }
+    }
+
+    private boolean isEnforcedByAdmin(ComponentName admin, String userRestriction, int userId) {
+        Bundle enforcedRestrictions = mDevicePolicyManager.getUserRestrictions(admin, userId);
+        if (enforcedRestrictions != null
+                && enforcedRestrictions.getBoolean(userRestriction, false)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Disable this preference.
+     *
+     * @param disabled true if preference should be disabled.
+     * @param admin Device admin that disabled the preference.
+     * @param userId userId the device admin is installed for.
+     * @return true if the disabled state was changed.
+     */
+    public boolean setDisabledByAdmin(boolean disabled, ComponentName admin, int userId) {
+        if (mDisabledByAdmin != disabled) {
+            mDisabledByAdmin = disabled;
+            mEnforcedAdmin = admin;
+            mUserId = userId;
+            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
new file mode 100644
index 0000000..526bd42
--- /dev/null
+++ b/src/com/android/settings/RestrictedSwitchPreference.java
@@ -0,0 +1,94 @@
+/*
+ * 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.ComponentName;
+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;
+
+/**
+ * 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(boolean disabled) {
+        mHelper.setDisabledByAdmin(disabled, null, UserHandle.USER_NULL);
+    }
+
+    public void setDisabledByAdmin(boolean disabled, ComponentName admin, int userId) {
+        if (mHelper.setDisabledByAdmin(disabled, admin, userId)) {
+            notifyChanged();
+        }
+    }
+
+    public boolean isDisabledByAdmin() {
+        return mHelper.isDisabledByAdmin();
+    }
+}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 838fcf3..fbe0f1c 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -129,7 +129,7 @@
     private KeyStore mKeyStore;
     private Preference mResetCredentials;
 
-    private SwitchPreference mToggleAppInstallation;
+    private RestrictedSwitchPreference mToggleAppInstallation;
     private DialogInterface mWarnInstallApps;
     private SwitchPreference mPowerButtonInstantlyLocks;
 
@@ -313,15 +313,19 @@
         // Application install
         PreferenceGroup deviceAdminCategory = (PreferenceGroup)
                 root.findPreference(KEY_DEVICE_ADMIN_CATEGORY);
-        mToggleAppInstallation = (SwitchPreference) findPreference(
+        mToggleAppInstallation = (RestrictedSwitchPreference) findPreference(
                 KEY_TOGGLE_INSTALL_APPLICATIONS);
         mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
         // Side loading of apps.
         // Disable for restricted profiles. For others, check if policy disallows it.
         mToggleAppInstallation.setEnabled(!um.getUserInfo(MY_USER_ID).isRestricted());
-        if (um.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)
-                || um.hasUserRestriction(UserManager.DISALLOW_INSTALL_APPS)) {
-            mToggleAppInstallation.setEnabled(false);
+        if (mToggleAppInstallation.isEnabled()) {
+            mToggleAppInstallation.checkRestrictionAndSetDisabled(
+                    UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+            if (!mToggleAppInstallation.isDisabledByAdmin()) {
+                mToggleAppInstallation.checkRestrictionAndSetDisabled(
+                        UserManager.DISALLOW_INSTALL_APPS);
+            }
         }
 
         // Advanced Security features
diff --git a/src/com/android/settings/ShowAdminSupportDetailsDialog.java b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
new file mode 100644
index 0000000..42e8f05
--- /dev/null
+++ b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
@@ -0,0 +1,73 @@
+/*
+ * 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.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+public class ShowAdminSupportDetailsDialog extends Activity
+        implements DialogInterface.OnDismissListener {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        View rootView = LayoutInflater.from(this).inflate(
+                R.layout.admin_support_details_dialog, null);
+        setAdminSupportDetails(rootView);
+
+        new AlertDialog.Builder(this)
+                .setView(rootView)
+                .setPositiveButton(R.string.okay, null)
+                .setOnDismissListener(this)
+                .show();
+    }
+
+    private void setAdminSupportDetails(View root) {
+        CharSequence adminDisabledMsg = getString(R.string.disabled_by_admin_msg,
+                getString(R.string.default_organisation_name));
+        TextView textView = (TextView) root.findViewById(R.id.disabled_by_admin_msg);
+        textView.setText(adminDisabledMsg);
+
+        CharSequence adminSupportDetails = getString(R.string.default_admin_support_msg);
+        textView = (TextView) root.findViewById(R.id.admin_support_msg);
+        textView.setText(adminSupportDetails);
+
+        root.findViewById(R.id.admins_policies_list).setOnClickListener(
+                new View.OnClickListener() {
+                    @Override
+                    public void onClick(View view) {
+                        Intent intent = new Intent();
+                        intent.setClass(ShowAdminSupportDetailsDialog.this,
+                                Settings.DeviceAdminSettingsActivity.class);
+                        startActivity(intent);
+                        finish();
+                    }
+                });
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+        finish();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/notification/ImportanceSeekBarPreference.java b/src/com/android/settings/notification/ImportanceSeekBarPreference.java
index fdba42c..ec77467 100644
--- a/src/com/android/settings/notification/ImportanceSeekBarPreference.java
+++ b/src/com/android/settings/notification/ImportanceSeekBarPreference.java
@@ -33,7 +33,6 @@
         SeekBar.OnSeekBarChangeListener {
     private static final String TAG = "ImportanceSeekBarPref";
 
-    public static final int IMPORTANCE_PROGRESS_OFFSET = 2;
     private Callback mCallback;
     private TextView mSummaryTextView;
     private String mSummary;
@@ -89,8 +88,6 @@
     }
 
     private String getProgressSummary(int progress) {
-        // Map progress 0-4 values to Importance's -2-2.
-        progress = progress - IMPORTANCE_PROGRESS_OFFSET;
         switch (progress) {
             case NotificationListenerService.Ranking.IMPORTANCE_NONE:
                 return getContext().getString(
diff --git a/src/com/android/settings/notification/TopicNotificationSettings.java b/src/com/android/settings/notification/TopicNotificationSettings.java
index 71196b7..e847e34 100644
--- a/src/com/android/settings/notification/TopicNotificationSettings.java
+++ b/src/com/android/settings/notification/TopicNotificationSettings.java
@@ -135,13 +135,11 @@
                 mTopicRow.importance == NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED
                 ? NotificationListenerService.Ranking.IMPORTANCE_DEFAULT
                         : mTopicRow.importance;
-        mImportance.setProgress(
-                importance + ImportanceSeekBarPreference.IMPORTANCE_PROGRESS_OFFSET);
+        mImportance.setProgress(importance);
         mImportance.setCallback(new ImportanceSeekBarPreference.Callback() {
             @Override
             public void onImportanceChanged(int progress) {
-                mBackend.setImportance(mTopicRow.pkg, mTopicRow.uid, mTopicRow.topic,
-                        progress - ImportanceSeekBarPreference.IMPORTANCE_PROGRESS_OFFSET);
+                mBackend.setImportance(mTopicRow.pkg, mTopicRow.uid, mTopicRow.topic, progress);
             }
         });
         mPriority.setChecked(mTopicRow.priority);