Merge "Code cleanup including removing direct references to IMS classes."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 43fe796..8c9af29 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1468,6 +1468,17 @@
             </intent-filter>
         </activity>
 
+        <!-- Note this must not be exported since it authenticates the given user -->
+        <activity android:name="ConfirmDeviceCredentialActivity$InternalActivity"
+            android:exported="false"
+            android:permission="android.permission.MANAGE_USERS"
+            android:theme="@android:style/Theme.NoDisplay">
+            <intent-filter android:priority="1">
+                <action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".SetupRedactionInterstitial"
             android:taskAffinity="com.android.wizard"
             android:theme="@style/SetupWizardDisableAppStartingTheme"/>
@@ -2646,5 +2657,40 @@
                 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>
+
+        <!-- Conditional receivers, only enabled during silenced state, default off-->
+        <receiver
+            android:name=".dashboard.conditional.HotspotCondition$Receiver"
+            android:enabled="false">
+            <intent-filter>
+                 <action android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
+            </intent-filter>
+       </receiver>
+
+        <receiver
+            android:name=".dashboard.conditional.AirplaneModeCondition$Receiver"
+            android:enabled="false">
+            <intent-filter>
+                 <action android:name="android.intent.action.AIRPLANE_MODE" />
+            </intent-filter>
+       </receiver>
+
+        <receiver
+            android:name=".dashboard.conditional.DndCondition$Receiver"
+            android:enabled="false">
+            <intent-filter>
+                 <action android:name="android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL" />
+            </intent-filter>
+       </receiver>
+
     </application>
 </manifest>
diff --git a/res/drawable/ic_add_24dp.xml b/res/drawable/ic_add_24dp.xml
index 6535107..97178b2 100644
--- a/res/drawable/ic_add_24dp.xml
+++ b/res/drawable/ic_add_24dp.xml
@@ -14,11 +14,12 @@
   ~ limitations under the License
   -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="48"
+        android:viewportHeight="48"
+        android:tint="?android:attr/colorAccent">
     <path
-        android:fillColor="?android:attr/colorAccent"
-        android:pathData="M38.0,26.0L26.0,26.0l0.0,12.0l-4.0,0.0L22.0,26.0L10.0,26.0l0.0,-4.0l12.0,0.0L22.0,10.0l4.0,0.0l0.0,12.0l12.0,0.0l0.0,4.0z"/>
+        android:fillColor="@android:color/white"
+        android:pathData="M38,26L26,26l0,12l-4,0L22,26L10,26l0,-4l12,0L22,10l4,0l0,12l12,0l0,4.0z"/>
 </vector>
diff --git a/res/drawable/ic_airplane.xml b/res/drawable/ic_airplane.xml
new file mode 100644
index 0000000..b3e0ba0
--- /dev/null
+++ b/res/drawable/ic_airplane.xml
@@ -0,0 +1,57 @@
+<?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:name="root"
+    android:alpha="1.0"
+    android:height="48dp"
+    android:width="48dp"
+    android:viewportHeight="48"
+    android:viewportWidth="48" >
+    <group
+        android:name="ic_signal_airplane"
+        android:translateX="21.9995"
+        android:translateY="25.73401" >
+        <group
+            android:name="ic_signal_airplane_pivot"
+            android:translateX="-23.21545"
+            android:translateY="-18.86649" >
+            <clip-path
+                android:name="mask"
+                android:pathData="M 37.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z" />
+            <group
+                android:name="cross" >
+                <path
+                    android:name="cross_1"
+                    android:pathData="M 7.54049682617,3.9430847168 c 0.0,0.0 0.324981689453,0.399978637695 0.324981689453,0.399978637695 "
+                    android:strokeColor="#FFFFFFFF"
+                    android:strokeAlpha="0"
+                    android:strokeWidth="3.5"
+                    android:fillColor="#00000000" />
+            </group>
+            <group
+                android:name="plane"
+                android:translateX="23.481"
+                android:translateY="18.71151" >
+                <path
+                    android:name="plane_1"
+                    android:pathData="M 18.9439849854,7.98849487305 c 0.0,0.0 0.0,-4.0 0.0,-4.0 c 0.0,0.0 -16.0,-10.0 -16.0,-10.0 c 0.0,0.0 0.0,-11.0 0.0,-11.0 c 0.0,-1.70001220703 -1.30000305176,-3.0 -3.0,-3.0 c -1.69999694824,0.0 -3.0,1.29998779297 -3.0,3.0 c 0.0,0.0 0.0,11.0 0.0,11.0 c 0.0,0.0 -16.0,10.0 -16.0,10.0 c 0.0,0.0 0.0,4.0 0.0,4.0 c 0.0,0.0 16.0,-5.0 16.0,-5.0 c 0.0,0.0 0.0,11.0 0.0,11.0 c 0.0,0.0 -4.0,3.0 -4.0,3.0 c 0.0,0.0 0.0,3.0 0.0,3.0 c 0.0,0.0 7.0,-2.0 7.0,-2.0 c 0.0,0.0 7.0,2.0 7.0,2.0 c 0.0,0.0 0.0,-3.0 0.0,-3.0 c 0.0,0.0 -4.0,-3.0 -4.0,-3.0 c 0.0,0.0 0.0,-11.0 0.0,-11.0 c 0.0,0.0 16.0,5.0 16.0,5.0 Z"
+                    android:fillColor="#FFFFFFFF"
+                    android:fillAlpha="1" />
+            </group>
+        </group>
+    </group>
+</vector>
diff --git a/res/drawable/ic_expand_less.xml b/res/drawable/ic_expand_less.xml
index 3a00faf..7ccc080 100644
--- a/res/drawable/ic_expand_less.xml
+++ b/res/drawable/ic_expand_less.xml
@@ -19,10 +19,11 @@
     android:width="24dp"
     android:height="24dp"
     android:viewportWidth="24"
-    android:viewportHeight="24">
+    android:viewportHeight="24"
+    android:tint="?android:attr/colorControlNormal">
 
     <path
-        android:fillColor="?android:attr/colorControlNormal"
+        android:fillColor="@android:color/white"
         android:pathData="M12.0,8.0l-6.0,6.0 1.41,1.41L12.0,10.83l4.59,4.58L18.0,14.0z"/>
 
 </vector>
diff --git a/res/drawable/ic_expand_more.xml b/res/drawable/ic_expand_more.xml
index 64d2242..609cf36 100644
--- a/res/drawable/ic_expand_more.xml
+++ b/res/drawable/ic_expand_more.xml
@@ -19,10 +19,11 @@
     android:width="24dp"
     android:height="24dp"
     android:viewportWidth="24"
-    android:viewportHeight="24">
+    android:viewportHeight="24"
+    android:tint="?android:attr/colorControlNormal">
 
     <path
-        android:fillColor="?android:attr/colorControlNormal"
+        android:fillColor="@android:color/white"
         android:pathData="M16.59,8.59L12.0,13.17 7.41,8.59 6.0,10.0l6.0,6.0 6.0,-6.0z"/>
 
 </vector>
diff --git a/res/drawable/ic_hotspot.xml b/res/drawable/ic_hotspot.xml
new file mode 100644
index 0000000..d8528dd
--- /dev/null
+++ b/res/drawable/ic_hotspot.xml
@@ -0,0 +1,62 @@
+<?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:name="root"
+    android:alpha="1.0"
+    android:height="48dp"
+    android:width="48dp"
+    android:viewportHeight="48"
+    android:viewportWidth="48" >
+    <group
+        android:name="ic_hotspot"
+        android:translateX="23.9778"
+        android:translateY="24.26443" >
+        <group
+            android:name="ic_hotspot_pivot"
+            android:translateX="-23.21545"
+            android:translateY="-18.86649" >
+            <clip-path
+                android:name="mask"
+                android:pathData="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 6.97125244141,7.33258056641 6.97125244141,7.33258056641 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -6.77128601074,-6.82850646973 -6.77128601074,-6.82850646973 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 0.659332275391,0.664688110352 0.659332275391,0.664688110351 c 0.0,0.0 -3.13299560547,2.82977294922 -3.13299560547,2.82977294922 c 0.0,0.0 29.0108337402,34.4080963135 29.0108337402,34.4080963135 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z" />
+            <group
+                android:name="cross" >
+                <path
+                    android:name="cross_1"
+                    android:pathData="M 4.44044494629,2.24310302734 c 0.0,0.0 0.0875396728516,0.112457275391 0.0875396728516,0.112457275391 "
+                    android:strokeColor="#FFFFFFFF"
+                    android:strokeAlpha="0"
+                    android:strokeWidth="3.5"
+                    android:fillColor="#00000000" />
+            </group>
+            <group
+                android:name="hotspot"
+                android:translateX="23.481"
+                android:translateY="18.71151" >
+                <group
+                    android:name="circles"
+                    android:translateX="-0.23909"
+                    android:translateY="-0.10807" >
+                    <path
+                        android:name="path_3"
+                        android:pathData="M -0.0042724609375,-2.64895629883 c -2.20922851562,0.0 -4.0,1.791015625 -4.0,4.0 c 0.0,2.20922851562 1.79077148438,4.0 4.0,4.0 c 2.208984375,0.0 4.0,-1.79077148438 4.0,-4.0 c 0.0,-2.208984375 -1.791015625,-4.0 -4.0,-4.0 Z M 11.9957275391,1.35104370117 c 0.0,-6.626953125 -5.373046875,-12.0 -12.0,-12.0 c -6.62719726562,0.0 -12.0,5.373046875 -12.0,12.0 c 0.0,4.43603515625 2.41381835938,8.30004882812 5.99194335938,10.3771972656 c 0.0,0.0 2.01586914062,-3.48217773438 2.01586914062,-3.48217773438 c -2.38500976562,-1.38500976562 -4.0078125,-3.93798828125 -4.0078125,-6.89501953125 c 0.0,-4.41796875 3.58178710938,-8.0 8.0,-8.0 c 4.41796875,0.0 8.0,3.58203125 8.0,8.0 c 0.0,2.95703125 -1.623046875,5.51000976562 -4.00805664062,6.89501953125 c 0.0,0.0 2.01586914062,3.48217773438 2.01586914062,3.48217773438 c 3.578125,-2.0771484375 5.9921875,-5.94116210938 5.9921875,-10.3771972656 Z M -0.0042724609375,-18.6489562988 c -11.0451660156,0.0 -20.0,8.9541015625 -20.0,20.0 c 0.0,7.39306640625 4.02099609375,13.8330078125 9.98779296875,17.2951660156 c 0.0,0.0 2.00219726562,-3.458984375 2.00219726562,-3.458984375 c -4.77319335938,-2.77001953125 -7.98999023438,-7.92211914062 -7.98999023438,-13.8361816406 c 0.0,-8.8369140625 7.16381835938,-16.0 16.0,-16.0 c 8.83595275879,0.0 16.0000152588,7.1630859375 16.0000152588,16.0 c 0.0,5.9140625 -3.21704101562,11.0661621094 -7.990234375,13.8361816406 c 0.0,0.0 2.00219726562,3.458984375 2.00219726563,3.458984375 c 5.966796875,-3.46215820312 9.98803710937,-9.90209960938 9.98803710938,-17.2951660156 c 0.0,-11.0458984375 -8.955078125,-20.0 -20.0000152588,-20.0 Z"
+                        android:fillColor="#FFFFFFFF"
+                        android:fillAlpha="1" />
+                </group>
+            </group>
+        </group>
+    </group>
+</vector>
diff --git a/res/drawable/ic_info.xml b/res/drawable/ic_info.xml
index 13d00a4..6e19d26 100644
--- a/res/drawable/ic_info.xml
+++ b/res/drawable/ic_info.xml
@@ -14,11 +14,11 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M11.0,17.0l2.0,0.0l0.0,-6.0l-2.0,0.0l0.0,6.0zm1.0,-15.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm0.0,18.0c-4.41,0.0 -8.0,-3.59 -8.0,-8.0s3.59,-8.0 8.0,-8.0 8.0,3.59 8.0,8.0 -3.59,8.0 -8.0,8.0zM11.0,9.0l2.0,0.0L13.0,7.0l-2.0,0.0l0.0,2.0z"/>
+        android:fillColor="@android:color/white"
+        android:pathData="M11,17l2,0l0,-6l-2,0l0,6.0zm1,-15.0C6.48,2 2,6.48 2,12.0s4.48,10 10,10 10,-4.48 10,-10.0S17.52,2 12,2.0zm0,18.0c-4.41,0 -8,-3.59 -8,-8.0s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8.0zM11,9l2,0L13,7l-2,0l0,2.0z"/>
 </vector>
diff --git a/res/drawable/ic_remove_24dp.xml b/res/drawable/ic_remove_24dp.xml
new file mode 100644
index 0000000..9233623
--- /dev/null
+++ b/res/drawable/ic_remove_24dp.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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="48"
+        android:viewportHeight="48"
+        android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M38 26H10v-4h28v4z"/>
+</vector>
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/drawable/ic_zen.xml b/res/drawable/ic_zen.xml
new file mode 100644
index 0000000..17ecf21
--- /dev/null
+++ b/res/drawable/ic_zen.xml
@@ -0,0 +1,26 @@
+<!--
+     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:height="24dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24dp" >
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z" />
+
+</vector>
diff --git a/res/drawable/screen_zoom_preview_action_background.xml b/res/drawable/screen_zoom_preview_action_background.xml
new file mode 100644
index 0000000..32fbb02
--- /dev/null
+++ b/res/drawable/screen_zoom_preview_action_background.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <size android:width="24dp"
+          android:height="24dp" />
+    <solid android:color="@android:color/white" />
+</shape>
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/layout/condition_card.xml b/res/layout/condition_card.xml
new file mode 100644
index 0000000..482d5b6
--- /dev/null
+++ b/res/layout/condition_card.xml
@@ -0,0 +1,109 @@
+<?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:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:background="?android:attr/colorAccent"
+    android:elevation="3dp"
+    android:clickable="true">
+
+    <LinearLayout
+        android:id="@+id/collapsed_group"
+        android:layout_width="match_parent"
+        android:layout_height="56dp"
+        android:orientation="horizontal"
+        android:gravity="center">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="24dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="36dp"
+            android:tint="?android:attr/textColorPrimaryInverse" />
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorPrimaryInverse" />
+
+        <ImageView
+            android:id="@+id/expand_indicator"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:tint="?android:attr/textColorPrimaryInverse"
+            android:padding="?android:attr/listPreferredItemPaddingEnd"
+            android:clickable="true"
+            android:background="?android:attr/selectableItemBackground" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/detail_group"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="60dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@android:id/summary"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+            android:paddingBottom="16dp"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorPrimaryInverse" />
+
+        <!-- TODO: Better background -->
+        <View
+            android:layout_width="match_parent"
+            android:layout_height=".25dp"
+            android:background="@android:color/white" />
+
+        <com.android.internal.widget.ButtonBarLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp"
+            style="?attr/buttonBarStyle"
+            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+            <Button
+                android:id="@+id/first_action"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="0dp"
+                android:textColor="?android:attr/textColorPrimaryInverse"
+                style="?android:attr/buttonBarButtonStyle" />
+
+            <Button
+                android:id="@+id/second_action"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textColor="?android:attr/textColorPrimaryInverse"
+                style="?android:attr/buttonBarButtonStyle" />
+
+        </com.android.internal.widget.ButtonBarLayout>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/dashboard.xml b/res/layout/dashboard.xml
index ae5be68..93261a53 100644
--- a/res/layout/dashboard.xml
+++ b/res/layout/dashboard.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<android.support.v7.widget.RecyclerView
+<com.android.settings.dashboard.conditional.FocusRecyclerView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/dashboard_container"
     android:layout_width="match_parent"
diff --git a/res/layout/fingerprint_enroll_find_sensor_base.xml b/res/layout/fingerprint_enroll_find_sensor_base.xml
index f65e932..3f69a0a 100644
--- a/res/layout/fingerprint_enroll_find_sensor_base.xml
+++ b/res/layout/fingerprint_enroll_find_sensor_base.xml
@@ -22,48 +22,50 @@
     android:layout_height="match_parent"
     style="?attr/fingerprint_layout_theme">
 
-    <LinearLayout
-        style="@style/SuwContentFrame"
+    <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical"
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <TextView
-            style="@style/TextAppearance.FingerprintMessage"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/suw_description_margin_top"
-            android:text="@string/security_settings_fingerprint_enroll_find_sensor_message"/>
-
-        <View
-            android:layout_height="0dp"
-            android:layout_width="match_parent"
-            android:layout_weight="1"/>
-
         <include
             layout="@layout/fingerprint_enroll_find_sensor_graphic"
-            android:layout_width="@dimen/fingerprint_find_sensor_graphic_size"
-            android:layout_height="@dimen/fingerprint_find_sensor_graphic_size"
-            android:layout_gravity="center_horizontal"/>
-
-        <View
-            android:layout_height="0dp"
             android:layout_width="match_parent"
-            android:layout_weight="1"/>
+            android:layout_height="match_parent"
+            android:layout_gravity="center_horizontal|bottom"/>
 
-        <Button
-            style="@style/Button.FingerprintButton"
-            android:id="@+id/next_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="4dp"
-            android:layout_marginEnd="-12dp"
-            android:layout_gravity="end"
-            android:gravity="end|center_vertical"
-            android:text="@string/fingerprint_enroll_button_next" />
+        <LinearLayout
+            style="@style/SuwContentFrame"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical"
+            android:clipToPadding="false"
+            android:clipChildren="false">
 
-    </LinearLayout>
+            <TextView
+                style="@style/TextAppearance.FingerprintMessage"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/suw_description_margin_top"
+                android:text="@string/security_settings_fingerprint_enroll_find_sensor_message"/>
 
+            <View
+                android:layout_height="0dp"
+                android:layout_width="match_parent"
+                android:layout_weight="1"/>
+
+            <Button
+                style="@style/Button.FingerprintButton"
+                android:id="@+id/next_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="4dp"
+                android:layout_marginEnd="-12dp"
+                android:layout_gravity="end"
+                android:gravity="end|center_vertical"
+                android:text="@string/fingerprint_enroll_button_next" />
+
+        </LinearLayout>
+    </FrameLayout>
 </com.android.setupwizardlib.SetupWizardLayout>
diff --git a/res/layout/screen_zoom_activity.xml b/res/layout/screen_zoom_activity.xml
new file mode 100644
index 0000000..81ce102
--- /dev/null
+++ b/res/layout/screen_zoom_activity.xml
@@ -0,0 +1,96 @@
+<?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:paddingLeft="?android:attr/listPreferredItemPaddingStart"
+        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/screen_zoom_summary"
+            android:layout_marginBottom="16dp"
+            android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/screen_zoom_preview_height"
+            android:background="?android:attr/colorBackgroundFloating"
+            android:elevation="2dp">
+
+            <com.android.settings.display.TouchBlockingFrameLayout
+                android:id="@+id/preview_frame"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
+            <TextView
+                android:id="@+id/current_density"
+                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/screen_zoom_make_smaller_desc" />
+
+            <SeekBar
+                android:id="@+id/seek_bar"
+                android:layout_width="0dp"
+                android:layout_height="48dp"
+                android:layout_weight="1" />
+
+            <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/screen_zoom_make_larger_desc" />
+        </LinearLayout>
+    </LinearLayout>
+</ScrollView>
diff --git a/res/layout/screen_zoom_preview.xml b/res/layout/screen_zoom_preview.xml
new file mode 100644
index 0000000..7cdb663
--- /dev/null
+++ b/res/layout/screen_zoom_preview.xml
@@ -0,0 +1,85 @@
+<?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">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="?android:attr/actionBarSize"
+        android:orientation="horizontal"
+        android:theme="?android:attr/actionBarTheme"
+        style="?android:attr/actionBarStyle">
+
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginLeft="16dp"
+            android:text="@string/screen_zoom_preview_title"
+            android:textAppearance="@android:style/TextAppearance.Material.Widget.ActionBar.Title" />
+
+        <ImageView
+            android:layout_width="36dp"
+            android:layout_height="48dp"
+            style="?android:attr/actionOverflowButtonStyle" />
+    </LinearLayout>
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scrollbars="none"
+        android:background="?android:attr/colorBackgroundFloating">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <TextView
+                style="@android:style/TextAppearance.Material.Subhead"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="16dp"
+                android:layout_marginTop="16dp"
+                android:text="@string/permissions_label" />
+
+            <include layout="@layout/screen_zoom_preview_item" />
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1dp"
+                android:layout_marginLeft="62dp"
+                android:layout_marginRight="8dp"
+                android:background="#36000000" />
+
+            <include layout="@layout/screen_zoom_preview_item" />
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1dp"
+                android:layout_marginLeft="62dp"
+                android:layout_marginRight="8dp"
+                android:background="#36000000" />
+
+            <include layout="@layout/screen_zoom_preview_item" />
+
+        </LinearLayout>
+
+    </ScrollView>
+</LinearLayout>
diff --git a/res/layout/screen_zoom_preview_item.xml b/res/layout/screen_zoom_preview_item.xml
new file mode 100644
index 0000000..68076f0
--- /dev/null
+++ b/res/layout/screen_zoom_preview_item.xml
@@ -0,0 +1,65 @@
+<?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"
+              xmlns:tools="http://schemas.android.com/tools"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:gravity="center_vertical"
+              android:padding="16dp"
+              tools:showIn="@layout/screen_zoom_preview">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:background="@drawable/screen_zoom_preview_action_background"
+        android:backgroundTint="?android:attr/colorAccent"
+        android:src="@drawable/ic_settings_32dp"
+        android:scaleType="center" />
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingStart="16dp">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/usage_access"
+            style="@android:style/TextAppearance.Material.Body1" />
+
+        <TextView
+            android:id="@+id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/usage_access_description"
+            style="@android:style/TextAppearance.Material.Caption" />
+    </LinearLayout>
+
+    <ImageView
+        android:id="@+id/action"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginLeft="24dp"
+        android:src="@drawable/ic_info"
+        android:tint="?android:attr/colorControlNormal"
+        android:tintMode="src_in"
+        android:scaleType="center" />
+</LinearLayout>
diff --git a/res/raw/fingerprint_location_animation.mp4 b/res/raw/fingerprint_location_animation.mp4
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/res/raw/fingerprint_location_animation.mp4
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index d15c254..7612c97 100755
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -48,4 +48,7 @@
     <!-- Fingerprint -->
     <item name="fingerprint_illustration_aspect_ratio" format="float" type="dimen">0.0</item>
     <dimen name="fingerprint_decor_padding_top">24dp</dimen>
+
+    <!-- Display, Screen zoom -->
+    <dimen name="screen_zoom_preview_height">160dp</dimen>
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 62c34ea..5d7758b 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -110,8 +110,7 @@
     <attr name="confirmDeviceCredentialsSideMargin" format="dimension" />
     <attr name="confirmDeviceCredentialsTopMargin" format="dimension" />
 
-    <declare-styleable name="DropDownPreference">
-        <attr name="android:entries" />
-        <attr name="android:entryValues" />
+    <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 dc0b186..539dc05 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -101,7 +101,7 @@
     <dimen name="dashboard_category_padding_end">0dp</dimen>
 
     <!-- Dashboard category panel elevation -->
-    <dimen name="dashboard_category_elevation">4dp</dimen>
+    <dimen name="dashboard_category_elevation">2dp</dimen>
 
     <!-- Dashboard category title layout height -->
     <dimen name="dashboard_category_title_height">48dp</dimen>
@@ -250,6 +250,18 @@
     <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>
+
+    <!-- Display, Screen zoom -->
+    <dimen name="screen_zoom_preview_height">240dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f0955a6..26961c8 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] -->
@@ -5512,46 +5512,44 @@
     <string name="search_results_label">Results</string>
 
     <!--Search Keywords [CHAR LIMIT=NONE]-->
-    <string name="keywords_wifi">wifi wi-fi network connection</string>
-    <string name="keywords_more_default_sms_app">text message texting messages messaging</string>
-    <string name="keywords_more_mobile_networks">cellular cell carrier wireless data 4g 3g 2g lte</string>
-    <string name="keywords_wifi_calling">wifi wi-fi call calling</string>
+    <string name="keywords_wifi">wifi, wi-fi, network connection</string>
+    <string name="keywords_more_default_sms_app">text message, texting, messages, messaging</string>
+    <string name="keywords_more_mobile_networks">cellular, cell carrier, wireless, data, 4g, 3g, 2g, lte</string>
+    <string name="keywords_wifi_calling">wifi, wi-fi, call, calling</string>
     <string name="keywords_home">launcher</string>
-    <string name="keywords_display">screen touchscreen</string>
-    <string name="keywords_display_brightness_level">dim screen touchscreen battery</string>
-    <string name="keywords_display_auto_brightness">dim screen touchscreen battery</string>
-    <!-- Search keywords for display light/dark theme: dark theme, night mode, dim screen, invert brightness [CHAR LIMIT=NONE] -->
-    <string name="keywords_display_night_mode">dark theme night mode dim screen invert brightness</string>
-    <string name="keywords_display_wallpaper">background personalize customize display</string>
+    <string name="keywords_display">screen, touchscreen</string>
+    <string name="keywords_display_brightness_level">dim screen, touchscreen, battery</string>
+    <string name="keywords_display_auto_brightness">dim screen, touchscreen, battery</string>
+    <string name="keywords_display_night_mode">dark theme, night mode, dim screen, invert brightness</string>
+    <string name="keywords_display_wallpaper">background, personalize, customize display</string>
     <string name="keywords_display_font_size">text size</string>
-    <string name="keywords_display_cast_screen">project cast</string>
-    <string name="keywords_storage">space disk hard drive device usage</string>
-    <string name="keywords_battery">power usage charge</string>
-    <string name="keywords_spell_checker">spelling dictionary spellcheck auto-correct</string>
-    <string name="keywords_voice_input">recognizer input speech speak language hands-free hand free recognition offensive word audio history bluetooth headset</string>
-    <string name="keywords_text_to_speech_output">rate language default speak speaking tts accessibility reader blind</string>
-    <string name="keywords_date_and_time">clock military</string>
-    <string name="keywords_network_reset">reset restore factory</string>
-    <string name="keywords_factory_data_reset">wipe delete restore clear remove</string>
+    <string name="keywords_display_cast_screen">project, cast</string>
+    <string name="keywords_storage">space, disk, hard drive, device usage</string>
+    <string name="keywords_battery">power usage, charge</string>
+    <string name="keywords_spell_checker">spelling, dictionary, spellcheck, auto-correct</string>
+    <string name="keywords_voice_input">recognizer, input, speech, speak, language, hands-free, hand free recognition offensive word audio history bluetooth headset</string>
+    <string name="keywords_text_to_speech_output">rate, language, default, speak, speaking, tts, accessibility, screen reader, blind</string>
+    <string name="keywords_date_and_time">clock, military</string>
+    <string name="keywords_network_reset">reset, restore, factory</string>
+    <string name="keywords_factory_data_reset">wipe, delete, restore, clear, remove</string>
     <string name="keywords_printing">printer</string>
     <string name="keywords_sounds">speaker beep</string>
-    <string name="keywords_sounds_and_notifications_interruptions">dont don\u2019t disturb interrupt interruption break</string>
+    <string name="keywords_sounds_and_notifications_interruptions">dont don\u2019t disturb, interrupt, interruption, break</string>
     <string name="keywords_app">RAM</string>
-    <string name="keywords_location">nearby location history reporting</string>
+    <string name="keywords_location">nearby, location, history, reporting</string>
     <string name="keywords_location_mode">accuracy</string>
     <string name="keywords_accounts">account</string>
-    <string name="keywords_users">restriction restrict restricted</string>
-    <string name="keywords_keyboard_and_ime">text correction correct sound vibrate auto language gesture suggest suggestion theme offensive word type emoji international</string>
-    <string name="keywords_reset_apps">reset preferences default</string>
-    <string name="keywords_emergency_app">emergency ice app default</string>
-    <string name="keywords_default_phone_app">phone dialer default</string>
-    <string name="keywords_all_apps">apps download applications system</string>
-    <string name="keywords_app_permissions">apps permissions security</string>
-    <string name="keywords_default_apps">apps default</string>
-    <string name="keywords_ignore_optimizations">ignore optimizations doze app standby</string>
-    <string name="keywords_color_mode">vibrant rgb srgb color natural standard</string>
-    <!-- Search keywords for different screen unlock modes : slide to unlock, password, pattern and PIN [CHAR LIMIT=none] -->
-    <string name="keywords_lockscreen">slide password pattern pin</string>
+    <string name="keywords_users">restriction, restrict, restricted</string>
+    <string name="keywords_keyboard_and_ime">text correction, correct, sound, vibrate, auto, language, gesture, suggest, suggestion, theme, offensive, word, type, emoji, international</string>
+    <string name="keywords_reset_apps">reset, preferences, default</string>
+    <string name="keywords_emergency_app">emergency, ice, app, default</string>
+    <string name="keywords_default_phone_app">phone, dialer, default</string>
+    <string name="keywords_all_apps">apps, download, applications, system</string>
+    <string name="keywords_app_permissions">apps, permissions, security</string>
+    <string name="keywords_default_apps">apps, default</string>
+    <string name="keywords_ignore_optimizations">ignore optimizations, doze, app standby</string>
+    <string name="keywords_color_mode">vibrant, rgb, srgb, color, natural, standard</string>
+    <string name="keywords_lockscreen">slide to unlock, password, pattern, pin</string>
 
     <!-- NFC Wi-Fi pairing/setup strings-->
 
@@ -6613,23 +6611,33 @@
     <!-- Description of setting that controls gesture to open camera by double tapping the power button [CHAR LIMIT=NONE] -->
     <string name="camera_double_tap_power_gesture_desc">Quickly open camera without unlocking your screen</string>
 
-    <!-- Title of setting that controls display scale (e.g. density). [CHAR LIMIT=40] -->
-    <string name="force_density_preference_title">Display scale</string>
-    <!-- Keywords for setting that controls display scale (e.g. density). [CHAR LIMIT=NONE] -->
-    <string name="force_density_keywords">display density zoom scale scaling</string>
-    <!-- Description for the display scale that makes interface elements small. [CHAR LIMIT=24] -->
-    <string name="force_density_summary_small">Small</string>
-    <!-- Description for the device's default display scale. [CHAR LIMIT=24] -->
-    <string name="force_density_summary_normal">Normal</string>
-    <!-- Description for the display scale that makes interface elements large. [CHAR LIMIT=24] -->
-    <string name="force_density_summary_large">Large</string>
-    <!-- Description for the display scale that makes interface elements larger. [CHAR LIMIT=24] -->
-    <string name="force_density_summary_very_large">Larger</string>
-    <!-- Description for the display scale that makes interface elements largest. [CHAR LIMIT=24] -->
-    <string name="force_density_summary_extremely_large">Largest</string>
-    <!-- Description for a custom display scale. This shows the requested display
-         density in raw pixels per inch rather than computing a scale amount. [CHAR LIMIT=24] -->
-    <string name="force_density_summary_custom">Custom (<xliff:g id="densityDpi" example="160">%d</xliff:g>)</string>
+    <!-- Title of setting that controls screen zoom (e.g. how large interface elements appear). [CHAR LIMIT=40] -->
+    <string name="screen_zoom_title">Screen zoom</string>
+    <!-- Keywords for setting that controls screen zoom (e.g. how large interface elements appear). [CHAR LIMIT=NONE] -->
+    <string name="screen_zoom_keywords">display density, screen zoom, scale, scaling</string>
+
+    <string name="screen_zoom_summary">Choose how zoomed you want the screen using the slider below the preview image.</string>
+
+    <!-- Title of the screen zoom preview activity. -->
+    <string name="screen_zoom_preview_title">Preview</string>
+    <!-- Description for the button that makes interface elements smaller. [CHAR_LIMIT=NONE] -->
+    <string name="screen_zoom_make_smaller_desc">Make smaller</string>
+    <!-- Description for the button that makes interface elements larger. [CHAR_LIMIT=NONE] -->
+    <string name="screen_zoom_make_larger_desc">Make larger</string>
+
+    <!-- Description for the screen zoom level that makes interface elements small. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_small">Small</string>
+    <!-- Description for the device's default screen zoom level. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_normal">Normal</string>
+    <!-- Description for the screen zoom level that makes interface elements large. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_large">Large</string>
+    <!-- Description for the screen zoom level that makes interface elements larger. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_very_large">Larger</string>
+    <!-- Description for the screen zoom level that makes interface elements largest. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_extremely_large">Largest</string>
+    <!-- Description for a custom screen zoom level. This shows the requested display
+         density in raw pixels per inch rather than using a relative description. [CHAR LIMIT=24] -->
+    <string name="screen_zoom_summary_custom">Custom (<xliff:g id="densityDpi" example="160">%d</xliff:g>)</string>
 
     <!-- Button to show all top-level settings items [CHAR LIMIT=20] -->
     <string name="see_all">See all</string>
@@ -6674,4 +6682,30 @@
 
     <!-- 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>
+
+    <!-- Turn off a conditional state of the device (e.g. airplane mode, or hotspot) [CHAR LIMIT=30] -->
+    <string name="condition_turn_off">Turn off</string>
+
+    <!-- Title of condition that hotspot is on [CHAR LIMIT=30] -->
+    <string name="condition_hotspot_title">Hotspot is on</string>
+
+    <!-- Summary of condition that hotspot is on [CHAR LIMIT=NONE] -->
+    <string name="condition_hotspot_summary">Portable Wi-Fi hotspot <xliff:g name="ap_name" example="AndroidAP">%1$s</xliff:g> is active, Wi-Fi for this device is turned off.</string>
+
+    <!-- Title of condition that airplane mode is on [CHAR LIMIT=30] -->
+    <string name="condition_airplane_title">Airplane mode is on</string>
+
+    <!-- Summary of condition that airplane mode is on [CHAR LIMIT=NONE] -->
+    <string name="condition_airplane_summary">Wi-Fi, Bluetooth, and cellular network are turned off. You can\'t make phone calls or connect to the Internet.</string>
+
+    <!-- Title of condition that do not disturb is on [CHAR LIMIT=30] -->
+    <string name="condition_zen_title">Do not disturb is on (<xliff:g name="zen_mode_type" example="Alarms only">%1$s</xliff:g>)</string>
+
 </resources>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index e72ad30..b15a77c 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -101,6 +101,7 @@
 
     <style name="PreferenceTheme" parent="@android:style/Theme.DeviceDefault.Settings">
         <item name="@android:preferenceStyle">@style/Preference</item>
+        <item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
         <item name="@android:preferenceFragmentStyle">@style/PreferenceFragmentStyle</item>
 
         <item name="apnPreferenceStyle">@style/ApnPreference</item>
diff --git a/res/xml/battery_saver_settings.xml b/res/xml/battery_saver_settings.xml
index 0134c6f..cc6d9af 100644
--- a/res/xml/battery_saver_settings.xml
+++ b/res/xml/battery_saver_settings.xml
@@ -19,9 +19,10 @@
         android:key="battery_saver">
 
     <!-- Turn on automatically -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
             android:key="turn_on_automatically"
             android:title="@string/battery_saver_turn_on_automatically_title"
+            android:summary="%s"
             android:persistent="false" />
 
     <!-- Feature description text -->
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index aa15f06..d64132a 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -26,9 +26,10 @@
             android:persistent="false" />
 
     <!-- When device is locked -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
             android:key="lock_screen_notifications"
             android:title="@string/lock_screen_notifications_title"
+            android:summary="%s"
             android:persistent="false" />
 
     <PreferenceCategory
diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml
index d3c8852..57fdc36 100644
--- a/res/xml/development_prefs.xml
+++ b/res/xml/development_prefs.xml
@@ -60,10 +60,11 @@
         android:summary="@string/runningservices_settings_summary"
         android:fragment="com.android.settings.applications.RunningServices" />
 
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
         android:key="night_mode"
         android:title="@string/night_mode_title"
-        android:summary="@string/night_mode_summary"
+        android:summary="%s"
+        android:persistent="false"
         android:entries="@array/night_mode_entries"
         android:entryValues="@array/night_mode_values" />
 
@@ -79,6 +80,12 @@
         android:summary="@string/picture_color_mode_desc"
         android:persistent="false" />
 
+    <ListPreference
+        android:key="select_webview_provider"
+        android:title="@string/select_webview_provider_title"
+        android:dialogTitle="@string/select_webview_provider_dialog_title"
+        android:summary="%s" />
+
     <PreferenceCategory android:key="debug_debugging_category"
             android:title="@string/debug_debugging_category">
 
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index 60730a9..0456ace 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -91,23 +91,24 @@
                 android:summary="@string/tap_to_wake_summary"
                 android:persistent="false" />
 
-        <com.android.settings.DropDownPreference
+        <DropDownPreference
                 android:key="font_size"
                 android:title="@string/title_font_size"
                 settings:keywords="@string/keywords_display_font_size"
-                android:summary="@string/summary_font_size"
+                android:persistent="false"
+                android:summary="%s"
                 android:entries="@array/entries_font_size"
                 android:entryValues="@array/entryvalues_font_size" />
 
-        <com.android.settings.DisplayDensityPreference
-                android:key="display_density"
-                android:title="@string/force_density_preference_title"
-                android:summary="%s"
-                settings:keywords="@string/force_density_keywords"
-                android:persistent="false" />
+        <com.android.settings.display.ScreenZoomPreference
+                android:key="screen_zoom"
+                android:title="@string/screen_zoom_title"
+                settings:keywords="@string/screen_zoom_keywords" />
 
-        <com.android.settings.DropDownPreference
+        <DropDownPreference
                 android:key="auto_rotate"
+                android:persistent="false"
+                android:summary="%s"
                 android:title="@string/display_auto_rotate_title" />
 
         <PreferenceScreen
diff --git a/res/xml/installed_app_launch_settings.xml b/res/xml/installed_app_launch_settings.xml
index e48476f..dee56ef 100644
--- a/res/xml/installed_app_launch_settings.xml
+++ b/res/xml/installed_app_launch_settings.xml
@@ -20,9 +20,10 @@
     <PreferenceCategory android:key="app_launch_domain_links"
                         android:title="@string/app_launch_domain_links_title">
 
-        <com.android.settings.DropDownPreference
+        <DropDownPreference
                 android:key="app_link_state"
                 android:persistent="false"
+                android:summary="%s"
                 android:title="@string/app_launch_open_domain_urls_title" />
 
         <com.android.settings.applications.AppDomainsPreference
diff --git a/res/xml/other_sound_settings.xml b/res/xml/other_sound_settings.xml
index cc88c3f..df113dc 100644
--- a/res/xml/other_sound_settings.xml
+++ b/res/xml/other_sound_settings.xml
@@ -56,15 +56,17 @@
             android:persistent="false" />
 
     <!-- Dock speaker plays -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
             android:key="dock_audio_media"
             android:title="@string/dock_audio_media_title"
+            android:summary="%s"
             android:persistent="false" />
 
     <!-- Emergency tone -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
             android:key="emergency_tone"
             android:title="@string/emergency_tone_title"
+            android:summary="%s"
             android:persistent="false" />
 
 </PreferenceScreen>
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/res/xml/zen_mode_event_rule_settings.xml b/res/xml/zen_mode_event_rule_settings.xml
index 2519fc1..98e75ce 100644
--- a/res/xml/zen_mode_event_rule_settings.xml
+++ b/res/xml/zen_mode_event_rule_settings.xml
@@ -25,21 +25,24 @@
         android:persistent="false" />
 
     <!-- During events for -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
         android:key="calendar"
         android:title="@string/zen_mode_event_rule_calendar"
+        android:summary="%s"
         android:persistent="false" />
 
     <!-- Where reply is -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
         android:key="reply"
         android:title="@string/zen_mode_event_rule_reply"
+        android:summary="%s"
         android:persistent="false" />
 
     <!-- Zen mode -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
         android:key="zen_mode"
         android:title="@string/zen_mode_settings_title"
+        android:summary="%s"
         android:persistent="false" />
 
 </PreferenceScreen>
diff --git a/res/xml/zen_mode_external_rule_settings.xml b/res/xml/zen_mode_external_rule_settings.xml
index e244dc8..e3fafbd 100644
--- a/res/xml/zen_mode_external_rule_settings.xml
+++ b/res/xml/zen_mode_external_rule_settings.xml
@@ -37,8 +37,9 @@
         android:persistent="false" />
 
     <!-- Zen mode -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
         android:key="zen_mode"
+        android:summary="%s"
         android:title="@string/zen_mode_settings_title"
         android:persistent="false" />
 
diff --git a/res/xml/zen_mode_priority_settings.xml b/res/xml/zen_mode_priority_settings.xml
index 6e324ce..6d9f36f 100644
--- a/res/xml/zen_mode_priority_settings.xml
+++ b/res/xml/zen_mode_priority_settings.xml
@@ -40,15 +40,17 @@
         android:persistent="false"/>
 
     <!-- Messages -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
         android:key="messages"
         android:title="@string/zen_mode_messages"
+        android:summary="%s"
         android:persistent="false" />
 
     <!-- Calls -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
         android:key="calls"
         android:title="@string/zen_mode_calls"
+        android:summary="%s"
         android:persistent="false" />
 
     <!-- Repeat callers -->
diff --git a/res/xml/zen_mode_schedule_rule_settings.xml b/res/xml/zen_mode_schedule_rule_settings.xml
index d808b10..3c62b5b 100644
--- a/res/xml/zen_mode_schedule_rule_settings.xml
+++ b/res/xml/zen_mode_schedule_rule_settings.xml
@@ -33,10 +33,11 @@
     <!-- Start time/End time added and removed here! :-) -->
 
     <!-- Zen mode -->
-    <com.android.settings.DropDownPreference
+    <DropDownPreference
             android:key="zen_mode"
             android:title="@string/zen_mode_settings_title"
             android:order="100"
+            android:summary="%s"
             android:persistent="false" />
 
 </PreferenceScreen>
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/ApnEditor.java b/src/com/android/settings/ApnEditor.java
index e785abb..20fb9ea 100644
--- a/src/com/android/settings/ApnEditor.java
+++ b/src/com/android/settings/ApnEditor.java
@@ -203,10 +203,22 @@
         mFirstTime = icicle == null;
 
         if (action.equals(Intent.ACTION_EDIT)) {
-            mUri = intent.getData();
+            Uri uri = intent.getData();
+            if (!uri.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) {
+                Log.e(TAG, "Edit request not for carrier table. Uri: " + uri);
+                finish();
+                return;
+            }
+            mUri = uri;
         } else if (action.equals(Intent.ACTION_INSERT)) {
             if (mFirstTime || icicle.getInt(SAVED_POS) == 0) {
-                mUri = getContentResolver().insert(intent.getData(), new ContentValues());
+                Uri uri = intent.getData();
+                if (!uri.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) {
+                    Log.e(TAG, "Insert request not for carrier table. Uri: " + uri);
+                    finish();
+                    return;
+                }
+                mUri = getContentResolver().insert(uri, new ContentValues());
             } else {
                 mUri = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI,
                         icicle.getInt(SAVED_POS));
diff --git a/src/com/android/settings/BugreportPreference.java b/src/com/android/settings/BugreportPreference.java
index 24af284..fc0466f 100644
--- a/src/com/android/settings/BugreportPreference.java
+++ b/src/com/android/settings/BugreportPreference.java
@@ -37,7 +37,7 @@
     @Override
     protected void onClick(DialogInterface dialog, int which) {
         if (which == DialogInterface.BUTTON_POSITIVE) {
-            SystemProperties.set("ctl.start", "bugreport");
+            SystemProperties.set("ctl.start", "bugreportplus");
         }
     }
 }
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
index 65f0ba6..73f8c46 100644
--- a/src/com/android/settings/ChooseLockGeneric.java
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -220,13 +220,17 @@
                     && !dpm.getDoNotAskCredentialsOnBoot()) {
                 mEncryptionRequestQuality = quality;
                 mEncryptionRequestDisabled = disabled;
+                // Get the intent that the encryption interstitial should start for creating
+                // the new unlock method.
+                Intent unlockMethodIntent = getIntentForUnlockMethod(quality, disabled);
                 final Context context = getActivity();
                 // If accessibility is enabled and the user hasn't seen this dialog before, set the
                 // default state to agree with that which is compatible with accessibility
                 // (password not required).
                 final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
                 final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
-                Intent intent = getEncryptionInterstitialIntent(context, quality, required);
+                Intent intent = getEncryptionInterstitialIntent(context, quality, required,
+                        unlockMethodIntent);
                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
                         mForFingerprint);
                 startActivityForResult(intent, ENABLE_ENCRYPTION_REQUEST);
@@ -244,14 +248,12 @@
                 mPasswordConfirmed = true;
                 mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
                 updatePreferencesOrFinish();
-            } else if (requestCode == ENABLE_ENCRYPTION_REQUEST
-                    && resultCode == Activity.RESULT_OK) {
-                mRequirePassword = data.getBooleanExtra(
-                        EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
-                updateUnlockMethodAndFinish(mEncryptionRequestQuality, mEncryptionRequestDisabled);
-            } else if (requestCode == CHOOSE_LOCK_REQUEST) {
-                getActivity().setResult(resultCode, data);
-                finish();
+            } else if (requestCode == CHOOSE_LOCK_REQUEST
+                    || requestCode == ENABLE_ENCRYPTION_REQUEST) {
+                if (resultCode != RESULT_CANCELED) {
+                    getActivity().setResult(resultCode, data);
+                    finish();
+                }
             } else {
                 getActivity().setResult(Activity.RESULT_CANCELED);
                 finish();
@@ -451,8 +453,9 @@
         }
 
         protected Intent getEncryptionInterstitialIntent(Context context, int quality,
-                boolean required) {
-            return EncryptionInterstitial.createStartIntent(context, quality, required);
+                boolean required, Intent unlockMethodIntent) {
+            return EncryptionInterstitial.createStartIntent(context, quality, required,
+                    unlockMethodIntent);
         }
 
         /**
@@ -471,34 +474,13 @@
             }
 
             quality = upgradeQuality(quality);
+            Intent intent = getIntentForUnlockMethod(quality, disabled);
+            if (intent != null) {
+                startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
+                return;
+            }
 
-            final Context context = getActivity();
-            if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
-                int minLength = mDPM.getPasswordMinimumLength(null);
-                if (minLength < MIN_PASSWORD_LENGTH) {
-                    minLength = MIN_PASSWORD_LENGTH;
-                }
-                final int maxLength = mDPM.getPasswordMaximumLength(quality);
-                Intent intent;
-                if (mHasChallenge) {
-                    intent = getLockPasswordIntent(context, quality, minLength,
-                            maxLength, mRequirePassword, mChallenge, mUserId);
-                } else {
-                    intent = getLockPasswordIntent(context, quality, minLength,
-                        maxLength, mRequirePassword, mUserPassword, mUserId);
-                }
-                startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
-            } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
-                Intent intent;
-                if (mHasChallenge) {
-                    intent = getLockPatternIntent(context, mRequirePassword,
-                        mChallenge, mUserId);
-                } else {
-                    intent = getLockPatternIntent(context, mRequirePassword,
-                        mUserPassword, mUserId);
-                }
-                startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
-            } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+            if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
                 mChooseLockSettingsHelper.utils().clearLock(mUserId);
                 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
                 removeAllFingerprintTemplatesAndFinish();
@@ -508,6 +490,34 @@
             }
         }
 
+        private Intent getIntentForUnlockMethod(int quality, boolean disabled) {
+            Intent intent = null;
+            final Context context = getActivity();
+            if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
+                int minLength = mDPM.getPasswordMinimumLength(null);
+                if (minLength < MIN_PASSWORD_LENGTH) {
+                    minLength = MIN_PASSWORD_LENGTH;
+                }
+                final int maxLength = mDPM.getPasswordMaximumLength(quality);
+                if (mHasChallenge) {
+                    intent = getLockPasswordIntent(context, quality, minLength,
+                            maxLength, mRequirePassword, mChallenge, mUserId);
+                } else {
+                    intent = getLockPasswordIntent(context, quality, minLength,
+                            maxLength, mRequirePassword, mUserPassword, mUserId);
+                }
+            } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
+                if (mHasChallenge) {
+                    intent = getLockPatternIntent(context, mRequirePassword,
+                            mChallenge, mUserId);
+                } else {
+                    intent = getLockPatternIntent(context, mRequirePassword,
+                            mUserPassword, mUserId);
+                }
+            }
+            return intent;
+        }
+
         private void removeAllFingerprintTemplatesAndFinish() {
             if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()
                     && mFingerprintManager.getEnrolledFingerprints().size() > 0) {
diff --git a/src/com/android/settings/ChooseLockSettingsHelper.java b/src/com/android/settings/ChooseLockSettingsHelper.java
index 4c3fb7b..ab81455 100644
--- a/src/com/android/settings/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/ChooseLockSettingsHelper.java
@@ -21,6 +21,7 @@
 import android.app.Fragment;
 import android.app.admin.DevicePolicyManager;
 import android.content.Intent;
+import android.content.IntentSender;
 
 import com.android.internal.widget.LockPatternUtils;
 
@@ -114,6 +115,27 @@
 
     /**
      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
+     *
+     * @param title title of the confirmation screen; shown in the action bar
+     * @param header header of the confirmation screen; shown as large text
+     * @param description description of the confirmation screen
+     * @param returnCredentials if true, put credentials into intent. Note that if this is true,
+     *                          this can only be called internally.
+     * @param external specifies whether this activity is launched externally, meaning that it will
+     *                 get a dark theme and allow fingerprint authentication
+     * @param userId The userId for whom the lock should be confirmed.
+     * @return true if one exists and we launched an activity to confirm it
+     * @see Activity#onActivityResult(int, int, android.content.Intent)
+     */
+    boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
+            @Nullable CharSequence header, @Nullable CharSequence description,
+            boolean returnCredentials, boolean external, int userId) {
+        return launchConfirmationActivity(request, title, header, description,
+                returnCredentials, external, false, 0, Utils.getSameOwnerUserId(mActivity, userId));
+    }
+
+    /**
+     * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
      * @param message optional message to display about the action about to be done
      * @param details optional detail message to display
      * @param challenge a challenge to be verified against the device credential.
@@ -175,8 +197,18 @@
         if (external) {
             intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
             if (mFragment != null) {
+                IntentSender intentSender = mFragment.getActivity().getIntent()
+                        .getParcelableExtra(Intent.EXTRA_INTENT);
+                if (intentSender != null) {
+                    intent.putExtra(Intent.EXTRA_INTENT, intentSender);
+                }
                 mFragment.startActivity(intent);
             } else {
+                IntentSender intentSender = mActivity.getIntent()
+                        .getParcelableExtra(Intent.EXTRA_INTENT);
+                if (intentSender != null) {
+                    intent.putExtra(Intent.EXTRA_INTENT, intentSender);
+                }
                 mActivity.startActivity(intent);
             }
         } else {
diff --git a/src/com/android/settings/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/ConfirmDeviceCredentialActivity.java
index 86935c3..c4587eb 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialActivity.java
@@ -20,7 +20,11 @@
 import android.app.Activity;
 import android.app.KeyguardManager;
 import android.content.Intent;
+import android.os.Binder;
 import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Log;
 
 /**
@@ -30,6 +34,9 @@
 public class ConfirmDeviceCredentialActivity extends Activity {
     public static final String TAG = ConfirmDeviceCredentialActivity.class.getSimpleName();
 
+    public static class InternalActivity extends ConfirmDeviceCredentialActivity {
+    }
+
     public static Intent createIntent(CharSequence title, CharSequence details) {
         Intent intent = new Intent();
         intent.setClassName("com.android.settings",
@@ -57,13 +64,24 @@
         Intent intent = getIntent();
         String title = intent.getStringExtra(KeyguardManager.EXTRA_TITLE);
         String details = intent.getStringExtra(KeyguardManager.EXTRA_DESCRIPTION);
-
+        int userId = Utils.getEffectiveUserId(this);
+        if (isInternalActivity()) {
+            int givenUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, userId);
+            UserManager userManager = UserManager.get(this);
+            if (userManager.isSameProfileGroup(givenUserId, userId)) {
+                userId = givenUserId;
+            }
+        }
         ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this);
         if (!helper.launchConfirmationActivity(0 /* request code */, null /* title */, title,
-                details, false /* returnCredentials */, true /* isExternal */)) {
+                details, false /* returnCredentials */, true /* isExternal */, userId)) {
             Log.d(TAG, "No pattern, password or PIN set.");
             setResult(Activity.RESULT_OK);
         }
         finish();
     }
+
+    private boolean isInternalActivity() {
+        return this instanceof ConfirmDeviceCredentialActivity.InternalActivity;
+    }
 }
diff --git a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
index 32ad317..e04f86f 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.os.Bundle;
 import android.view.View;
 import android.widget.Button;
@@ -124,4 +125,16 @@
 
     public void startEnterAnimation() {
     }
+
+    protected void checkForPendingIntent() {
+        IntentSender intentSender = getActivity().getIntent()
+                .getParcelableExtra(Intent.EXTRA_INTENT);
+        if (intentSender != null) {
+            try {
+                getActivity().startIntentSenderForResult(intentSender, -1, null, 0, 0, 0);
+            } catch (IntentSender.SendIntentException e) {
+                /* ignore */
+            }
+        }
+    }
 }
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
index 7ef6a57..53555e0 100644
--- a/src/com/android/settings/ConfirmLockPassword.java
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -20,6 +20,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.CountDownTimer;
@@ -405,6 +406,7 @@
             mPasswordEntryInputDisabler.setInputEnabled(true);
             if (matched) {
                 startDisappearAnimation(intent);
+                checkForPendingIntent();
             } else {
                 if (timeoutMs > 0) {
                     long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java
index 44e74c9..6331290 100644
--- a/src/com/android/settings/ConfirmLockPattern.java
+++ b/src/com/android/settings/ConfirmLockPattern.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.CountDownTimer;
@@ -473,6 +474,7 @@
             mLockPatternView.setEnabled(true);
             if (matched) {
                 startDisappearAnimation(intent);
+                checkForPendingIntent();
             } else {
                 if (timeoutMs > 0) {
                     long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 1b37066..594cd38 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -799,6 +799,8 @@
         // Asynchronously throw up the IME, since there are issues with requesting it to be shown
         // immediately.
         if (mLockPatternView == null && !mCooldown) {
+            getWindow().setSoftInputMode(
+                                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
             mHandler.postDelayed(new Runnable() {
                 @Override public void run() {
                     imm.showSoftInputUnchecked(0, null);
diff --git a/src/com/android/settings/CustomListPreference.java b/src/com/android/settings/CustomListPreference.java
index 1d49165..ce37c14 100644
--- a/src/com/android/settings/CustomListPreference.java
+++ b/src/com/android/settings/CustomListPreference.java
@@ -44,6 +44,8 @@
 
     public static class CustomListPreferenceDialogFragment extends ListPreferenceDialogFragment {
 
+        private int mClickedDialogEntryIndex;
+
         public static ListPreferenceDialogFragment newInstance(String key) {
             final ListPreferenceDialogFragment fragment = new CustomListPreferenceDialogFragment();
             final Bundle b = new Bundle(1);
@@ -59,12 +61,35 @@
         @Override
         protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
             super.onPrepareDialogBuilder(builder);
-            getCustomizablePreference().onPrepareDialogBuilder(builder, this);
+            mClickedDialogEntryIndex = getCustomizablePreference()
+                    .findIndexOfValue(getCustomizablePreference().getValue());
+            getCustomizablePreference().onPrepareDialogBuilder(builder,
+                new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        mClickedDialogEntryIndex = which;
+
+                        /*
+                         * Clicking on an item simulates the positive button
+                         * click, and dismisses the dialog.
+                         */
+                        CustomListPreferenceDialogFragment.this.onClick(dialog,
+                                DialogInterface.BUTTON_POSITIVE);
+                        dialog.dismiss();
+                    }
+                });
         }
 
         @Override
         public void onDialogClosed(boolean positiveResult) {
             getCustomizablePreference().onDialogClosed(positiveResult);
+            final ListPreference preference = getCustomizablePreference();
+            if (positiveResult && mClickedDialogEntryIndex >= 0 &&
+                    preference.getEntryValues() != null) {
+                String value = preference.getEntryValues()[mClickedDialogEntryIndex].toString();
+                if (preference.callChangeListener(value)) {
+                    preference.setValue(value);
+                }
+            }
         }
     }
 }
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index 950af3c..c6f57ec 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -59,6 +59,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.ListPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
@@ -72,6 +73,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
+import android.webkit.IWebViewUpdateService;
+import android.webkit.WebViewProviderInfo;
 import android.widget.Switch;
 import android.widget.TextView;
 
@@ -110,6 +113,7 @@
     private static final String ENABLE_TERMINAL = "enable_terminal";
     private static final String KEEP_SCREEN_ON = "keep_screen_on";
     private static final String BT_HCI_SNOOP_LOG = "bt_hci_snoop_log";
+    private static final String WEBVIEW_PROVIDER_KEY = "select_webview_provider";
     private static final String ENABLE_OEM_UNLOCK = "oem_unlock_enable";
     private static final String HDCP_CHECKING_KEY = "hdcp_checking";
     private static final String HDCP_CHECKING_PROPERTY = "persist.sys.hdcp_checking";
@@ -253,6 +257,7 @@
     private ListPreference mAnimatorDurationScale;
     private ListPreference mOverlayDisplayDevices;
     private ListPreference mOpenGLTraces;
+    private ListPreference mWebViewProvider;
 
     private ListPreference mSimulateColorSpace;
 
@@ -389,6 +394,7 @@
         mMobileDataAlwaysOn = findAndInitSwitchPref(MOBILE_DATA_ALWAYS_ON);
         mLogdSize = addListPreference(SELECT_LOGD_SIZE_KEY);
         mUsbConfiguration = addListPreference(USB_CONFIGURATION_KEY);
+        mWebViewProvider = addListPreference(WEBVIEW_PROVIDER_KEY);
 
         mWindowAnimationScale = addListPreference(WINDOW_ANIMATION_SCALE_KEY);
         mTransitionAnimationScale = addListPreference(TRANSITION_ANIMATION_SCALE_KEY);
@@ -461,6 +467,7 @@
             removePreference(KEY_COLOR_MODE);
             mColorModePreference = null;
         }
+        updateWebViewProviderOptions();
     }
 
     private ListPreference addListPreference(String prefKey) {
@@ -669,6 +676,7 @@
         updateSimulateColorSpace();
         updateUSBAudioOptions();
         updateForceResizableOptions();
+        updateWebViewProviderOptions();
     }
 
     private void resetDangerousOptions() {
@@ -697,6 +705,35 @@
         pokeSystemProperties();
     }
 
+    private void updateWebViewProviderOptions() {
+        IWebViewUpdateService webViewUpdateService  =
+            IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
+        try {
+            WebViewProviderInfo[] providers = webViewUpdateService.getValidWebViewPackages();
+            String[] options = new String[providers.length];
+            String[] values = new String[providers.length];
+            for(int n = 0; n < providers.length; n++) {
+                options[n] = providers[n].description;
+                values[n] = providers[n].packageName;
+            }
+            mWebViewProvider.setEntries(options);
+            mWebViewProvider.setEntryValues(values);
+
+            String value = webViewUpdateService.getCurrentWebViewPackageName();
+            if (value == null) {
+                value = "";
+            }
+
+            for (int i = 0; i < values.length; i++) {
+                if (value.contentEquals(values[i])) {
+                    mWebViewProvider.setValueIndex(i);
+                    return;
+                }
+            }
+        } catch(RemoteException e) {
+        }
+    }
+
     private void updateHdcpValues() {
         ListPreference hdcpChecking = (ListPreference) findPreference(HDCP_CHECKING_KEY);
         if (hdcpChecking != null) {
@@ -736,6 +773,18 @@
                 mBtHciSnoopLog.isChecked() ? 1 : 0);
     }
 
+    private void writeWebViewProviderOptions(Object newValue) {
+        IWebViewUpdateService webViewUpdateService  =
+            IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
+
+        try {
+            webViewUpdateService.changeProviderAndSetting(
+                    newValue == null ? "" : newValue.toString());
+            updateWebViewProviderOptions();
+        } catch(RemoteException e) {
+        }
+    }
+
     private void writeDebuggerOptions() {
         try {
             ActivityManagerNative.getDefault().setDebugApp(
@@ -1754,6 +1803,9 @@
             updateHdcpValues();
             pokeSystemProperties();
             return true;
+        } else if (preference == mWebViewProvider) {
+            writeWebViewProviderOptions(newValue);
+            return true;
         } else if (preference == mLogdSize) {
             writeLogdSizeOption(newValue);
             return true;
diff --git a/src/com/android/settings/DisplayDensityPreference.java b/src/com/android/settings/DisplayDensityPreference.java
deleted file mode 100644
index 85f2fb2..0000000
--- a/src/com/android/settings/DisplayDensityPreference.java
+++ /dev/null
@@ -1,247 +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.Resources;
-import android.os.AsyncTask;
-import android.os.RemoteException;
-import android.support.annotation.ArrayRes;
-import android.support.v7.preference.ListPreference;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.MathUtils;
-import android.view.Display;
-import android.view.IWindowManager;
-import android.view.WindowManagerGlobal;
-
-import com.android.settings.R;
-
-import java.util.Arrays;
-
-/**
- * Preference for changing the density of the display on which the preference
- * is visible.
- */
-public class DisplayDensityPreference extends ListPreference {
-    private static final String LOG_TAG = "DisplayDensityPreference";
-
-    /** Minimum increment between density scales. */
-    private static final float MIN_SCALE_INTERVAL = 0.09f;
-
-    /** Minimum density scale. This is available on all devices. */
-    private static final float MIN_SCALE = 0.85f;
-
-    /** Maximum density scale. The actual scale used depends on the device. */
-    private static final float MAX_SCALE = 1.50f;
-
-    /** Sentinel value for "normal" scaling (effectively disabled). */
-    private static final int DENSITY_VALUE_NORMAL = -1;
-
-    /** Summary used for "normal" scale. */
-    private static final int DENSITY_SUMMARY_NORMAL = R.string.force_density_summary_normal;
-
-    /**
-     * Summaries for scales smaller than "normal" in order of smallest to
-     * largest.
-     */
-    private static final int[] SMALLER_SUMMARIES = new int[] {
-            R.string.force_density_summary_small
-    };
-
-    /**
-     * Summaries for scales larger than "normal" in order of smallest to
-     * largest.
-     */
-    private static final int[] LARGER_SUMMARIES = new int[] {
-            R.string.force_density_summary_large,
-            R.string.force_density_summary_very_large,
-            R.string.force_density_summary_extremely_large,
-    };
-
-    /**
-     * Minimum allowed screen dimension, corresponds to resource qualifiers
-     * "small" or "sw320dp". This value must be at least the minimum screen
-     * size required by the CDD so that we meet developer expectations.
-     */
-    private static final int MIN_DIMENSION_DP = 320;
-
-    /** The ID of the display affected by this preference. */
-    private int mDisplayId = Display.DEFAULT_DISPLAY;
-
-    public DisplayDensityPreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        if (!prepareList()) {
-            setEnabled(false);
-        }
-    }
-
-    private boolean prepareList() {
-        final int initialDensity = getInitialDisplayDensity(mDisplayId);
-        if (initialDensity <= 0) {
-            return false;
-        }
-
-        final Resources res = getContext().getResources();
-        final DisplayMetrics metrics = res.getDisplayMetrics();
-        final int currentDensity = metrics.densityDpi;
-        int currentDensityIndex = -1;
-
-        // Compute number of "larger" and "smaller" scales for this display.
-        final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
-        final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
-        final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) initialDensity);
-        final float minScale = MIN_SCALE;
-        final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
-                0, LARGER_SUMMARIES.length);
-        final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
-                0, SMALLER_SUMMARIES.length);
-
-        CharSequence[] values = new CharSequence[1 + numSmaller + numLarger];
-        CharSequence[] entries = new CharSequence[values.length];
-        int curIndex = 0;
-
-        if (numSmaller > 0) {
-            final float interval = (1 - minScale) / numSmaller;
-            for (int i = numSmaller - 1; i >= 0; i--) {
-                final int density = (int) (initialDensity * (1 - (i + 1) * interval));
-                if (currentDensity == density) {
-                    currentDensityIndex = curIndex;
-                }
-                values[curIndex] = Integer.toString(density);
-                entries[curIndex] = res.getText(SMALLER_SUMMARIES[i]);
-                curIndex++;
-            }
-        }
-
-        if (currentDensity == initialDensity) {
-            currentDensityIndex = curIndex;
-        }
-        values[curIndex] = Integer.toString(DENSITY_VALUE_NORMAL);
-        entries[curIndex] = res.getText(DENSITY_SUMMARY_NORMAL);
-        curIndex++;
-
-        if (numLarger > 0) {
-            final float interval = (maxScale - 1) / numLarger;
-            for (int i = 0; i < numLarger; i++) {
-                final int density = (int) (initialDensity * (1 + (i + 1) * interval));
-                if (currentDensity == density) {
-                    currentDensityIndex = curIndex;
-                }
-                values[curIndex] = Integer.toString(density);
-                entries[curIndex] = res.getText(LARGER_SUMMARIES[i]);
-                curIndex++;
-            }
-        }
-
-        final int displayIndex;
-        if (currentDensityIndex >= 0) {
-            displayIndex = currentDensityIndex;
-        } else {
-            // We don't understand the current density. Must have been set by
-            // someone else. Make room for another entry...
-            values = Arrays.copyOf(values, values.length + 1);
-            values[curIndex] = res.getString(R.string.force_density_summary_custom, currentDensity);
-
-            entries = Arrays.copyOf(entries, values.length + 1);
-            entries[curIndex] = Integer.toString(currentDensity);
-
-            displayIndex = curIndex;
-        }
-
-        super.setEntryValues(values);
-        super.setEntries(entries);
-
-        setValueIndex(displayIndex);
-
-        return true;
-    }
-
-    @Override
-    public boolean callChangeListener(Object newValue) {
-        final boolean allowed = super.callChangeListener(newValue);
-        if (allowed) {
-            final int density = Integer.parseInt((String) newValue);
-            setForcedDisplayDensity(mDisplayId, density);
-        }
-
-        return allowed;
-    }
-
-    @Override
-    public void setEntries(CharSequence[] entries) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setEntries(@ArrayRes int entriesResId) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setEntryValues(CharSequence[] entryValues) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setEntryValues(@ArrayRes int entryValuesResId) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Returns the initial density for the specified display.
-     *
-     * @param displayId the identifier of the display
-     * @return the initial density of the specified display, or {@code -1} if
-     *         the display does not exist or the density could not be obtained
-     */
-    private static int getInitialDisplayDensity(int displayId) {
-        try {
-            IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
-            return wm.getInitialDisplayDensity(displayId);
-        } catch (RemoteException exc) {
-            return -1;
-        }
-    }
-
-    /**
-     * Asynchronously applies display density changes to the specified display.
-     *
-     * @param displayId the identifier of the display to modify
-     * @param density the density to force for the specified display, or <= 0
-     *                to clear any previously forced density
-     */
-    private static void setForcedDisplayDensity(final int displayId, final int density) {
-        AsyncTask.execute(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
-                    if (density <= 0) {
-                        wm.clearForcedDisplayDensity(displayId);
-                    } else {
-                        wm.setForcedDisplayDensity(displayId, density);
-                    }
-                } catch (RemoteException exc) {
-                    Log.w(LOG_TAG, "Unable to save forced display density setting");
-                }
-            }
-        });
-    }
-}
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index 0d52aa7..6d99a35 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -33,11 +33,13 @@
 import android.provider.SearchIndexableResource;
 import android.provider.Settings;
 import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.ListPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.text.TextUtils;
 import android.util.Log;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.view.RotationPolicy;
 import com.android.settings.dashboard.SummaryLoader;
@@ -76,7 +78,6 @@
     private static final String KEY_CAMERA_GESTURE = "camera_gesture";
     private static final String KEY_CAMERA_DOUBLE_TAP_POWER_GESTURE
             = "camera_double_tap_power_gesture";
-    private static final String KEY_DISPLAY_DENSITY = "display_density";
 
     private DropDownPreference mFontSizePref;
 
@@ -214,9 +215,6 @@
             mNightModePreference.setValue(String.valueOf(currentNightMode));
             mNightModePreference.setOnPreferenceChangeListener(this);
         }
-
-        final Preference displayDensity = findPreference(KEY_DISPLAY_DENSITY);
-        displayDensity.setOnPreferenceChangeListener(this);
     }
 
     private static boolean allowAllRotations(Context context) {
diff --git a/src/com/android/settings/DropDownPreference.java b/src/com/android/settings/DropDownPreference.java
deleted file mode 100644
index 3088497..0000000
--- a/src/com/android/settings/DropDownPreference.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import android.content.Context;
-import android.support.v7.preference.ListPreference;
-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;
-
-public class DropDownPreference extends ListPreference {
-
-    private final Context mContext;
-    private final ArrayAdapter<String> mAdapter;
-    private final Spinner mSpinner;
-
-    public DropDownPreference(Context context) {
-        this(context, null);
-    }
-
-    public DropDownPreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mContext = context;
-        mAdapter = new ArrayAdapter<String>(mContext,
-                android.R.layout.simple_spinner_dropdown_item);
-
-        mSpinner = new Spinner(mContext);
-
-        mSpinner.setVisibility(View.INVISIBLE);
-        mSpinner.setAdapter(mAdapter);
-        mSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
-            @Override
-            public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
-                if (position >= 0) {
-                    String value = getEntryValues()[position].toString();
-                    if (!value.equals(getValue()) && callChangeListener(value)) {
-                        setValue(value);
-                    }
-                }
-            }
-
-            @Override
-            public void onNothingSelected(AdapterView<?> parent) {
-                // noop
-            }
-        });
-        setPersistent(false);
-        updateEntries();
-    }
-
-    @Override
-    protected void onClick() {
-        mSpinner.performClick();
-    }
-
-    public void setDropDownWidth(int dimenResId) {
-        mSpinner.setDropDownWidth(mContext.getResources().getDimensionPixelSize(dimenResId));
-    }
-
-    @Override
-    public void setEntries(CharSequence[] entries) {
-        super.setEntries(entries);
-        updateEntries();
-    }
-
-    private void updateEntries() {
-        mAdapter.clear();
-        if (getEntries() != null) {
-            for (CharSequence c : getEntries()) {
-                mAdapter.add(c.toString());
-            }
-        }
-    }
-
-    @Override
-    public void setValue(String value) {
-        super.setValue(value);
-        mSpinner.setSelection(findIndexOfValue(getValue()));
-        setSummary(getEntry());
-    }
-
-    public void setValueIndex(int index) {
-        setValue(getEntryValues()[index].toString());
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder view) {
-        super.onBindViewHolder(view);
-        if (view.equals(mSpinner.getParent())) return;
-        if (mSpinner.getParent() != null) {
-            ((ViewGroup) mSpinner.getParent()).removeView(mSpinner);
-        }
-        final ViewGroup vg = (ViewGroup) view.itemView;
-        vg.addView(mSpinner, 0);
-        final ViewGroup.LayoutParams lp = mSpinner.getLayoutParams();
-        lp.width = 0;
-        mSpinner.setLayoutParams(lp);
-    }
-}
diff --git a/src/com/android/settings/EncryptionInterstitial.java b/src/com/android/settings/EncryptionInterstitial.java
index 3aec03e..be75c87 100644
--- a/src/com/android/settings/EncryptionInterstitial.java
+++ b/src/com/android/settings/EncryptionInterstitial.java
@@ -26,10 +26,12 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.Button;
 import android.widget.RadioButton;
 import android.widget.TextView;
 
@@ -39,9 +41,12 @@
 import java.util.List;
 
 public class EncryptionInterstitial extends SettingsActivity {
+    private final static String TAG = EncryptionInterstitial.class.getSimpleName();
 
     protected static final String EXTRA_PASSWORD_QUALITY = "extra_password_quality";
+    protected static final String EXTRA_UNLOCK_METHOD_INTENT = "extra_unlock_method_intent";
     public static final String EXTRA_REQUIRE_PASSWORD = "extra_require_password";
+    private static final int CHOOSE_LOCK_REQUEST = 100;
 
     @Override
     public Intent getIntent() {
@@ -56,7 +61,7 @@
     }
 
     public static Intent createStartIntent(Context ctx, int quality,
-            boolean requirePasswordDefault) {
+            boolean requirePasswordDefault, Intent unlockMethodIntent) {
         return new Intent(ctx, EncryptionInterstitial.class)
                 .putExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, true)
                 .putExtra(EXTRA_PREFS_SET_BACK_TEXT, (String) null)
@@ -64,7 +69,8 @@
                         R.string.encryption_continue_button))
                 .putExtra(EXTRA_PASSWORD_QUALITY, quality)
                 .putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.encryption_interstitial_header)
-                .putExtra(EXTRA_REQUIRE_PASSWORD, requirePasswordDefault);
+                .putExtra(EXTRA_REQUIRE_PASSWORD, requirePasswordDefault)
+                .putExtra(EXTRA_UNLOCK_METHOD_INTENT, unlockMethodIntent);
     }
 
     public static class EncryptionInterstitialFragment extends SettingsPreferenceFragment
@@ -75,6 +81,7 @@
         private RadioButton mDontRequirePasswordToDecryptButton;
         private TextView mEncryptionMessage;
         private boolean mPasswordRequired;
+        private Intent mUnlockMethodIntent;
 
         @Override
         protected int getMetricsCategory() {
@@ -98,7 +105,9 @@
                     (TextView) view.findViewById(R.id.encryption_message);
             boolean forFingerprint = getActivity().getIntent().getBooleanExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
-            int quality = getActivity().getIntent().getIntExtra(EXTRA_PASSWORD_QUALITY, 0);
+            Intent intent = getActivity().getIntent();
+            final int quality = intent.getIntExtra(EXTRA_PASSWORD_QUALITY, 0);
+            mUnlockMethodIntent = (Intent) intent.getParcelableExtra(EXTRA_UNLOCK_METHOD_INTENT);
             final int msgId;
             final int enableId;
             final int disableId;
@@ -136,6 +145,35 @@
 
             setRequirePasswordState(getActivity().getIntent().getBooleanExtra(
                     EXTRA_REQUIRE_PASSWORD, true));
+
+            Button nextButton = getNextButton();
+            if (nextButton != null) {
+                nextButton.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        startLockIntent();
+                    }
+                });
+            }
+        }
+
+        protected void startLockIntent() {
+            if (mUnlockMethodIntent != null) {
+                mUnlockMethodIntent.putExtra(EXTRA_REQUIRE_PASSWORD, mPasswordRequired);
+                startActivityForResult(mUnlockMethodIntent, CHOOSE_LOCK_REQUEST);
+            } else {
+                Log.wtf(TAG, "no unlock intent to start");
+                finish();
+            }
+        }
+
+        @Override
+        public void onActivityResult(int requestCode, int resultCode, Intent data) {
+            super.onActivityResult(requestCode, resultCode, data);
+            if (requestCode == CHOOSE_LOCK_REQUEST && resultCode != RESULT_CANCELED) {
+                getActivity().setResult(resultCode, data);
+                finish();
+            }
         }
 
         @Override
@@ -206,15 +244,6 @@
             mPasswordRequired = required;
             mRequirePasswordToDecryptButton.setChecked(required);
             mDontRequirePasswordToDecryptButton.setChecked(!required);
-
-            // Updates value returned by SettingsActivity.onActivityResult().
-            SettingsActivity sa = (SettingsActivity)getActivity();
-            Intent resultIntentData = sa.getResultIntentData();
-            if (resultIntentData == null) {
-                resultIntentData = new Intent();
-                sa.setResultIntentData(resultIntentData);
-            }
-            resultIntentData.putExtra(EXTRA_REQUIRE_PASSWORD, mPasswordRequired);
         }
 
         @Override
diff --git a/src/com/android/settings/InstrumentedFragment.java b/src/com/android/settings/InstrumentedFragment.java
index 44fd110..cc0014d 100644
--- a/src/com/android/settings/InstrumentedFragment.java
+++ b/src/com/android/settings/InstrumentedFragment.java
@@ -32,6 +32,7 @@
     public static final int SOUND = UNDECLARED + 2;
     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;
 
     /**
      * Declare the view of this category.
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/SetupChooseLockGeneric.java b/src/com/android/settings/SetupChooseLockGeneric.java
index 0b0333b..9559f8d 100644
--- a/src/com/android/settings/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/SetupChooseLockGeneric.java
@@ -170,9 +170,9 @@
 
         @Override
         protected Intent getEncryptionInterstitialIntent(Context context, int quality,
-                boolean required) {
+                boolean required, Intent unlockMethodIntent) {
             Intent intent = SetupEncryptionInterstitial.createStartIntent(context, quality,
-                    required);
+                    required, unlockMethodIntent);
             SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
             return intent;
         }
diff --git a/src/com/android/settings/SetupEncryptionInterstitial.java b/src/com/android/settings/SetupEncryptionInterstitial.java
index cd943af..8d061ec 100644
--- a/src/com/android/settings/SetupEncryptionInterstitial.java
+++ b/src/com/android/settings/SetupEncryptionInterstitial.java
@@ -38,9 +38,9 @@
 public class SetupEncryptionInterstitial extends EncryptionInterstitial {
 
     public static Intent createStartIntent(Context ctx, int quality,
-            boolean requirePasswordDefault) {
+            boolean requirePasswordDefault, Intent unlockMethodIntent) {
         Intent startIntent = EncryptionInterstitial.createStartIntent(ctx, quality,
-                requirePasswordDefault);
+                requirePasswordDefault, unlockMethodIntent);
         startIntent.setClass(ctx, SetupEncryptionInterstitial.class);
         startIntent.putExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)
                 .putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, -1);
@@ -102,12 +102,7 @@
 
         @Override
         public void onNavigateNext() {
-            final SetupEncryptionInterstitial activity =
-                    (SetupEncryptionInterstitial) getActivity();
-            if (activity != null) {
-                activity.setResult(RESULT_OK, activity.getResultIntentData());
-                finish();
-            }
+            startLockIntent();
         }
     }
 }
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/Utils.java b/src/com/android/settings/Utils.java
index 5a54ba4..ddea92b 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -74,6 +74,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -83,8 +84,6 @@
 import android.widget.ListView;
 import android.widget.TabWidget;
 import com.android.internal.util.UserIcons;
-import com.android.settingslib.drawer.UserAdapter;
-import com.android.settingslib.drawer.UserAdapter.UserDetails;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -1058,5 +1057,11 @@
             return UserHandle.myUserId();
         }
     }
+
+    public static int resolveResource(Context context, int attr) {
+        TypedValue value = new TypedValue();
+        context.getTheme().resolveAttribute(attr, value, true);
+        return value.resourceId;
+    }
 }
 
diff --git a/src/com/android/settings/applications/AppLaunchSettings.java b/src/com/android/settings/applications/AppLaunchSettings.java
index cbac4a1..ae711f7 100644
--- a/src/com/android/settings/applications/AppLaunchSettings.java
+++ b/src/com/android/settings/applications/AppLaunchSettings.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.util.ArraySet;
@@ -34,7 +35,6 @@
 import android.view.View.OnClickListener;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.settings.DropDownPreference;
 import com.android.settings.R;
 import com.android.settings.Utils;
 
diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java
index 6228bbc..3e0b9dd 100644
--- a/src/com/android/settings/dashboard/DashboardAdapter.java
+++ b/src/com/android/settings/dashboard/DashboardAdapter.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
-import android.util.Log;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -26,40 +25,52 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 import com.android.internal.util.ArrayUtils;
+import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.dashboard.conditional.Condition;
+import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.DashboardTile;
 
 import java.util.ArrayList;
 import java.util.List;
 
-public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.DashboardItemHolder> {
+public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.DashboardItemHolder> implements View.OnClickListener {
     public static final String TAG = "DashboardAdapter";
 
     private final List<Object> mItems = new ArrayList<>();
     private final List<Integer> mTypes = new ArrayList<>();
     private final List<Integer> mIds = new ArrayList<>();
 
-    private final List<DashboardCategory> mCategories;
     private final Context mContext;
 
+    private List<DashboardCategory> mCategories;
+    private List<Condition> mConditions;
+
     private boolean mIsShowingAll;
     // Used for counting items;
     private int mId;
 
-    public DashboardAdapter(Context context, List<DashboardCategory> categories) {
+    private Condition mExpandedCondition = null;
+
+    public DashboardAdapter(Context context) {
         mContext = context;
+
+        setHasStableIds(true);
+    }
+
+    public void setCategories(List<DashboardCategory> categories) {
         mCategories = categories;
 
         // TODO: Better place for tinting?
         TypedValue tintColor = new TypedValue();
-        context.getTheme().resolveAttribute(com.android.internal.R.attr.colorAccent,
+        mContext.getTheme().resolveAttribute(com.android.internal.R.attr.colorAccent,
                 tintColor, true);
         for (int i = 0; i < categories.size(); i++) {
             for (int j = 0; j < categories.get(i).tiles.size(); j++) {
                 DashboardTile tile = categories.get(i).tiles.get(j);
 
-                if (!context.getPackageName().equals(
+                if (!mContext.getPackageName().equals(
                         tile.intent.getComponent().getPackageName())) {
                     // If this drawable is coming from outside Settings, tint it to match the
                     // color.
@@ -67,9 +78,12 @@
                 }
             }
         }
+        setShowingAll(mIsShowingAll);
+    }
 
-        setShowingAll(false);
-        setHasStableIds(true);
+    public void setConditions(List<Condition> conditions) {
+        mConditions = conditions;
+        setShowingAll(mIsShowingAll);
     }
 
     public boolean isShowingAll() {
@@ -88,19 +102,21 @@
     public void setShowingAll(boolean showingAll) {
         mIsShowingAll = showingAll;
         reset();
-        countItem(null, com.android.settings.R.layout.dashboard_spacer, true);
-        for (int i = 0; i < mCategories.size(); i++) {
+        for (int i = 0; mConditions != null && i < mConditions.size(); i++) {
+            countItem(mConditions.get(i), R.layout.condition_card, mConditions.get(i).shouldShow());
+        }
+        countItem(null, R.layout.dashboard_spacer, true);
+        for (int i = 0; mCategories != null && i < mCategories.size(); i++) {
             DashboardCategory category = mCategories.get(i);
-            countItem(category, com.android.settings.R.layout.dashboard_category, mIsShowingAll);
+            countItem(category, R.layout.dashboard_category, mIsShowingAll);
             for (int j = 0; j < category.tiles.size(); j++) {
                 DashboardTile tile = category.tiles.get(j);
-                Log.d(TAG, "Maybe adding " + tile.intent.getComponent().getClassName());
-                countItem(tile, com.android.settings.R.layout.dashboard_tile, mIsShowingAll
+                countItem(tile, R.layout.dashboard_tile, mIsShowingAll
                         || ArrayUtils.contains(DashboardSummary.INITIAL_ITEMS,
                         tile.intent.getComponent().getClassName()));
             }
         }
-        countItem(null, com.android.settings.R.layout.see_all, true);
+        countItem(null, R.layout.see_all, true);
         notifyDataSetChanged();
     }
 
@@ -129,10 +145,10 @@
     @Override
     public void onBindViewHolder(DashboardItemHolder holder, int position) {
         switch (mTypes.get(position)) {
-            case com.android.settings.R.layout.dashboard_category:
+            case R.layout.dashboard_category:
                 onBindCategory(holder, (DashboardCategory) mItems.get(position));
                 break;
-            case com.android.settings.R.layout.dashboard_tile:
+            case R.layout.dashboard_tile:
                 final DashboardTile tile = (DashboardTile) mItems.get(position);
                 onBindTile(holder, tile);
                 holder.itemView.setOnClickListener(new View.OnClickListener() {
@@ -142,7 +158,7 @@
                     }
                 });
                 break;
-            case com.android.settings.R.layout.see_all:
+            case R.layout.see_all:
                 onBindSeeAll(holder);
                 holder.itemView.setOnClickListener(new View.OnClickListener() {
                     @Override
@@ -151,6 +167,16 @@
                     }
                 });
                 break;
+            case R.layout.condition_card:
+                ConditionAdapterUtils.bindViews((Condition) mItems.get(position), holder,
+                        mItems.get(position) == mExpandedCondition, this,
+                        new View.OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+                                onExpandClick(v);
+                            }
+                        });
+                break;
         }
     }
 
@@ -170,8 +196,8 @@
     }
 
     private void onBindSeeAll(DashboardItemHolder holder) {
-        holder.title.setText(mIsShowingAll ? com.android.settings.R.string.see_less
-                : com.android.settings.R.string.see_all);
+        holder.title.setText(mIsShowingAll ? R.string.see_less
+                : R.string.see_all);
     }
 
     @Override
@@ -189,10 +215,38 @@
         return mIds.size();
     }
 
+    @Override
+    public void onClick(View v) {
+        if (v.getTag() == mExpandedCondition) {
+            mExpandedCondition.onPrimaryClick();
+        } else {
+            mExpandedCondition = (Condition) v.getTag();
+            notifyDataSetChanged();
+        }
+    }
+
+    public void onExpandClick(View v) {
+        if (v.getTag() == mExpandedCondition) {
+            mExpandedCondition = null;
+        } else {
+            mExpandedCondition = (Condition) v.getTag();
+        }
+        notifyDataSetChanged();
+    }
+
+    public Object getItem(long itemId) {
+        for (int i = 0; i < mIds.size(); i++) {
+            if (mIds.get(i) == itemId) {
+                return mItems.get(i);
+            }
+        }
+        return null;
+    }
+
     public static class DashboardItemHolder extends RecyclerView.ViewHolder {
-        private final ImageView icon;
-        private final TextView title;
-        private final TextView summary;
+        public final ImageView icon;
+        public final TextView title;
+        public final TextView summary;
 
         public DashboardItemHolder(View itemView) {
             super(itemView);
diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java
index 64eb356..95170a4 100644
--- a/src/com/android/settings/dashboard/DashboardSummary.java
+++ b/src/com/android/settings/dashboard/DashboardSummary.java
@@ -18,7 +18,6 @@
 
 import android.os.Bundle;
 import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -31,13 +30,17 @@
 import com.android.settings.R;
 import com.android.settings.Settings;
 import com.android.settings.SettingsActivity;
+import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
+import com.android.settings.dashboard.conditional.ConditionManager;
+import com.android.settings.dashboard.conditional.FocusRecyclerView;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.SettingsDrawerActivity;
 
 import java.util.List;
 
 public class DashboardSummary extends InstrumentedFragment
-        implements SettingsDrawerActivity.CategoryListener {
+        implements SettingsDrawerActivity.CategoryListener, ConditionManager.ConditionListener,
+        FocusRecyclerView.FocusListener {
     public static final boolean DEBUG = false;
     private static final boolean DEBUG_TIMING = false;
     private static final String TAG = "DashboardSummary";
@@ -51,11 +54,10 @@
             Settings.StorageSettingsActivity.class.getName(),
     };
 
-    private static final int MSG_REBUILD_UI = 1;
-
-    private RecyclerView mDashboard;
+    private FocusRecyclerView mDashboard;
     private DashboardAdapter mAdapter;
     private SummaryLoader mSummaryLoader;
+    private ConditionManager mConditionManager;
 
     @Override
     protected int getMetricsCategory() {
@@ -73,6 +75,7 @@
         setHasOptionsMenu(true);
         if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
                 + " ms");
+        mConditionManager = ConditionManager.get(getContext());
     }
 
     @Override
@@ -95,6 +98,7 @@
 
         ((SettingsDrawerActivity) getActivity()).addCategoryListener(this);
         mSummaryLoader.setListening(true);
+        Log.d(TAG, "onResume");
     }
 
     @Override
@@ -106,6 +110,16 @@
     }
 
     @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        if (hasWindowFocus) {
+            mConditionManager.addListener(this);
+            mConditionManager.refreshAll();
+        } else {
+            mConditionManager.remListener(this);
+        }
+    }
+
+    @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
         return inflater.inflate(R.layout.dashboard, container, false);
@@ -113,11 +127,16 @@
 
     @Override
     public void onViewCreated(View view, Bundle bundle) {
-        mDashboard = (RecyclerView) view.findViewById(R.id.dashboard_container);
+        mDashboard = (FocusRecyclerView) view.findViewById(R.id.dashboard_container);
         LinearLayoutManager llm = new LinearLayoutManager(getContext());
         llm.setOrientation(LinearLayoutManager.VERTICAL);
         mDashboard.setLayoutManager(llm);
         mDashboard.setHasFixedSize(true);
+        mDashboard.setListener(this);
+        mAdapter = new DashboardAdapter(getContext());
+        mAdapter.setConditions(mConditionManager.getConditions());
+        mSummaryLoader.setAdapter(mAdapter);
+        ConditionAdapterUtils.addDismiss(mDashboard);
 
         rebuildUI();
     }
@@ -132,10 +151,7 @@
         // TODO: Cache summaries from old categories somehow.
         List<DashboardCategory> categories =
                 ((SettingsActivity) getActivity()).getDashboardCategories();
-        boolean showingAll = mAdapter != null && mAdapter.isShowingAll();
-        mAdapter = new DashboardAdapter(getContext(), categories);
-        mSummaryLoader.setAdapter(mAdapter);
-        mAdapter.setShowingAll(showingAll);
+        mAdapter.setCategories(categories);
         mDashboard.setAdapter(mAdapter);
 
         long delta = System.currentTimeMillis() - start;
@@ -146,4 +162,10 @@
     public void onCategoriesChanged() {
         rebuildUI();
     }
+
+    @Override
+    public void onConditionsChanged() {
+        Log.d(TAG, "onConditionsChanged");
+        mAdapter.setConditions(mConditionManager.getConditions());
+    }
 }
diff --git a/src/com/android/settings/dashboard/conditional/AirplaneModeCondition.java b/src/com/android/settings/dashboard/conditional/AirplaneModeCondition.java
new file mode 100644
index 0000000..b839631
--- /dev/null
+++ b/src/com/android/settings/dashboard/conditional/AirplaneModeCondition.java
@@ -0,0 +1,95 @@
+/*
+ * 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.dashboard.conditional;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Icon;
+import android.net.ConnectivityManager;
+import com.android.settings.R;
+import com.android.settings.Settings;
+import com.android.settingslib.WirelessUtils;
+
+public class AirplaneModeCondition extends Condition {
+
+    public AirplaneModeCondition(ConditionManager conditionManager) {
+        super(conditionManager);
+    }
+
+    @Override
+    public void refreshState() {
+        setActive(WirelessUtils.isAirplaneModeOn(mManager.getContext()));
+    }
+
+    @Override
+    protected void onSilenceChanged(boolean silenced) {
+        // Only need to listen for airplane mode changes when its been silenced.
+        PackageManager pm = mManager.getContext().getPackageManager();
+        pm.setComponentEnabledSetting(new ComponentName(mManager.getContext(), Receiver.class),
+                silenced ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                PackageManager.DONT_KILL_APP);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_airplane);
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return mManager.getContext().getString(R.string.condition_airplane_title);
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return mManager.getContext().getString(R.string.condition_airplane_summary);
+    }
+
+    @Override
+    public CharSequence[] getActions() {
+        return new CharSequence[] { mManager.getContext().getString(R.string.condition_turn_off) };
+    }
+
+    @Override
+    public void onPrimaryClick() {
+        mManager.getContext().startActivity(new Intent(mManager.getContext(),
+                Settings.WirelessSettings.class));
+    }
+
+    @Override
+    public void onActionClick(int index) {
+        if (index == 0) {
+            ConnectivityManager.from(mManager.getContext()).setAirplaneMode(false);
+            setActive(false);
+        } else {
+            throw new IllegalArgumentException("Unexpected index " + index);
+        }
+    }
+
+    public static class Receiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
+                ConditionManager.get(context).getCondition(AirplaneModeCondition.class)
+                        .refreshState();
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/dashboard/conditional/Condition.java b/src/com/android/settings/dashboard/conditional/Condition.java
new file mode 100644
index 0000000..7a6fed5
--- /dev/null
+++ b/src/com/android/settings/dashboard/conditional/Condition.java
@@ -0,0 +1,107 @@
+/*
+ * 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.dashboard.conditional;
+
+import android.graphics.drawable.Icon;
+import android.os.PersistableBundle;
+import android.util.Log;
+
+public abstract class Condition {
+
+    private static final String KEY_SILENCE = "silence";
+    private static final String KEY_ACTIVE = "active";
+    private static final String KEY_LAST_STATE = "last_state";
+
+    protected final ConditionManager mManager;
+
+    private boolean mIsSilenced;
+    private boolean mIsActive;
+    private long mLastStateChange;
+
+    public Condition(ConditionManager manager) {
+        mManager = manager;
+    }
+
+    void restoreState(PersistableBundle bundle) {
+        mIsSilenced = bundle.getBoolean(KEY_SILENCE);
+        mIsActive = bundle.getBoolean(KEY_ACTIVE);
+        mLastStateChange = bundle.getLong(KEY_LAST_STATE);
+    }
+
+    void saveState(PersistableBundle bundle) {
+        bundle.putBoolean(KEY_SILENCE, mIsSilenced);
+        bundle.putBoolean(KEY_ACTIVE, mIsActive);
+        bundle.putLong(KEY_LAST_STATE, mLastStateChange);
+    }
+
+    protected void notifyChanged() {
+        mManager.notifyChanged(this);
+    }
+
+    public boolean isSilenced() {
+        return mIsSilenced;
+    }
+
+    public boolean isActive() {
+        return mIsActive;
+    }
+
+    protected void setActive(boolean active) {
+        if (mIsActive == active) {
+            return;
+        }
+        mIsActive = active;
+        mLastStateChange = System.currentTimeMillis();
+        if (mIsSilenced && !active) {
+            mIsSilenced = false;
+            onSilenceChanged(mIsSilenced);
+        }
+        notifyChanged();
+    }
+
+    public void silence() {
+        if (!mIsSilenced) {
+            mIsSilenced = true;
+            onSilenceChanged(mIsSilenced);
+            notifyChanged();
+        }
+    }
+
+    protected void onSilenceChanged(boolean state) {
+        // Optional enable/disable receivers based on silence state.
+    }
+
+    public boolean shouldShow() {
+        return isActive() && !isSilenced();
+    }
+
+    long getLastChange() {
+        return mLastStateChange;
+    }
+
+    // State.
+    public abstract void refreshState();
+
+    // UI.
+    public abstract Icon getIcon();
+    public abstract CharSequence getTitle();
+    public abstract CharSequence getSummary();
+    public abstract CharSequence[] getActions();
+
+    public abstract void onPrimaryClick();
+    public abstract void onActionClick(int index);
+}
diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java b/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
new file mode 100644
index 0000000..e390782
--- /dev/null
+++ b/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
@@ -0,0 +1,93 @@
+/*
+ * 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.dashboard.conditional;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardAdapter;
+
+public class ConditionAdapterUtils {
+
+    public static void addDismiss(final RecyclerView recyclerView) {
+        ItemTouchHelper.SimpleCallback callback = new ItemTouchHelper.SimpleCallback(0,
+                ItemTouchHelper.START | ItemTouchHelper.END) {
+            @Override
+            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
+                    RecyclerView.ViewHolder target) {
+                return true;
+            }
+
+            @Override
+            public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+                return viewHolder.getItemViewType() == R.layout.condition_card
+                        ? super.getSwipeDirs(recyclerView, viewHolder) : 0;
+            }
+
+            @Override
+            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+                DashboardAdapter adapter = (DashboardAdapter) recyclerView.getAdapter();
+                Object item = adapter.getItem(viewHolder.getItemId());
+                if (item instanceof Condition) {
+                    ((Condition) item).silence();
+                }
+            }
+        };
+        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
+        itemTouchHelper.attachToRecyclerView(recyclerView);
+    }
+
+    public static void bindViews(final Condition condition,
+            DashboardAdapter.DashboardItemHolder view, boolean isExpanded,
+            View.OnClickListener onClickListener, View.OnClickListener onExpandListener) {
+        view.itemView.setTag(condition);
+        view.itemView.setOnClickListener(onClickListener);
+        view.icon.setImageIcon(condition.getIcon());
+        view.title.setText(condition.getTitle());
+        ImageView expand = (ImageView) view.itemView.findViewById(R.id.expand_indicator);
+        expand.setTag(condition);
+        expand.setImageResource(isExpanded ? R.drawable.ic_expand_less : R.drawable.ic_expand_more);
+        expand.setOnClickListener(onExpandListener);
+
+        View detailGroup = view.itemView.findViewById(R.id.detail_group);
+        // TODO: Animate expand/collapse
+        detailGroup.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
+        if (isExpanded) {
+            view.summary.setText(condition.getSummary());
+            CharSequence[] actions = condition.getActions();
+            for (int i = 0; i < 2; i++) {
+                Button button = (Button) detailGroup.findViewById(i == 0
+                        ? R.id.first_action : R.id.second_action);
+                if (actions.length > i) {
+                    button.setVisibility(View.VISIBLE);
+                    button.setText(actions[i]);
+                    final int index = i;
+                    button.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            condition.onActionClick(index);
+                        }
+                    });
+                } else {
+                    button.setVisibility(View.GONE);
+                }
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/dashboard/conditional/ConditionManager.java b/src/com/android/settings/dashboard/conditional/ConditionManager.java
new file mode 100644
index 0000000..d710da2
--- /dev/null
+++ b/src/com/android/settings/dashboard/conditional/ConditionManager.java
@@ -0,0 +1,223 @@
+/*
+ * 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.dashboard.conditional;
+
+import android.content.Context;
+import android.os.PersistableBundle;
+import android.util.Log;
+import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class ConditionManager {
+
+    private static final String TAG = "ConditionManager";
+
+    private static final boolean DEBUG = true;
+
+    private static final String FILE_NAME = "condition_state.xml";
+    private static final String TAG_CONDITIONS = "conditions";
+    private static final String TAG_CONDITION = "condition";
+    private static final String ATTR_CLASS = "class";
+
+    private static ConditionManager sInstance;
+
+    private final Context mContext;
+    private final ArrayList<Condition> mConditions;
+    private final File mXmlFile;
+
+    private final ArrayList<ConditionListener> mListeners = new ArrayList<>();
+
+    private ConditionManager(Context context) {
+        mContext = context;
+        mConditions = new ArrayList<Condition>();
+        mXmlFile = new File(context.getFilesDir(), FILE_NAME);
+        if (mXmlFile.exists()) {
+            readFromXml();
+        }
+        addMissingConditions();
+    }
+
+    public void refreshAll() {
+        final int N = mConditions.size();
+        for (int i = 0; i < N; i++) {
+            mConditions.get(i).refreshState();
+        }
+    }
+
+    private void readFromXml() {
+        if (DEBUG) Log.d(TAG, "Reading from " + mXmlFile.toString());
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            FileReader in = new FileReader(mXmlFile);
+            parser.setInput(in);
+            int state = parser.getEventType();
+
+            while (state != XmlPullParser.END_DOCUMENT) {
+                if (TAG_CONDITION.equals(parser.getName())) {
+                    int depth = parser.getDepth();
+                    String clz = parser.getAttributeValue("", ATTR_CLASS);
+                    Condition condition = createCondition(Class.forName(clz));
+                    PersistableBundle bundle = PersistableBundle.restoreFromXml(parser);
+                    if (DEBUG) Log.d(TAG, "Reading " + clz + " -- " + bundle);
+                    condition.restoreState(bundle);
+                    mConditions.add(condition);
+                    while (parser.getDepth() > depth) {
+                        parser.next();
+                    }
+                }
+                state = parser.next();
+            }
+            in.close();
+        } catch (XmlPullParserException | IOException | ClassNotFoundException e) {
+            Log.w(TAG, "Problem reading " + FILE_NAME, e);
+        }
+    }
+
+    private void saveToXml() {
+        if (DEBUG) Log.d(TAG, "Writing to " + mXmlFile.toString());
+        try {
+            XmlSerializer serializer = Xml.newSerializer();
+            FileWriter writer = new FileWriter(mXmlFile);
+            serializer.setOutput(writer);
+
+            serializer.startDocument("UTF-8", true);
+            serializer.startTag("", TAG_CONDITIONS);
+
+            final int N = mConditions.size();
+            for (int i = 0; i < N; i++) {
+                serializer.startTag("", TAG_CONDITION);
+                serializer.attribute("", ATTR_CLASS, mConditions.get(i).getClass().getName());
+                PersistableBundle bundle = new PersistableBundle();
+                mConditions.get(i).saveState(bundle);
+                bundle.saveToXml(serializer);
+                serializer.endTag("", TAG_CONDITION);
+            }
+
+            serializer.endTag("", TAG_CONDITIONS);
+            serializer.flush();
+            writer.close();
+        } catch (XmlPullParserException | IOException e) {
+            Log.w(TAG, "Problem writing " + FILE_NAME, e);
+        }
+    }
+
+    private void addMissingConditions() {
+        addIfMissing(AirplaneModeCondition.class);
+        addIfMissing(HotspotCondition.class);
+        addIfMissing(DndCondition.class);
+    }
+
+    private void addIfMissing(Class<? extends Condition> clz) {
+        if (getCondition(clz) == null) {
+            if (DEBUG) Log.d(TAG, "Adding missing " + clz.getName());
+            mConditions.add(createCondition(clz));
+        }
+    }
+
+    private Condition createCondition(Class<?> clz) {
+        if (AirplaneModeCondition.class == clz) {
+            return new AirplaneModeCondition(this);
+        } else if (HotspotCondition.class == clz) {
+            return new HotspotCondition(this);
+        } else if (DndCondition.class == clz) {
+            return new DndCondition(this);
+        }
+        try {
+            Constructor<?> constructor = clz.getConstructor(ConditionManager.class);
+            return (Condition) constructor.newInstance(this);
+        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException
+                | InvocationTargetException e) {
+        }
+        return null;
+    }
+
+    Context getContext() {
+        return mContext;
+    }
+
+    public <T extends Condition> T getCondition(Class<T> clz) {
+        final int N = mConditions.size();
+        for (int i = 0; i < N; i++) {
+            if (clz.equals(mConditions.get(i).getClass())) {
+                return (T) mConditions.get(i);
+            }
+        }
+        return null;
+    }
+
+    public List<Condition> getConditions() {
+        return mConditions;
+    }
+
+    public List<Condition> getVisibleConditions() {
+        List<Condition> conditions = new ArrayList<>();
+        final int N = mConditions.size();
+        for (int i = 0; i < N; i++) {
+            if (mConditions.get(i).shouldShow()) {
+                conditions.add(mConditions.get(i));
+            }
+        }
+        Collections.sort(conditions, CONDITION_COMPARATOR);
+        return conditions;
+    }
+
+    public void notifyChanged(Condition condition) {
+        saveToXml();
+        final int N = mListeners.size();
+        for (int i = 0; i < N; i++) {
+            mListeners.get(i).onConditionsChanged();
+        }
+    }
+
+    public void addListener(ConditionListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void remListener(ConditionListener listener) {
+        mListeners.remove(listener);
+    }
+
+    public static ConditionManager get(Context context) {
+        if (sInstance == null) {
+            sInstance = new ConditionManager(context);
+        }
+        return sInstance;
+    }
+
+    public interface ConditionListener {
+        void onConditionsChanged();
+    }
+
+    private static final Comparator<Condition> CONDITION_COMPARATOR = new Comparator<Condition>() {
+        @Override
+        public int compare(Condition lhs, Condition rhs) {
+            return Long.compare(lhs.getLastChange(), rhs.getLastChange());
+        }
+    };
+}
diff --git a/src/com/android/settings/dashboard/conditional/DndCondition.java b/src/com/android/settings/dashboard/conditional/DndCondition.java
new file mode 100644
index 0000000..3cc3cf0
--- /dev/null
+++ b/src/com/android/settings/dashboard/conditional/DndCondition.java
@@ -0,0 +1,133 @@
+/*
+ * 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.dashboard.conditional;
+
+import android.app.ActivityManager;
+import android.app.NotificationManager;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Icon;
+import android.provider.Settings;
+
+import android.service.notification.ZenModeConfig;
+import com.android.settings.R;
+
+public class DndCondition extends Condition {
+
+    private static final String TAG = "DndCondition";
+
+    private int mZen;
+    private ZenModeConfig mConfig;
+
+    public DndCondition(ConditionManager manager) {
+        super(manager);
+    }
+
+    @Override
+    public void refreshState() {
+        NotificationManager notificationManager =
+                mManager.getContext().getSystemService(NotificationManager.class);
+        mZen = notificationManager.getZenMode();
+        boolean zenModeEnabled = mZen != Settings.Global.ZEN_MODE_OFF;
+        if (zenModeEnabled) {
+            mConfig = notificationManager.getZenModeConfig();
+        } else {
+            mConfig = null;
+        }
+        setActive(zenModeEnabled);
+    }
+
+    @Override
+    protected void onSilenceChanged(boolean silenced) {
+        // Only need to listen for dnd mode changes when its been silenced.
+        PackageManager pm = mManager.getContext().getPackageManager();
+        pm.setComponentEnabledSetting(new ComponentName(mManager.getContext(), Receiver.class),
+                silenced ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                PackageManager.DONT_KILL_APP);
+    }
+
+    private CharSequence getZenState() {
+        switch (mZen) {
+            case Settings.Global.ZEN_MODE_ALARMS:
+                return mManager.getContext().getString(R.string.zen_mode_option_alarms);
+            case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+                return mManager.getContext().getString(
+                        R.string.zen_mode_option_important_interruptions);
+            case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
+                return mManager.getContext().getString(R.string.zen_mode_option_no_interruptions);
+        }
+        return null;
+    }
+
+    @Override
+    public Icon getIcon() {
+        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_zen);
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return mManager.getContext().getString(R.string.condition_zen_title, getZenState());
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        final boolean isForever = mConfig != null && mConfig.manualRule != null
+                && mConfig.manualRule.conditionId == null;
+        return isForever ? mManager.getContext().getString(com.android.internal.R.string.zen_mode_forever_dnd)
+                : ZenModeConfig.getConditionSummary(mManager.getContext(), mConfig,
+                ActivityManager.getCurrentUser(),
+                false);
+    }
+
+    @Override
+    public CharSequence[] getActions() {
+        return new CharSequence[] { mManager.getContext().getString(R.string.condition_turn_off) };
+    }
+
+    @Override
+    public void onPrimaryClick() {
+        StatusBarManager statusBar = mManager.getContext().getSystemService(StatusBarManager.class);
+        statusBar.expandSettingsPanel("dnd");
+    }
+
+    @Override
+    public void onActionClick(int index) {
+        if (index == 0) {
+            NotificationManager notificationManager = mManager.getContext().getSystemService(
+                    NotificationManager.class);
+            notificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG);
+            setActive(false);
+        } else {
+            throw new IllegalArgumentException("Unexpected index " + index);
+        }
+    }
+
+    public static class Receiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL
+                    .equals(intent.getAction())) {
+                ConditionManager.get(context).getCondition(DndCondition.class)
+                        .refreshState();
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/dashboard/conditional/FocusRecyclerView.java b/src/com/android/settings/dashboard/conditional/FocusRecyclerView.java
new file mode 100644
index 0000000..af51ed5
--- /dev/null
+++ b/src/com/android/settings/dashboard/conditional/FocusRecyclerView.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 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.dashboard.conditional;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+
+/**
+ * Version of RecyclerView that can have listeners for onWindowFocusChanged.
+ */
+public class FocusRecyclerView extends RecyclerView {
+
+    private FocusListener mListener;
+
+    public FocusRecyclerView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+        if (mListener != null) {
+            mListener.onWindowFocusChanged(hasWindowFocus);
+        }
+    }
+
+    public void setListener(FocusListener listener) {
+        mListener = listener;
+    }
+
+    public interface FocusListener {
+        void onWindowFocusChanged(boolean hasWindowFocus);
+    }
+}
diff --git a/src/com/android/settings/dashboard/conditional/HotspotCondition.java b/src/com/android/settings/dashboard/conditional/HotspotCondition.java
new file mode 100644
index 0000000..0f185c6
--- /dev/null
+++ b/src/com/android/settings/dashboard/conditional/HotspotCondition.java
@@ -0,0 +1,111 @@
+/*
+ * 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.dashboard.conditional;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Icon;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import com.android.settings.R;
+import com.android.settings.TetherSettings;
+import com.android.settings.Utils;
+import com.android.settingslib.TetherUtil;
+
+public class HotspotCondition extends Condition {
+
+    private final WifiManager mWifiManager;
+
+    public HotspotCondition(ConditionManager manager) {
+        super(manager);
+        mWifiManager = mManager.getContext().getSystemService(WifiManager.class);
+    }
+
+    @Override
+    public void refreshState() {
+        boolean wifiTetherEnabled = TetherUtil.isWifiTetherEnabled(mManager.getContext());
+        setActive(wifiTetherEnabled);
+    }
+
+    @Override
+    protected void onSilenceChanged(boolean silenced) {
+        // Only need to listen for hotspot changes when hotspot has been silenced.
+        PackageManager pm = mManager.getContext().getPackageManager();
+        pm.setComponentEnabledSetting(new ComponentName(mManager.getContext(), Receiver.class),
+                silenced ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                PackageManager.DONT_KILL_APP);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_hotspot);
+    }
+
+    private String getSsid() {
+        WifiConfiguration wifiConfig = mWifiManager.getWifiApConfiguration();
+        if (wifiConfig == null) {
+            return mManager.getContext().getString(
+                    com.android.internal.R.string.wifi_tether_configure_ssid_default);
+        } else {
+            return wifiConfig.SSID;
+        }
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return mManager.getContext().getString(R.string.condition_hotspot_title);
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return mManager.getContext().getString(R.string.condition_hotspot_summary, getSsid());
+    }
+
+    @Override
+    public CharSequence[] getActions() {
+        return new CharSequence[] { mManager.getContext().getString(R.string.condition_turn_off) };
+    }
+
+    @Override
+    public void onPrimaryClick() {
+        Utils.startWithFragment(mManager.getContext(), TetherSettings.class.getName(), null, null,
+                0, R.string.tether_settings_title_all, null);
+    }
+
+    @Override
+    public void onActionClick(int index) {
+        if (index == 0) {
+            TetherUtil.setWifiTethering(false, mManager.getContext());
+            setActive(false);
+        } else {
+            throw new IllegalArgumentException("Unexpected index " + index);
+        }
+    }
+
+    public static class Receiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) {
+                ConditionManager.get(context).getCondition(HotspotCondition.class)
+                        .refreshState();
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/display/DisplayDensityUtils.java b/src/com/android/settings/display/DisplayDensityUtils.java
new file mode 100644
index 0000000..cef5418
--- /dev/null
+++ b/src/com/android/settings/display/DisplayDensityUtils.java
@@ -0,0 +1,240 @@
+/*
+ * 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.display;
+
+import com.android.settings.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.MathUtils;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import java.util.Arrays;
+
+/**
+ * Utility methods for working with display density.
+ */
+class DisplayDensityUtils {
+    private static final String LOG_TAG = "DisplayDensityUtils";
+
+    /** Minimum increment between density scales. */
+    private static final float MIN_SCALE_INTERVAL = 0.09f;
+
+    /** Minimum density scale. This is available on all devices. */
+    private static final float MIN_SCALE = 0.85f;
+
+    /** Maximum density scale. The actual scale used depends on the device. */
+    private static final float MAX_SCALE = 1.50f;
+
+    /** Summary used for "normal" scale. */
+    private static final int SUMMARY_NORMAL = R.string.screen_zoom_summary_normal;
+
+    /** Summary used for "custom" scale. */
+    private static final int SUMMARY_CUSTOM = R.string.screen_zoom_summary_custom;
+
+    /**
+     * Summaries for scales smaller than "normal" in order of smallest to
+     * largest.
+     */
+    private static final int[] SUMMARIES_SMALLER = new int[] {
+            R.string.screen_zoom_summary_small
+    };
+
+    /**
+     * Summaries for scales larger than "normal" in order of smallest to
+     * largest.
+     */
+    private static final int[] SUMMARIES_LARGER = new int[] {
+            R.string.screen_zoom_summary_large,
+            R.string.screen_zoom_summary_very_large,
+            R.string.screen_zoom_summary_extremely_large,
+    };
+
+    /**
+     * Minimum allowed screen dimension, corresponds to resource qualifiers
+     * "small" or "sw320dp". This value must be at least the minimum screen
+     * size required by the CDD so that we meet developer expectations.
+     */
+    private static final int MIN_DIMENSION_DP = 320;
+
+    private final String[] mEntries;
+    private final int[] mValues;
+
+    private final int mNormalDensity;
+    private final int mCurrentIndex;
+
+    public DisplayDensityUtils(Context context) {
+        final int normalDensity = DisplayDensityUtils.getNormalDisplayDensity(
+                Display.DEFAULT_DISPLAY);
+        if (normalDensity <= 0) {
+            mEntries = null;
+            mValues = null;
+            mNormalDensity = 0;
+            mCurrentIndex = -1;
+            return;
+        }
+
+        final Resources res = context.getResources();
+        final DisplayMetrics metrics = res.getDisplayMetrics();
+        final int currentDensity = metrics.densityDpi;
+        int currentDensityIndex = -1;
+
+        // Compute number of "larger" and "smaller" scales for this display.
+        final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
+        final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
+        final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) normalDensity);
+        final float minScale = MIN_SCALE;
+        final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
+                0, SUMMARIES_LARGER.length);
+        final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
+                0, SUMMARIES_SMALLER.length);
+
+        String[] entries = new String[1 + numSmaller + numLarger];
+        int[] values = new int[entries.length];
+        int curIndex = 0;
+
+        if (numSmaller > 0) {
+            final float interval = (1 - minScale) / numSmaller;
+            for (int i = numSmaller - 1; i >= 0; i--) {
+                final int density = (int) (normalDensity * (1 - (i + 1) * interval));
+                if (currentDensity == density) {
+                    currentDensityIndex = curIndex;
+                }
+                entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]);
+                values[curIndex] = density;
+                curIndex++;
+            }
+        }
+
+        if (currentDensity == normalDensity) {
+            currentDensityIndex = curIndex;
+        }
+        values[curIndex] = normalDensity;
+        entries[curIndex] = res.getString(SUMMARY_NORMAL);
+        curIndex++;
+
+        if (numLarger > 0) {
+            final float interval = (maxScale - 1) / numLarger;
+            for (int i = 0; i < numLarger; i++) {
+                final int density = (int) (normalDensity * (1 + (i + 1) * interval));
+                if (currentDensity == density) {
+                    currentDensityIndex = curIndex;
+                }
+                values[curIndex] = density;
+                entries[curIndex] = res.getString(SUMMARIES_LARGER[i]);
+                curIndex++;
+            }
+        }
+
+        final int displayIndex;
+        if (currentDensityIndex >= 0) {
+            displayIndex = currentDensityIndex;
+        } else {
+            // We don't understand the current density. Must have been set by
+            // someone else. Make room for another entry...
+            values = Arrays.copyOf(values, values.length + 1);
+            values[curIndex] = currentDensity;
+
+            entries = Arrays.copyOf(entries, values.length + 1);
+            entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
+
+            displayIndex = curIndex;
+        }
+
+        mNormalDensity = normalDensity;
+        mCurrentIndex = displayIndex;
+        mEntries = entries;
+        mValues = values;
+    }
+
+    public String[] getEntries() {
+        return mEntries;
+    }
+
+    public int[] getValues() {
+        return mValues;
+    }
+
+    public int getCurrentIndex() {
+        return mCurrentIndex;
+    }
+
+    public int getNormalDensity() {
+        return mNormalDensity;
+    }
+
+    /**
+     * Returns the normal (default) density for the specified display.
+     *
+     * @param displayId the identifier of the display
+     * @return the normal density of the specified display, or {@code -1} if
+     *         the display does not exist or the density could not be obtained
+     */
+    private static int getNormalDisplayDensity(int displayId) {
+       try {
+           final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+           return wm.getInitialDisplayDensity(displayId);
+       } catch (RemoteException exc) {
+           return -1;
+       }
+    }
+
+    /**
+     * Asynchronously applies display density changes to the specified display.
+     *
+     * @param displayId the identifier of the display to modify
+     */
+    public static void clearForcedDisplayDensity(final int displayId) {
+        AsyncTask.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                    wm.clearForcedDisplayDensity(displayId);
+                } catch (RemoteException exc) {
+                    Log.w(LOG_TAG, "Unable to clear forced display density setting");
+                }
+            }
+        });
+    }
+
+    /**
+     * Asynchronously applies display density changes to the specified display.
+     *
+     * @param displayId the identifier of the display to modify
+     * @param density the density to force for the specified display
+     */
+    public static void setForcedDisplayDensity(final int displayId, final int density) {
+        AsyncTask.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                    wm.setForcedDisplayDensity(displayId, density);
+                } catch (RemoteException exc) {
+                    Log.w(LOG_TAG, "Unable to save forced display density setting");
+                }
+            }
+        });
+    }
+}
diff --git a/src/com/android/settings/display/ScreenZoomPreference.java b/src/com/android/settings/display/ScreenZoomPreference.java
new file mode 100644
index 0000000..78cc49c
--- /dev/null
+++ b/src/com/android/settings/display/ScreenZoomPreference.java
@@ -0,0 +1,53 @@
+/*
+ * 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.display;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.support.v7.preference.PreferenceGroup;
+import android.util.AttributeSet;
+
+/**
+ * Preference for changing the density of the display on which the preference
+ * is visible.
+ */
+public class ScreenZoomPreference extends PreferenceGroup {
+    public ScreenZoomPreference(Context context, AttributeSet attrs) {
+        super(context, attrs, TypedArrayUtils.getAttr(context,
+                android.support.v7.preference.R.attr.preferenceScreenStyle,
+                android.R.attr.preferenceScreenStyle));
+
+        setFragment("com.android.settings.display.ScreenZoomSettings");
+
+        final DisplayDensityUtils density = new DisplayDensityUtils(context);
+        final int defaultIndex = density.getCurrentIndex();
+        if (defaultIndex < 0) {
+            setVisible(false);
+            setEnabled(false);
+        } else {
+            final String[] entries = density.getEntries();
+            final int currentIndex = density.getCurrentIndex();
+            setSummary(entries[currentIndex]);
+        }
+    }
+
+    @Override
+    protected boolean isOnSameScreenAsChildren() {
+        return false;
+    }
+}
diff --git a/src/com/android/settings/display/ScreenZoomSettings.java b/src/com/android/settings/display/ScreenZoomSettings.java
new file mode 100644
index 0000000..1ddcaab
--- /dev/null
+++ b/src/com/android/settings/display/ScreenZoomSettings.java
@@ -0,0 +1,272 @@
+/*
+ * 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.display;
+
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+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;
+
+/**
+ * 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;
+
+    /** 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;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final DisplayDensityUtils density = new DisplayDensityUtils(getContext());
+
+        final int initialIndex = density.getCurrentIndex();
+        if (initialIndex < 0) {
+            // Failed to obtain normal density, which means we failed to
+            // connect to the window manager service. Just use the current
+            // density and don't let the user change anything.
+            final int densityDpi = getResources().getDisplayMetrics().densityDpi;
+            mValues = new int[] { densityDpi };
+            mEntries = new String[] { getString(R.string.screen_zoom_summary_normal) };
+            mInitialIndex = 0;
+            mNormalDensity = densityDpi;
+        } else {
+            mValues = density.getValues();
+            mEntries = density.getEntries();
+            mInitialIndex = initialIndex;
+            mNormalDensity = density.getNormalDensity();
+        }
+    }
+
+    @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);
+
+        // 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;
+    }
+
+    /**
+     * Persists the selected density and sends a configuration change.
+     */
+    private void commit() {
+        final int densityDpi = mValues[mCurrentIndex];
+        if (densityDpi == mNormalDensity) {
+            DisplayDensityUtils.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
+        } else {
+            DisplayDensityUtils.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, densityDpi);
+        }
+    }
+
+    @Override
+    protected int getMetricsCategory() {
+        return InstrumentedFragment.DISPLAY_SCREEN_ZOOM;
+    }
+
+    /** Index provider used to expose this fragment in search. */
+    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+                    final Resources res = context.getResources();
+                    final SearchIndexableRaw data = new SearchIndexableRaw(context);
+                    data.title = res.getString(R.string.screen_zoom_title);
+                    data.screenTitle = res.getString(R.string.screen_zoom_title);
+                    data.keywords = res.getString(R.string.screen_zoom_keywords);
+
+                    final List<SearchIndexableRaw> result = new ArrayList<>(1);
+                    result.add(data);
+                    return result;
+                }
+            };
+}
diff --git a/src/com/android/settings/display/TouchBlockingFrameLayout.java b/src/com/android/settings/display/TouchBlockingFrameLayout.java
new file mode 100644
index 0000000..3f5483d
--- /dev/null
+++ b/src/com/android/settings/display/TouchBlockingFrameLayout.java
@@ -0,0 +1,42 @@
+/*
+ * 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.display;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+/**
+ * Extension of FrameLayout that consumes all touch events.
+ */
+public class TouchBlockingFrameLayout extends FrameLayout {
+    public TouchBlockingFrameLayout(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        return true;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        return true;
+    }
+}
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
index 63d9335..b246bdf 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
@@ -33,7 +33,7 @@
     private static final int ENROLLING = 2;
     public static final String EXTRA_KEY_LAUNCHED_CONFIRM = "launched_confirm_lock";
 
-    private FingerprintLocationAnimationView mAnimation;
+    private FingerprintFindSensorAnimation mAnimation;
     private boolean mLaunchedConfirmLock;
 
     @Override
@@ -46,7 +46,7 @@
         if (mToken == null && !mLaunchedConfirmLock) {
             launchConfirmLock();
         }
-        mAnimation = (FingerprintLocationAnimationView) findViewById(
+        mAnimation = (FingerprintFindSensorAnimation) findViewById(
                 R.id.fingerprint_sensor_location_animation);
     }
 
diff --git a/src/com/android/settings/fingerprint/FingerprintFindSensorAnimation.java b/src/com/android/settings/fingerprint/FingerprintFindSensorAnimation.java
new file mode 100644
index 0000000..cb254ba
--- /dev/null
+++ b/src/com/android/settings/fingerprint/FingerprintFindSensorAnimation.java
@@ -0,0 +1,35 @@
+/*
+ * 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.fingerprint;
+
+/**
+ * An abstraction for a view that contains an animation that shows the user
+ * where the fingerprint sensor is on the device.
+ */
+public interface FingerprintFindSensorAnimation {
+
+    /**
+     * Start the animation
+     */
+    void startAnimation();
+
+    /**
+     * Stop the animation
+     */
+    void stopAnimation();
+
+}
diff --git a/src/com/android/settings/fingerprint/FingerprintLocationAnimationVideoView.java b/src/com/android/settings/fingerprint/FingerprintLocationAnimationVideoView.java
new file mode 100644
index 0000000..c1fd2c2
--- /dev/null
+++ b/src/com/android/settings/fingerprint/FingerprintLocationAnimationVideoView.java
@@ -0,0 +1,127 @@
+/*
+ * 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.fingerprint;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.SurfaceTexture;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnInfoListener;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.View;
+
+import com.android.settings.R;
+
+/**
+ * A view containing a VideoView for showing the user how to enroll a fingerprint
+ */
+public class FingerprintLocationAnimationVideoView extends TextureView
+        implements FingerprintFindSensorAnimation {
+    protected float mAspect = 1.0f; // initial guess until we know
+    protected MediaPlayer mMediaPlayer;
+
+    public FingerprintLocationAnimationVideoView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Width is driven by measurespec, height is derrived from aspect ratio
+        int originalWidth = MeasureSpec.getSize(widthMeasureSpec);
+        int height = Math.round(mAspect * originalWidth);
+        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        setSurfaceTextureListener(new SurfaceTextureListener() {
+            @Override
+            public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
+                    int height) {
+                setVisibility(View.INVISIBLE);
+                Uri videoUri = resourceEntryToUri(mContext, R.raw.fingerprint_location_animation);
+                mMediaPlayer = MediaPlayer.create(mContext, videoUri);
+                mMediaPlayer.setSurface(new Surface(surfaceTexture));
+                mMediaPlayer.setOnPreparedListener(new OnPreparedListener() {
+                    @Override
+                    public void onPrepared(MediaPlayer mediaPlayer) {
+                        mediaPlayer.setLooping(true);
+                    }
+                });
+                mMediaPlayer.setOnInfoListener(new OnInfoListener() {
+                    @Override
+                    public boolean onInfo(MediaPlayer mediaPlayer, int what, int extra) {
+                        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
+                            // Keep the view hidden until video starts
+                            setVisibility(View.VISIBLE);
+                        }
+                        return false;
+                    }
+                });
+                mAspect = (float) mMediaPlayer.getVideoHeight() / mMediaPlayer.getVideoWidth();
+                requestLayout();
+                startAnimation();
+            }
+
+            @Override
+            public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
+                    int width, int height) {
+            }
+
+            @Override
+            public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+                return false;
+            }
+
+            @Override
+            public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
+            }
+        });
+    }
+
+    private static Uri resourceEntryToUri (Context context, int id) {
+        Resources res = context.getResources();
+        return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+                res.getResourcePackageName(id) + '/' +
+                res.getResourceTypeName(id) + '/' +
+                res.getResourceEntryName(id));
+    }
+
+    @Override
+    public void startAnimation() {
+        if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
+            mMediaPlayer.start();
+        }
+    }
+
+    @Override
+    public void stopAnimation() {
+        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
+            mMediaPlayer.stop();
+            mMediaPlayer.release();
+            mMediaPlayer = null;
+        }
+    }
+
+}
diff --git a/src/com/android/settings/fingerprint/FingerprintLocationAnimationView.java b/src/com/android/settings/fingerprint/FingerprintLocationAnimationView.java
index 65f38bd..c17069f 100644
--- a/src/com/android/settings/fingerprint/FingerprintLocationAnimationView.java
+++ b/src/com/android/settings/fingerprint/FingerprintLocationAnimationView.java
@@ -34,7 +34,8 @@
 /**
  * View which plays an animation to indicate where the sensor is on the device.
  */
-public class FingerprintLocationAnimationView extends View {
+public class FingerprintLocationAnimationView extends View implements
+        FingerprintFindSensorAnimation {
 
     private static final float MAX_PULSE_ALPHA = 0.15f;
     private static final long DELAY_BETWEEN_PHASE = 1000;
@@ -95,10 +96,12 @@
         return getHeight() * mFractionCenterY;
     }
 
+    @Override
     public void startAnimation() {
         startPhase();
     }
 
+    @Override
     public void stopAnimation() {
         removeCallbacks(mStartPhaseRunnable);
         if (mRadiusAnimator != null) {
diff --git a/src/com/android/settings/nfc/NfcForegroundPreference.java b/src/com/android/settings/nfc/NfcForegroundPreference.java
index 2e0c3d8..f2d98bf 100644
--- a/src/com/android/settings/nfc/NfcForegroundPreference.java
+++ b/src/com/android/settings/nfc/NfcForegroundPreference.java
@@ -16,8 +16,8 @@
 package com.android.settings.nfc;
 
 import android.content.Context;
+import android.support.v7.preference.DropDownPreference;
 
-import com.android.settings.DropDownPreference;
 import com.android.settings.R;
 
 public class NfcForegroundPreference extends DropDownPreference implements
diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java
index 4b438f0..f3f74a7 100644
--- a/src/com/android/settings/notification/ConfigureNotificationSettings.java
+++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java
@@ -17,7 +17,6 @@
 package com.android.settings.notification;
 
 import com.android.internal.widget.LockPatternUtils;
-import com.android.settings.DropDownPreference;
 import com.android.settings.InstrumentedFragment;
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
@@ -31,6 +30,7 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.support.v7.preference.TwoStatePreference;
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/SettingPref.java b/src/com/android/settings/notification/SettingPref.java
index 99ce3b5..18efc33 100644
--- a/src/com/android/settings/notification/SettingPref.java
+++ b/src/com/android/settings/notification/SettingPref.java
@@ -22,11 +22,11 @@
 import android.net.Uri;
 import android.provider.Settings.Global;
 import android.provider.Settings.System;
+import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.support.v7.preference.TwoStatePreference;
 
-import com.android.settings.DropDownPreference;
 import com.android.settings.SettingsPreferenceFragment;
 
 /** Helper to manage a two-state or dropdown preference bound to a global or system setting. */
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);
diff --git a/src/com/android/settings/notification/ZenModeEventRuleSettings.java b/src/com/android/settings/notification/ZenModeEventRuleSettings.java
index d8e7ad1..c5691d4 100644
--- a/src/com/android/settings/notification/ZenModeEventRuleSettings.java
+++ b/src/com/android/settings/notification/ZenModeEventRuleSettings.java
@@ -26,12 +26,12 @@
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.EventInfo;
+import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.support.v7.preference.PreferenceScreen;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.settings.DropDownPreference;
 import com.android.settings.R;
 
 import java.util.ArrayList;
diff --git a/src/com/android/settings/notification/ZenModePrioritySettings.java b/src/com/android/settings/notification/ZenModePrioritySettings.java
index e3413a7..f479ba3 100644
--- a/src/com/android/settings/notification/ZenModePrioritySettings.java
+++ b/src/com/android/settings/notification/ZenModePrioritySettings.java
@@ -21,13 +21,13 @@
 import android.os.Bundle;
 import android.service.notification.ZenModeConfig;
 import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.support.v7.preference.PreferenceScreen;
 import android.util.Log;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.settings.DropDownPreference;
 import com.android.settings.R;
 import com.android.settings.search.Indexable;
 
diff --git a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
index e8a9c28..b0f12f8 100644
--- a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
+++ b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.service.notification.ConditionProviderService;
+import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.support.v7.preference.Preference.OnPreferenceClickListener;
@@ -39,7 +40,6 @@
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.settings.DropDownPreference;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.widget.SwitchBar;
diff --git a/src/com/android/settings/search/Index.java b/src/com/android/settings/search/Index.java
index 73386fb..3fd06a2 100644
--- a/src/com/android/settings/search/Index.java
+++ b/src/com/android/settings/search/Index.java
@@ -150,7 +150,9 @@
 
     private static final String EMPTY = "";
     private static final String NON_BREAKING_HYPHEN = "\u2011";
+    private static final String LIST_DELIMITERS = "[,]\\s*";
     private static final String HYPHEN = "-";
+    private static final String SPACE = " ";
 
     private static final String FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER =
             "SEARCH_INDEX_DATA_PROVIDER";
@@ -1002,12 +1004,13 @@
         final String normalizedSummaryOn = normalizeString(updatedSummaryOn);
         final String normalizedSummaryOff = normalizeString(updatedSummaryOff);
 
+        final String spaceDelimitedKeywords = normalizeKeywords(keywords);
+
         updateOneRow(database, locale,
                 updatedTitle, normalizedTitle, updatedSummaryOn, normalizedSummaryOn,
-                updatedSummaryOff, normalizedSummaryOff, entries,
-                className, screenTitle, iconResId,
-                rank, keywords, intentAction, intentTargetPackage, intentTargetClass, enabled,
-                key, userId);
+                updatedSummaryOff, normalizedSummaryOff, entries, className, screenTitle, iconResId,
+                rank, spaceDelimitedKeywords, intentAction, intentTargetPackage, intentTargetClass,
+                enabled, key, userId);
     }
 
     private static String normalizeHyphen(String input) {
@@ -1021,11 +1024,14 @@
         return REMOVE_DIACRITICALS_PATTERN.matcher(normalized).replaceAll("").toLowerCase();
     }
 
-    private void updateOneRow(SQLiteDatabase database, String locale,
-            String updatedTitle, String normalizedTitle,
-            String updatedSummaryOn, String normalizedSummaryOn,
-            String updatedSummaryOff, String normalizedSummaryOff, String entries,
-            String className, String screenTitle, int iconResId, int rank, String keywords,
+    private static String normalizeKeywords(String input) {
+        return (input != null) ? input.replaceAll(LIST_DELIMITERS, SPACE) : EMPTY;
+    }
+
+    private void updateOneRow(SQLiteDatabase database, String locale, String updatedTitle,
+            String normalizedTitle, String updatedSummaryOn, String normalizedSummaryOn,
+            String updatedSummaryOff, String normalizedSummaryOff, String entries, String className,
+            String screenTitle, int iconResId, int rank, String spaceDelimitedKeywords,
             String intentAction, String intentTargetPackage, String intentTargetClass,
             boolean enabled, String key, int userId) {
 
@@ -1050,7 +1056,7 @@
         values.put(IndexColumns.DATA_SUMMARY_OFF, updatedSummaryOff);
         values.put(IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, normalizedSummaryOff);
         values.put(IndexColumns.DATA_ENTRIES, entries);
-        values.put(IndexColumns.DATA_KEYWORDS, keywords);
+        values.put(IndexColumns.DATA_KEYWORDS, spaceDelimitedKeywords);
         values.put(IndexColumns.CLASS_NAME, className);
         values.put(IndexColumns.SCREEN_TITLE, screenTitle);
         values.put(IndexColumns.INTENT_ACTION, intentAction);
diff --git a/src/com/android/settings/search/Ranking.java b/src/com/android/settings/search/Ranking.java
index 4ac4fb8..3d5ff35 100644
--- a/src/com/android/settings/search/Ranking.java
+++ b/src/com/android/settings/search/Ranking.java
@@ -36,6 +36,7 @@
 import com.android.settings.applications.ManageDefaultApps;
 import com.android.settings.bluetooth.BluetoothSettings;
 import com.android.settings.deviceinfo.StorageSettings;
+import com.android.settings.display.ScreenZoomSettings;
 import com.android.settings.fuelgauge.BatterySaverSettings;
 import com.android.settings.fuelgauge.PowerUsageSummary;
 import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
@@ -122,6 +123,7 @@
 
         // Display
         sRankMap.put(DisplaySettings.class.getName(), RANK_DISPLAY);
+        sRankMap.put(ScreenZoomSettings.class.getName(), RANK_WIFI);
 
         // Wallpapers
         sRankMap.put(WallpaperTypeSettings.class.getName(), RANK_WALLPAPER);
diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java
index 6d6ca08..f15ff63 100644
--- a/src/com/android/settings/search/SearchIndexableResources.java
+++ b/src/com/android/settings/search/SearchIndexableResources.java
@@ -38,6 +38,7 @@
 import com.android.settings.applications.ManageDefaultApps;
 import com.android.settings.bluetooth.BluetoothSettings;
 import com.android.settings.deviceinfo.StorageSettings;
+import com.android.settings.display.ScreenZoomSettings;
 import com.android.settings.fuelgauge.BatterySaverSettings;
 import com.android.settings.fuelgauge.PowerUsageSummary;
 import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
@@ -131,6 +132,13 @@
                         HomeSettings.class.getName(),
                         R.drawable.ic_settings_home));
 
+        sResMap.put(ScreenZoomSettings.class.getName(),
+                new SearchIndexableResource(
+                        Ranking.getRankForClassName(ScreenZoomSettings.class.getName()),
+                        NO_DATA_RES_ID,
+                        ScreenZoomSettings.class.getName(),
+                        R.drawable.ic_settings_display));
+
         sResMap.put(DisplaySettings.class.getName(),
                 new SearchIndexableResource(
                         Ranking.getRankForClassName(DisplaySettings.class.getName()),