Merge "Remove unused ExploreByTouchHelper class"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 26a5e10..07d7ecc 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1572,11 +1572,11 @@
         </activity>
 
         <activity android:name="ConfirmLockPattern"
-            android:theme="@style/Theme.ConfirmDeviceCredentials"/>
+            android:theme="@style/SetupWizardTheme.Light"/>
 
         <activity android:name="ConfirmLockPassword"
             android:windowSoftInputMode="stateHidden|adjustResize"
-            android:theme="@style/Theme.ConfirmDeviceCredentials"/>
+            android:theme="@style/SetupWizardTheme.Light"/>
 
         <activity
             android:name=".Settings$FingerprintSuggestionActivity"
@@ -1618,13 +1618,13 @@
         <!-- Note this must not be exported since it returns the password in the intent -->
         <activity android:name="ConfirmLockPattern$InternalActivity"
             android:exported="false"
-            android:theme="@style/Theme.ConfirmDeviceCredentials"/>
+            android:theme="@style/SetupWizardTheme.Light"/>
 
         <!-- Note this must not be exported since it returns the password in the intent -->
         <activity android:name="ConfirmLockPassword$InternalActivity"
             android:exported="false"
             android:windowSoftInputMode="adjustResize"
-            android:theme="@style/Theme.ConfirmDeviceCredentials"/>
+            android:theme="@style/SetupWizardTheme.Light"/>
 
         <activity android:name="SetupChooseLockGeneric"
             android:taskAffinity="com.android.wizard"
diff --git a/res/layout-land/confirm_lock_pattern_internal.xml b/res/layout-land/confirm_lock_pattern_internal.xml
new file mode 100644
index 0000000..4e58f32
--- /dev/null
+++ b/res/layout-land/confirm_lock_pattern_internal.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<com.android.setupwizardlib.GlifLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/setup_wizard_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:icon="@drawable/ic_lock"
+    android:layout="@layout/suw_glif_blank_template">
+
+    <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+        android:id="@+id/topLayout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal">
+
+        <ScrollView
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:fillViewport="true">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:paddingBottom="24dp">
+
+                <ImageView
+                    android:id="@+id/suw_layout_icon"
+                    style="@style/SuwGlifIcon"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:src="@drawable/ic_lock" />
+
+                <TextView
+                    android:id="@+id/headerText"
+                    style="@style/SuwGlifHeaderTitle"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" />
+
+                <TextView
+                    style="@style/SuwDescription.Glif"
+                    android:id="@+id/detailsText"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="?attr/suwMarginSides"
+                    android:layout_marginEnd="?attr/suwMarginSides" />
+
+                <Button
+                    android:id="@+id/cancelButton"
+                    style="@style/SetupWizardButton.Negative"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="?attr/suwMarginSides"
+                    android:layout_marginEnd="?attr/suwMarginSides"
+                    android:text="@string/cancel" />
+
+                <Space
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_weight="1" />
+
+                <TextView
+                    style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+                    android:accessibilityLiveRegion="polite"
+                    android:id="@+id/errorText"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="?attr/suwMarginSides"
+                    android:layout_marginEnd="?attr/suwMarginSides"
+                    android:layout_marginBottom="24dp"
+                    android:gravity="center_vertical"/>
+
+                <ImageView
+                    android:id="@+id/fingerprintIcon"
+                    android:layout_gravity="center_horizontal"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:contentDescription="@string/confirm_fingerprint_icon_content_description"
+                    android:visibility="gone"/>
+            </LinearLayout>
+
+        </ScrollView>
+
+        <FrameLayout
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1">
+
+            <com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"
+                android:background="@color/lock_pattern_background" />
+
+        </FrameLayout>
+
+    </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout/confirm_lock_password_internal.xml b/res/layout/confirm_lock_password_internal.xml
new file mode 100644
index 0000000..e22d764
--- /dev/null
+++ b/res/layout/confirm_lock_password_internal.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<com.android.setupwizardlib.GlifLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/setup_wizard_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:icon="@drawable/ic_lock"
+    android:layout="@layout/suw_glif_blank_template">
+
+    <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+        android:id="@+id/topLayout"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <ImageView
+            android:id="@+id/suw_layout_icon"
+            style="@style/SuwGlifIcon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_lock" />
+
+        <TextView
+            android:id="@+id/headerText"
+            style="@style/SuwGlifHeaderTitle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+        <TextView
+            android:id="@+id/detailsText"
+            style="@style/SuwDescription.Glif"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="?attr/suwMarginSides"
+            android:layout_marginEnd="?attr/suwMarginSides" />
+
+        <Button
+            style="@style/SetupWizardButton.Negative"
+            android:id="@+id/cancelButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/cancel" />
+
+        <Space
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+
+        <EditText
+            android:id="@+id/password_entry"
+            android:layout_width="208dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="-40dp"
+            android:inputType="textPassword"
+            android:imeOptions="actionNext|flagNoFullscreen"
+            android:gravity="center"
+            android:textSize="16sp"
+            style="@style/TextAppearance.PasswordEntry"/>
+
+        <TextView
+            style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+            android:accessibilityLiveRegion="polite"
+            android:id="@+id/errorText"
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginStart="12dp"
+            android:layout_marginEnd="12dp"
+            android:gravity="center_vertical"/>
+
+        <ImageView
+            android:id="@+id/fingerprintIcon"
+            android:layout_gravity="center_horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_marginBottom="24dp"
+            android:contentDescription="@string/confirm_fingerprint_icon_content_description"
+            android:visibility="gone"/>
+
+    </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</com.android.setupwizardlib.GlifLayout>
\ No newline at end of file
diff --git a/res/layout/confirm_lock_pattern_internal_base.xml b/res/layout/confirm_lock_pattern_internal_base.xml
new file mode 100644
index 0000000..359b51b
--- /dev/null
+++ b/res/layout/confirm_lock_pattern_internal_base.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<com.android.setupwizardlib.GlifLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/setup_wizard_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:icon="@drawable/ic_lock"
+    android:layout="@layout/suw_glif_blank_template">
+
+    <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+        android:id="@+id/topLayout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="2">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="vertical">
+
+                <ImageView
+                    android:id="@+id/suw_layout_icon"
+                    style="@style/SuwGlifIcon"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:src="@drawable/ic_lock" />
+
+                <TextView
+                    android:id="@+id/headerText"
+                    style="@style/SuwGlifHeaderTitle"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" />
+
+                <TextView
+                    style="@style/SuwDescription.Glif"
+                    android:id="@+id/detailsText"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="?attr/suwMarginSides"
+                    android:layout_marginEnd="?attr/suwMarginSides" />
+
+                <Button
+                    android:id="@+id/cancelButton"
+                    style="@style/SetupWizardButton.Negative"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="?attr/suwMarginSides"
+                    android:layout_marginEnd="?attr/suwMarginSides"
+                    android:text="@string/cancel" />
+
+            </LinearLayout>
+
+        </ScrollView>
+
+        <com.android.internal.widget.LockPatternView
+            android:id="@+id/lockPattern"
+            android:layout_width="312dp"
+            android:layout_height="0dp"
+            android:layout_weight="3"
+            android:layout_gravity="center_horizontal"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:orientation="vertical">
+
+            <TextView
+                style="@style/TextAppearance.ConfirmDeviceCredentialsErrorText"
+                android:accessibilityLiveRegion="polite"
+                android:id="@+id/errorText"
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginTop="12dp"
+                android:layout_marginStart="12dp"
+                android:layout_marginEnd="12dp"
+                android:gravity="center_vertical"/>
+
+            <ImageView
+                android:id="@+id/fingerprintIcon"
+                android:layout_gravity="center_horizontal"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentBottom="true"
+                android:layout_marginBottom="24dp"
+                android:contentDescription="@string/confirm_fingerprint_icon_content_description"
+                android:visibility="gone"/>
+        </LinearLayout>
+
+    </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/values-sw600dp/aliases.xml b/res/values-sw600dp/aliases.xml
index 163e97a..86f2da5 100644
--- a/res/values-sw600dp/aliases.xml
+++ b/res/values-sw600dp/aliases.xml
@@ -20,5 +20,6 @@
      <item name="fingerprint_enroll_enrolling" type="layout">@layout/fingerprint_enroll_enrolling_base</item>
      <item name="fingerprint_enroll_finish" type="layout">@layout/fingerprint_enroll_finish_base</item>
      <item name="choose_lock_pattern" type="layout">@layout/choose_lock_pattern_common</item>
+     <item name="confirm_lock_pattern_internal" type="layout">@layout/confirm_lock_pattern_internal_base</item>
 </resources>
 
diff --git a/res/values/aliases.xml b/res/values/aliases.xml
index 951b1bb..8c4858d 100644
--- a/res/values/aliases.xml
+++ b/res/values/aliases.xml
@@ -17,6 +17,7 @@
 <resources>
      <item name="notification_app_section" type="layout">@*android:layout/preference_category_material</item>
      <item name="confirm_lock_pattern" type="layout">@layout/confirm_lock_pattern_base</item>
+     <item name="confirm_lock_pattern_internal" type="layout">@layout/confirm_lock_pattern_internal_base</item>
      <item name="confirm_lock_password" type="layout">@layout/confirm_lock_password_base</item>
      <item name="fingerprint_enroll_find_sensor" type="layout">@layout/fingerprint_enroll_find_sensor_base</item>
      <item name="fingerprint_enroll_enrolling" type="layout">@layout/fingerprint_enroll_enrolling_base</item>
diff --git a/res/values/config.xml b/res/values/config.xml
index 0fa2b71..f81bf9b 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -67,4 +67,36 @@
     <!-- If the support features are enabled. -->
     <bool name="config_support_enabled">false</bool>
 
+    <!-- List containing the component names of pre-installed screen reader services. -->
+    <string-array name="config_preinstalled_screen_reader_services" translatable="false">
+        <!--
+        <item>com.example.package.first/com.example.class.FirstService</item>
+        <item>com.example.package.second/com.example.class.SecondService</item>
+        -->
+    </string-array>
+
+    <!-- List containing the component names of pre-installed audio and captioning services. -->
+    <string-array name="config_preinstalled_audio_and_caption_services" translatable="false">
+        <!--
+        <item>com.example.package.first/com.example.class.FirstService</item>
+        <item>com.example.package.second/com.example.class.SecondService</item>
+        -->
+    </string-array>
+
+    <!-- List containing the component names of pre-installed display services. -->
+    <string-array name="config_preinstalled_display_services" translatable="false">
+        <!--
+        <item>com.example.package.first/com.example.class.FirstService</item>
+        <item>com.example.package.second/com.example.class.SecondService</item>
+        -->
+    </string-array>
+
+    <!-- List containing the component names of pre-installed interaction control services. -->
+    <string-array name="config_preinstalled_interaction_control_services" translatable="false">
+        <!--
+        <item>com.example.package.first/com.example.class.FirstService</item>
+        <item>com.example.package.second/com.example.class.SecondService</item>
+        -->
+    </string-array>
+
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 79042c4..bff3170 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2961,7 +2961,7 @@
     <!-- Tethering controls, item title to go into the tethering settings when USB and Bluetooth tethering are available [CHAR LIMIT=25]-->
     <string name="tether_settings_title_usb_bluetooth">Tethering</string>
     <!-- Tethering controls, item title to go into the tethering settings when USB, Bluetooth and Wifi tethering are available [CHAR LIMIT=50]-->
-    <string name="tether_settings_title_all">Hotspot &amp; Tethering</string>
+    <string name="tether_settings_title_all">Hotspot &amp; tethering</string>
     <!-- Tethering setting summary when both Wi-Fi hotspot and tether are turned on [CHAR LIMIT=NONE]-->
     <string name="tether_settings_summary_hotspot_on_tether_on">Hotspot on, tethering</string>
     <!-- Tethering setting summary when Wi-Fi hotspot is on and tether is off [CHAR LIMIT=NONE]-->
@@ -3019,7 +3019,7 @@
     <string name="tethering_help_button_text">Help</string>
 
     <!-- Wireless controls, item title to go into the network settings -->
-    <string name="network_settings_title">Mobile networks</string>
+    <string name="network_settings_title">Mobile network</string>
 
     <!-- Mobile plan [CHAR LIMIT=35]-->
     <string name="manage_mobile_plan_title" translatable="true">Mobile plan</string>
@@ -3997,22 +3997,30 @@
     <string name="vision_settings_title">Vision Settings</string>
     <!-- Settings description for a brief version of Vision-Related Accessibility Settings. Tells the user that they can adjust these settings now to help them through the remainder of the Setup Wizard and that they can later be changed in Settings. Displayed in Setup Wizard only. [CHAR LIMIT=none] -->
     <string name="vision_settings_description">You can customize this device to fit your needs. These accessibility features can be changed later in Settings.</string>
-    <!-- Title for the accessibility preference category of accessibility services. [CHAR LIMIT=25] -->
-    <string name="accessibility_services_title">Services</string>
+    <!-- Title for the accessibility preference category of screen reader services and settings. [CHAR LIMIT=50] -->
+    <string name="screen_reader_category_title">Screen readers</string>
+    <!-- Title for the accessibility preference category of audio services and settings. [CHAR LIMIT=50] -->
+    <string name="audio_and_captions_category_title">Audio &amp; on-screen text</string>
+    <!-- Title for the accessibility preference category of display services and settings. [CHAR LIMIT=50] -->
+    <string name="display_category_title">Display</string>
+    <!-- Title for the accessibility preference category of interaction control services and settings. [CHAR LIMIT=50] -->
+    <string name="interaction_control_category_title">Interaction controls</string>
+    <!-- Title for the accessibility preference category of services downloaded by the user. [CHAR LIMIT=50] -->
+    <string name="user_installed_services_category_title">Downloaded services</string>
+    <!-- Title for the accessibility preference category of settings considered to be experimental, meaning they might be changed or removed in the future. [CHAR LIMIT=50] -->
+    <string name="experimental_category_title">Experimental</string>
     <!-- Title for the Talkback Accessibility Service. Displayed on the Accessibility Settings screen in Setup Wizard. [CHAR_LIMIT=25] -->
     <string name="talkback_title">Talkback</string>
     <!-- Summary for the Talkback Accessibility Service. Lets the user know that Talkback is a screenreader and that it is usually most helpful to blind and low vision users and whether the service is on. [CHAR_LIMIT=none] -->
     <string name="talkback_summary">Screen reader primarily for people with blindness and low vision</string>
     <!-- Summary for the Select to Speak Accessibility Service. [CHAR_LIMIT=none] -->
     <string name="select_to_speak_summary">Tap items on your screen to hear them read aloud</string>
-    <!-- Title for the accessibility preference category of system related preferences. [CHAR LIMIT=25] -->
-    <string name="accessibility_system_title">System</string>
-    <!-- Title for the accessibility preference category of display related preferences. [CHAR LIMIT=25] -->
-    <string name="accessibility_display_title">Display</string>
     <!-- Title for the accessibility preference screen to enable video captioning. [CHAR LIMIT=35] -->
     <string name="accessibility_captioning_title">Captions</string>
     <!-- Title for the accessibility preference screen to enable screen magnification. [CHAR LIMIT=35] -->
-    <string name="accessibility_screen_magnification_title">Magnification gesture</string>
+    <string name="accessibility_screen_magnification_title">Magnification</string>
+    <!-- Summary for the accessibility preference to enable screen magnification. [CHAR LIMIT=25] -->
+    <string name="accessibility_preference_magnification_summary">Zoom in on screen</string>
     <!-- Short summary for Magnification gesture. Tells the user that this feature allows the user to magnify the screen by tapping 3 times. Appears in accessibility portion of setup wizard -->
     <string name="accessibility_screen_magnification_short_summary">Tap 3 times to zoom</string>
     <!-- Summary for the accessibility preference screen to enable screen magnification. [CHAR LIMIT=none] -->
@@ -4040,7 +4048,7 @@
     <!-- Title for the accessibility preference to configure display color inversion. [CHAR LIMIT=NONE] -->
     <string name="accessibility_display_inversion_preference_title">Color inversion</string>
     <!-- Subtitle for the accessibility preference to configure display color inversion. [CHAR LIMIT=NONE] -->
-    <string name="accessibility_display_inversion_preference_subtitle">(Experimental) May affect performance</string>
+    <string name="accessibility_display_inversion_preference_subtitle">May affect performance</string>
     <!-- Title for accessibility preference for configuring feature that performs click action soon after mouse/trackpad pointer stops moving. [CHAR LIMIT=NONE] -->
     <string name="accessibility_autoclick_preference_title">Click after pointer stops moving</string>
     <!-- Title for accessibility preference for configuring amount of time that has to pass after pointer stops moving before click action can be performed (if automatic click after pointer stops moving feature is enabled). [CHAR LIMIT=NONE] -->
@@ -4199,10 +4207,10 @@
     <string name="disable_service_message">Tapping OK will
         stop <xliff:g id="service" example="TalkBack">%1$s</xliff:g>.</string>
 
-    <!-- Title for the prompt shown as a placeholder if no accessibility serivices are installed. [CHAR LIMIT=50] -->
+    <!-- Title for the prompt shown as a placeholder if no accessibility services are installed. [CHAR LIMIT=50] -->
     <string name="accessibility_no_services_installed">No services installed</string>
 
-    <!-- Default description for an accessibility serivice if the latter doesn't provide one. [CHAR LIMIT=NONE] -->
+    <!-- Default description for an accessibility service if the latter doesn't provide one. [CHAR LIMIT=NONE] -->
     <string name="accessibility_service_default_description">No description provided.</string>
 
     <!-- Accessibility settings: button for lauching settings for an accessibility service -->
@@ -4223,7 +4231,7 @@
     <!-- Title for print service settings screen [CHAR LIMIT=25] -->
     <string name="print_settings_title">Print services</string>
 
-    <!-- Title for the prompt shown as a placeholder if no print serivices are installed. [CHAR LIMIT=50] -->
+    <!-- Title for the prompt shown as a placeholder if no print services are installed. [CHAR LIMIT=50] -->
     <string name="print_no_services_installed">No services installed</string>
 
     <!-- Title for the prompt shown as a placeholder if no printers are found while searching. [CHAR LIMIT=50] -->
@@ -5470,6 +5478,8 @@
     <string name="vpn_no_network">There is no network connection. Please try again later.</string>
     <!-- Toast message when VPN has disconnected automatically due to Clear credentials. [CHAR LIMIT=NONE] -->
     <string name="vpn_disconnected">Disconnected from VPN</string>
+    <!-- Seting subtext indicating the device is not currently connected to any VPN [CHAR LIMIT=40]-->
+    <string name="vpn_disconnected_summary">None</string>
     <!-- Toast message when a certificate is missing. [CHAR LIMIT=100] -->
     <string name="vpn_missing_cert">A certificate is missing. Please edit the profile.</string>
 
@@ -6465,8 +6475,14 @@
     <!-- [CHAR LIMIT=NONE] App notification settings: no channels -->
     <string name="no_channels">This app has not posted any notifications</string>
 
-    <!-- [CHAR LIMIT=60] App notification settings: Text to display for deleted channels -->
-    <string name="deleted_channel_name"><xliff:g id="channel_name" example="Promotions">%1$s</xliff:g> (deleted)</string>
+    <!-- [CHAR LIMIT=NONE] App notification settings: link to app notification settings-->
+    <string name="app_settings_link">Additional settings in the app</string>
+
+    <!-- [CHAR LIMIT=NONE] Footer listing a count of deleted channels. -->
+    <plurals name="deleted_channels">
+        <item quantity="one">%d category deleted</item>
+        <item quantity="other">%d categories deleted</item>
+    </plurals>
 
     <!-- [CHAR LIMIT=NONE] App notification settings: Block option title -->
     <string name="app_notification_block_title">Block all</string>
@@ -7178,7 +7194,7 @@
     <!-- Title of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for transferring files via MTP. -->
-    <string name="usb_use_file_transfers">Transfer files</string>
+    <string name="usb_use_file_transfers">Transferring files</string>
     <!-- Description of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for transferring files via MTP. -->
@@ -7186,7 +7202,7 @@
     <!-- Title of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for transferring photos via PTP. -->
-    <string name="usb_use_photo_transfers">Transfer photos (PTP)</string>
+    <string name="usb_use_photo_transfers">Transferring photos (PTP)</string>
     <!-- Description of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for transferring photos via PTP. -->
@@ -7194,7 +7210,7 @@
     <!-- Title of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for entering MIDI mode. -->
-    <string name="usb_use_MIDI">Use device as MIDI</string>
+    <string name="usb_use_MIDI">Using device as MIDI</string>
     <!-- Description of one of the choices in a dialog (with title defined in usb_use) that lets the user
          select what the USB connection for this device should be used for. This choice
          is for entering MIDI mode. -->
@@ -7206,8 +7222,6 @@
 
     <!-- Settings item title for USB preference [CHAR LIMIT=35] -->
     <string name="usb_pref">USB</string>
-    <!-- Summary for the USB preference when nothing is connected through the usb port.  [CHAR LIMIT=40] -->
-    <string name="usb_nothing_connected">Nothing connected</string>
 
     <!-- Settings item title for background check prefs [CHAR LIMIT=35] -->
     <string name="background_check_pref">Background check</string>
@@ -7332,38 +7346,38 @@
     <string name="accessibility_lock_screen_progress"><xliff:g id="count" example="1">%1$d</xliff:g> of <xliff:g id="count" example="1">%2$d</xliff:g> characters used</string>
 
     <!-- System Alert Window settings -->
-    <!-- Title of Draw Overlay preference item [CHAR LIMIT=55] -->
-    <string name="draw_overlay_title">Apps that can draw over other apps</string>
-    <!-- Title of draw overlay screen [CHAR LIMIT=30] -->
-    <string name="draw_overlay">Draw over other apps</string>
+    <!-- Title of display overlay preference item [CHAR LIMIT=55] -->
+    <string name="draw_overlay_title">Apps that can display over other apps</string>
+    <!-- Title of display overlay screen [CHAR LIMIT=30] -->
+    <string name="draw_overlay">Display over other apps</string>
     <!-- Settings title in main settings screen for SYSTEM_ALERT_WINDOW [CHAR LIMIT=45] -->
-    <string name="system_alert_window_settings">Draw over other apps</string>
+    <string name="system_alert_window_settings">Display over other apps</string>
     <!-- Title for the apps with SYSTEM_ALERT_WINDOW permission/privilege [CHAR LIMIT=20] -->
     <string name="system_alert_window_apps_title">Apps</string>
-    <!-- Title for the apps that are allowed to draw on top of other apps [CHAR LIMIT=60] -->
-    <string name="system_alert_window_access_title">Draw over other apps</string>
-    <!-- Label for setting which controls whether app can draw overlays [CHAR LIMIT=45] -->
-    <string name="permit_draw_overlay">Permit drawing over other apps</string>
+    <!-- Title for the apps that are allowed to display over other apps [CHAR LIMIT=60] -->
+    <string name="system_alert_window_access_title">Display over other apps</string>
+    <!-- Label for setting which controls whether app can display over other apps [CHAR LIMIT=45] -->
+    <string name="permit_draw_overlay">Allow display over other apps</string>
     <!-- Link to the apps page for SYSTEM_ALERT_WINDOW settings [CHAR LIMIT=45] -->
-    <string name="app_overlay_permission_preference">App draw on top permission</string>
+    <string name="app_overlay_permission_preference">App display on top permission</string>
     <!-- Description of allowing overlay setting [CHAR LIMIT=NONE] -->
-    <string name="allow_overlay_description">This permission allows an app to display on top of other apps you\u2019re using and may interfere with your use of the interface in other applications, or change what you think you are seeing in other applications.</string>
+    <string name="allow_overlay_description">This feature allows an app to display on top of other apps you\u2019re using. It may interfere with your use of those apps or change the way they seem to appear or behave.</string>
 
     <!-- Keyword for VR setting -->
     <string name="keywords_vr_listener">vr virtual reality listener stereo helper service</string>
     <!-- Keyword for SYSTEM_ALERT_WINDOW -->
-    <string name="keywords_system_alert_window">system alert window dialog draw on top other apps</string>
+    <string name="keywords_system_alert_window">system alert window dialog display on top other apps</string>
     <!-- Main settings screen item's title to go into the overlay settings screen [CHAR LIMIT=30] -->
-    <string name="overlay_settings">Draw over other apps</string>
+    <string name="overlay_settings">Display over other apps</string>
 
-    <!-- Summary of number of apps currently can draw overlays [CHAR LIMIT=60] -->
-    <string name="system_alert_window_summary"><xliff:g id="count" example="10">%1$d</xliff:g> of <xliff:g id="count" example="10">%2$d</xliff:g> apps allowed to draw on top of other apps</string>
+    <!-- Summary of number of apps currently can display over other apps [CHAR LIMIT=60] -->
+    <string name="system_alert_window_summary"><xliff:g id="count" example="10">%1$d</xliff:g> of <xliff:g id="count" example="10">%2$d</xliff:g> apps allowed to display over other apps</string>
 
-    <!-- Label for showing apps that can draw overlays [CHAR LIMIT=45] -->
+    <!-- Label for showing apps that can display over other apps [CHAR LIMIT=45] -->
     <string name="filter_overlay_apps">Apps with permission</string>
-    <!-- Summary of app allowed to draw overlay [CHAR LIMIT=60] -->
+    <!-- Summary of app allowed to display over other apps [CHAR LIMIT=60] -->
     <string name="system_alert_window_on">Yes</string>
-    <!-- Summary of app not allowed to draw overlay [CHAR LIMIT=60] -->
+    <!-- Summary of app not allowed to display over other apps [CHAR LIMIT=60] -->
     <string name="system_alert_window_off">No</string>
 
     <!-- Title for settings screen for controlling apps that can install other apps on device [CHAR LIMIT=50] -->
@@ -7376,7 +7390,7 @@
     <string name="write_settings">Modify system settings</string>
     <!-- Keyword for WRITE_SETTINGS -->
     <string name="keywords_write_settings">write modify system settings</string>
-    <!-- Summary of number of apps currently can draw overlays [CHAR LIMIT=60] -->
+    <!-- Summary of number of apps currently can write system settings [CHAR LIMIT=60] -->
     <string name="write_settings_summary"><xliff:g id="count" example="10">%1$d</xliff:g> of <xliff:g id="count" example="10">%2$d</xliff:g> apps allowed to modify system settings</string>
 
     <!-- Label for showing apps that can install other apps [CHAR LIMIT=45] -->
@@ -7453,7 +7467,7 @@
     <string name="screen_zoom_conversation_timestamp_4">Tue 6:03PM</string>
 
     <!-- Wi-Fi state - Disconnected [CHAR LIMIT=NONE] -->
-    <string name="disconnected">Disconnected</string>
+    <string name="disconnected">Not connected</string>
 
     <!-- Summary of data usage [CHAR LIMIT=NONE] -->
     <string name="data_usage_summary_format"><xliff:g id="amount" example="50%">%1$s</xliff:g> of data used</string>
@@ -7866,8 +7880,8 @@
     <!-- Title of screen controlling which apps have access to send premium SMS messages [CHAR LIMIT=60] -->
     <string name="premium_sms_access">Premium SMS access</string>
 
-    <!-- [CHAR LIMIT=25] Bluetooth is disabled. -->
-    <string name="bluetooth_disabled">Disabled</string>
+    <!-- Bluetooth is disabled. -->
+    <string name="bluetooth_disabled">Not visible to other devices</string>
 
     <!-- [CHAR LIMIT=60] Name of dev option called "System UI demo mode" -->
     <string name="demo_mode">System UI demo mode</string>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 99e2133..7ca109b 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -77,6 +77,10 @@
         <item name="android:windowAnimationStyle">@null</item>
     </style>
 
+    <style name="SuwSuggestionThemeGlif.Light" parent="SuwThemeGlif.Light">
+        <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>
+    </style>
+
     <style name="PreferenceTheme" parent="@style/PreferenceThemeOverlay.v14.Material">
         <!-- Parent path frameworks/support/v14/preference/res/values/themes.xml -->
         <item name="android:scrollbars">vertical</item>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index ee21017..5c67d6e 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -18,43 +18,61 @@
         android:title="@string/accessibility_settings"
         android:persistent="true">
 
+    <ListPreference
+            android:key="accessibility_shortcut_preference"
+            android:title="@string/accessibility_global_gesture_preference_title"/>
+
     <PreferenceCategory
-            android:key="services_category"
-            android:title="@string/accessibility_services_title">
+            android:key="user_installed_services_category"
+            android:title="@string/user_installed_services_category_title">
     </PreferenceCategory>
 
     <PreferenceCategory
-            android:key="system_category"
-            android:title="@string/accessibility_system_title">
+            android:key="screen_reader_category"
+            android:title="@string/screen_reader_category_title">
 
         <Preference
-            android:fragment="com.android.settings.accessibility.CaptionPropertiesFragment"
-            android:key="captioning_preference_screen"
-            android:title="@string/accessibility_captioning_title" />
+                android:key="tts_settings_preference"
+                android:fragment="com.android.settings.tts.TextToSpeechSettings"
+                android:title="@string/tts_settings_title"/>
+    </PreferenceCategory>
+
+    <PreferenceCategory
+            android:key="display_category"
+            android:title="@string/display_category_title">
 
         <Preference
-            android:fragment="com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment"
-            android:key="screen_magnification_preference_screen"
-            android:title="@string/accessibility_screen_magnification_title"/>
-
-        <Preference
-            android:fragment="com.android.settings.accessibility.ToggleFontSizePreferenceFragment"
-            android:key="font_size_preference_screen"
-            android:title="@string/title_font_size"/>
+                android:fragment="com.android.settings.accessibility.ToggleFontSizePreferenceFragment"
+                android:key="font_size_preference_screen"
+                android:title="@string/title_font_size"/>
 
         <com.android.settings.display.ScreenZoomPreference
-            android:key="screen_zoom"
-            android:title="@string/screen_zoom_title"/>
+                android:key="screen_zoom"
+                android:title="@string/screen_zoom_title"/>
 
         <Preference
-            android:fragment="com.android.settings.accessibility.ToggleAutoclickPreferenceFragment"
-            android:key="autoclick_preference_screen"
-            android:title="@string/accessibility_autoclick_preference_title"/>
+                android:fragment="com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment"
+                android:key="screen_magnification_preference_screen"
+                android:title="@string/accessibility_screen_magnification_title" />
+
+        <Preference
+                android:fragment="com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment"
+                android:key="daltonizer_preference_screen"
+                android:title="@string/accessibility_display_daltonizer_preference_title" />
 
         <SwitchPreference
-                android:key="toggle_high_text_contrast_preference"
-                android:title="@string/accessibility_toggle_high_text_contrast_preference_title"
-                android:summary="@string/experimental_preference"/>
+                android:key="toggle_large_pointer_icon"
+                android:title="@string/accessibility_toggle_large_pointer_icon_title" />
+    </PreferenceCategory>
+
+    <PreferenceCategory
+            android:key="interaction_control_category"
+            android:title="@string/interaction_control_category_title">
+
+        <Preference
+                android:fragment="com.android.settings.accessibility.ToggleAutoclickPreferenceFragment"
+                android:key="autoclick_preference_screen"
+                android:title="@string/accessibility_autoclick_preference_title"/>
 
         <SwitchPreference
                 android:key="toggle_power_button_ends_call_preference"
@@ -66,9 +84,17 @@
                 android:title="@string/accelerometer_title"
                 android:persistent="false"/>
 
-        <SwitchPreference
-                android:key="toggle_large_pointer_icon"
-                android:title="@string/accessibility_toggle_large_pointer_icon_title" />
+        <ListPreference
+                android:key="select_long_press_timeout_preference"
+                android:title="@string/accessibility_long_press_timeout_preference_title"
+                android:entries="@array/long_press_timeout_selector_titles"
+                android:entryValues="@array/long_press_timeout_selector_values"
+                android:persistent="false"/>
+    </PreferenceCategory>
+
+    <PreferenceCategory
+            android:key="audio_and_captions_category"
+            android:title="@string/audio_and_captions_category_title">
 
         <SwitchPreference
                 android:key="toggle_master_mono"
@@ -76,35 +102,24 @@
                 android:summary="@string/accessibility_toggle_master_mono_summary"
                 android:persistent="false"/>
 
-        <ListPreference
-                android:key="accessibility_shortcut_preference"
-                android:title="@string/accessibility_global_gesture_preference_title"/>
-
         <Preference
-                android:key="tts_settings_preference"
-                android:fragment="com.android.settings.tts.TextToSpeechSettings"
-                android:title="@string/tts_settings_title"/>
-
-        <ListPreference android:key="select_long_press_timeout_preference"
-                android:title="@string/accessibility_long_press_timeout_preference_title"
-                android:entries="@array/long_press_timeout_selector_titles"
-                android:entryValues="@array/long_press_timeout_selector_values"
-                android:persistent="false"/>
-
+                android:fragment="com.android.settings.accessibility.CaptionPropertiesFragment"
+                android:key="captioning_preference_screen"
+                android:title="@string/accessibility_captioning_title" />
     </PreferenceCategory>
 
     <PreferenceCategory
-        android:key="display_category"
-        android:title="@string/accessibility_display_title" >
-        <SwitchPreference
-            android:key="toggle_inversion_preference"
-            android:title="@string/accessibility_display_inversion_preference_title"
-            android:summary="@string/accessibility_display_inversion_preference_subtitle"
-            android:persistent="false" />
-        <Preference
-            android:fragment="com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment"
-            android:key="daltonizer_preference_screen"
-            android:title="@string/accessibility_display_daltonizer_preference_title" />
-    </PreferenceCategory>
+            android:key="experimental_category"
+            android:title="@string/experimental_category_title">
 
+        <SwitchPreference
+                android:key="toggle_high_text_contrast_preference"
+                android:title="@string/accessibility_toggle_high_text_contrast_preference_title" />
+
+        <SwitchPreference
+                android:key="toggle_inversion_preference"
+                android:title="@string/accessibility_display_inversion_preference_title"
+                android:summary="@string/accessibility_display_inversion_preference_subtitle"
+                android:persistent="false" />
+    </PreferenceCategory>
 </PreferenceScreen>
diff --git a/res/xml/channel_notification_settings.xml b/res/xml/channel_notification_settings.xml
index 4af9fe8..fde1bfa 100644
--- a/res/xml/channel_notification_settings.xml
+++ b/res/xml/channel_notification_settings.xml
@@ -23,29 +23,25 @@
         android:key="block"
         android:title="@string/app_notification_block_title"
         android:summary="@string/app_notification_block_summary"
-        android:order="1"
         settings:useAdditionalSummary="true"
         settings:restrictedSwitchSummary="@string/enabled_by_admin" />
 
     <!-- Importance -->
     <com.android.settings.notification.RestrictedDropDownPreference
         android:key="importance"
-        android:title="@string/notification_importance_title"
-        android:order="2"/>
+        android:title="@string/notification_importance_title" />
 
     <!-- Default ringtone -->
     <com.android.settings.notification.DefaultNotificationTonePreference
         android:key="ringtone"
         android:title="@string/notification_ringtone_title"
         android:dialogTitle="@string/notification_ringtone_title"
-        android:order="3"
         android:ringtoneType="notification" />
 
     <!-- Vibration -->
     <com.android.settingslib.RestrictedSwitchPreference
         android:key="vibrate"
         android:title="@string/notification_vibrate_title"
-        android:order="4"
         settings:useAdditionalSummary="true" />
 
     <!-- Show badge -->
@@ -53,7 +49,6 @@
         android:key="badge"
         android:title="@string/notification_badge_title"
         android:summary="@string/notification_badge_summary"
-        android:order="5"
         settings:useAdditionalSummary="true"
         settings:restrictedSwitchSummary="@string/enabled_by_admin" />
 
@@ -61,21 +56,18 @@
     <com.android.settingslib.RestrictedSwitchPreference
         android:key="lights"
         android:title="@string/notification_show_lights_title"
-        android:order="6"
         settings:useAdditionalSummary="true" />
 
     <!-- Visibility Override -->
     <com.android.settings.notification.RestrictedDropDownPreference
             android:key="visibility_override"
-            android:title="@string/app_notification_visibility_override_title"
-            android:order="7" />
+            android:title="@string/app_notification_visibility_override_title" />
 
     <!-- Bypass DND -->
     <com.android.settingslib.RestrictedSwitchPreference
             android:key="bypass_dnd"
             android:title="@string/app_notification_override_dnd_title"
             android:summary="@string/app_notification_override_dnd_summary"
-            android:order="8"
             settings:useAdditionalSummary="true" />
 
 </PreferenceScreen>
diff --git a/src/com/android/settings/ConfirmDeviceCredentialBaseActivity.java b/src/com/android/settings/ConfirmDeviceCredentialBaseActivity.java
index e8880ae..489dbbe 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialBaseActivity.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialBaseActivity.java
@@ -22,16 +22,23 @@
 import android.os.UserManager;
 import android.view.MenuItem;
 import android.view.WindowManager;
+import android.widget.LinearLayout;
 
 public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivity {
 
     private static final String STATE_IS_KEYGUARD_LOCKED = "STATE_IS_KEYGUARD_LOCKED";
 
+    enum ConfirmCredentialTheme {
+        INTERNAL,
+        DARK,
+        WORK
+    }
+
     private boolean mRestoring;
-    private boolean mDark;
     private boolean mEnterAnimationPending;
     private boolean mFirstTimeVisible = true;
     private boolean mIsKeyguardLocked = false;
+    private ConfirmCredentialTheme mConfirmCredentialTheme;
 
     @Override
     protected void onCreate(Bundle savedState) {
@@ -39,12 +46,24 @@
                 Utils.getUserIdFromBundle(this, getIntent().getExtras()));
         if (UserManager.get(this).isManagedProfile(credentialOwnerUserId)) {
             setTheme(R.style.Theme_ConfirmDeviceCredentialsWork);
+            mConfirmCredentialTheme = ConfirmCredentialTheme.WORK;
         } else if (getIntent().getBooleanExtra(
                 ConfirmDeviceCredentialBaseFragment.DARK_THEME, false)) {
             setTheme(R.style.Theme_ConfirmDeviceCredentialsDark);
-            mDark = true;
+            mConfirmCredentialTheme = ConfirmCredentialTheme.DARK;
+        } else {
+            setTheme(R.style.SetupWizardTheme_Light);
+            mConfirmCredentialTheme = ConfirmCredentialTheme.INTERNAL;
         }
         super.onCreate(savedState);
+
+        if (mConfirmCredentialTheme == ConfirmCredentialTheme.INTERNAL) {
+            // Prevent the content parent from consuming the window insets because GlifLayout uses
+            // it to show the status bar background.
+            LinearLayout layout = (LinearLayout) findViewById(R.id.content_parent);
+            layout.setFitsSystemWindows(false);
+        }
+
         mIsKeyguardLocked = savedState == null
                 ? getSystemService(KeyguardManager.class).isKeyguardLocked()
                 : savedState.getBoolean(STATE_IS_KEYGUARD_LOCKED, false);
@@ -85,7 +104,8 @@
     @Override
     public void onResume() {
         super.onResume();
-        if (!isChangingConfigurations() && !mRestoring && mDark && mFirstTimeVisible) {
+        if (!isChangingConfigurations() && !mRestoring
+                && mConfirmCredentialTheme == ConfirmCredentialTheme.DARK && mFirstTimeVisible) {
             mFirstTimeVisible = false;
             prepareEnterAnimation();
             mEnterAnimationPending = true;
@@ -116,4 +136,8 @@
     public void startEnterAnimation() {
         getFragment().startEnterAnimation();
     }
+
+    public ConfirmCredentialTheme getConfirmCredentialTheme() {
+        return mConfirmCredentialTheme;
+    }
 }
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
index 6b55add..5c86dcd 100644
--- a/src/com/android/settings/ConfirmLockPassword.java
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -122,7 +122,14 @@
                 Bundle savedInstanceState) {
             final int storedQuality = mLockPatternUtils.getKeyguardStoredPasswordQuality(
                     mEffectiveUserId);
-            View view = inflater.inflate(R.layout.confirm_lock_password, null);
+
+            ConfirmLockPassword activity = (ConfirmLockPassword) getActivity();
+            View view = inflater.inflate(
+                    activity.getConfirmCredentialTheme() == ConfirmCredentialTheme.INTERNAL
+                            ? R.layout.confirm_lock_password_internal
+                            : R.layout.confirm_lock_password,
+                    container,
+                    false);
 
             mPasswordEntry = (TextView) view.findViewById(R.id.password_entry);
             mPasswordEntry.setOnEditorActionListener(this);
@@ -406,25 +413,22 @@
             }
             mDisappearing = true;
 
-            if (getActivity().getThemeResId() == R.style.Theme_ConfirmDeviceCredentialsDark) {
-                mDisappearAnimationUtils.startAnimation(getActiveViews(), new Runnable() {
-                    @Override
-                    public void run() {
-                        // Bail if there is no active activity.
-                        if (getActivity() == null || getActivity().isFinishing()) {
-                            return;
-                        }
-
-                        getActivity().setResult(RESULT_OK, intent);
-                        getActivity().finish();
-                        getActivity().overridePendingTransition(
-                                R.anim.confirm_credential_close_enter,
-                                R.anim.confirm_credential_close_exit);
-                    }
+            final ConfirmLockPassword activity = (ConfirmLockPassword) getActivity();
+            // Bail if there is no active activity.
+            if (activity == null || activity.isFinishing()) {
+                return;
+            }
+            if (activity.getConfirmCredentialTheme() == ConfirmCredentialTheme.DARK) {
+                mDisappearAnimationUtils.startAnimation(getActiveViews(), () -> {
+                    activity.setResult(RESULT_OK, intent);
+                    activity.finish();
+                    activity.overridePendingTransition(
+                            R.anim.confirm_credential_close_enter,
+                            R.anim.confirm_credential_close_exit);
                 });
             } else {
-                getActivity().setResult(RESULT_OK, intent);
-                getActivity().finish();
+                activity.setResult(RESULT_OK, intent);
+                activity.finish();
             }
         }
 
diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java
index a224ac8..4b65163 100644
--- a/src/com/android/settings/ConfirmLockPattern.java
+++ b/src/com/android/settings/ConfirmLockPattern.java
@@ -114,7 +114,13 @@
         @Override
         public View onCreateView(LayoutInflater inflater, ViewGroup container,
                 Bundle savedInstanceState) {
-            View view = inflater.inflate(R.layout.confirm_lock_pattern, null);
+            ConfirmLockPattern activity = (ConfirmLockPattern) getActivity();
+            View view = inflater.inflate(
+                    activity.getConfirmCredentialTheme() == ConfirmCredentialTheme.INTERNAL
+                            ? R.layout.confirm_lock_pattern_internal
+                            : R.layout.confirm_lock_pattern,
+                    container,
+                    false);
             mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
             mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
             mDetailsTextView = (TextView) view.findViewById(R.id.detailsText);
@@ -343,27 +349,24 @@
             }
             mDisappearing = true;
 
-            if (getActivity().getThemeResId() == R.style.Theme_ConfirmDeviceCredentialsDark) {
+            final ConfirmLockPattern activity = (ConfirmLockPattern) getActivity();
+            // Bail if there is no active activity.
+            if (activity == null || activity.isFinishing()) {
+                return;
+            }
+            if (activity.getConfirmCredentialTheme() == ConfirmCredentialTheme.DARK) {
                 mLockPatternView.clearPattern();
                 mDisappearAnimationUtils.startAnimation2d(getActiveViews(),
-                        new Runnable() {
-                            @Override
-                            public void run() {
-                                // Bail if there is no active activity.
-                                if (getActivity() == null || getActivity().isFinishing()) {
-                                    return;
-                                }
-
-                                getActivity().setResult(RESULT_OK, intent);
-                                getActivity().finish();
-                                getActivity().overridePendingTransition(
-                                        R.anim.confirm_credential_close_enter,
-                                        R.anim.confirm_credential_close_exit);
-                            }
+                        () -> {
+                            activity.setResult(RESULT_OK, intent);
+                            activity.finish();
+                            activity.overridePendingTransition(
+                                    R.anim.confirm_credential_close_enter,
+                                    R.anim.confirm_credential_close_exit);
                         }, this);
             } else {
-                getActivity().setResult(RESULT_OK, intent);
-                getActivity().finish();
+                activity.setResult(RESULT_OK, intent);
+                activity.finish();
             }
         }
 
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 807371e..86c340d 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -35,7 +36,9 @@
 import android.support.v7.preference.ListPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -46,18 +49,17 @@
 import com.android.internal.view.RotationPolicy.RotationPolicyListener;
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.SingleLineSummaryPreference;
 import com.android.settings.Utils;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settings.search.SearchIndexableRaw;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.settingslib.RestrictedPreference;
 import com.android.settingslib.accessibility.AccessibilityUtils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -68,9 +70,20 @@
 public class AccessibilitySettings extends SettingsPreferenceFragment implements
         Preference.OnPreferenceChangeListener, Indexable {
 
+    // Index of the first preference in a preference category.
+    private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = -1;
+
     // Preference categories
-    private static final String SERVICES_CATEGORY = "services_category";
-    private static final String SYSTEM_CATEGORY = "system_category";
+    private static final String CATEGORY_SCREEN_READER = "screen_reader_category";
+    private static final String CATEGORY_AUDIO_AND_CAPTIONS = "audio_and_captions_category";
+    private static final String CATEGORY_DISPLAY = "display_category";
+    private static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
+    private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
+
+    private static final String[] CATEGORIES = new String[] {
+        CATEGORY_SCREEN_READER, CATEGORY_AUDIO_AND_CAPTIONS, CATEGORY_DISPLAY,
+        CATEGORY_INTERACTION_CONTROL, CATEGORY_DOWNLOADED_SERVICES
+    };
 
     // Preferences
     private static final String TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE =
@@ -118,10 +131,7 @@
     // ID for dialog that confirms shortcut capabilities
     private static final int DIALOG_ID_ADD_SHORTCUT_WARNING = 1;
 
-    // Auxiliary members.
-    static final Set<ComponentName> sInstalledServices = new HashSet<>();
-
-    private final Map<String, String> mLongPressTimeoutValuetoTitleMap = new HashMap<>();
+    private final Map<String, String> mLongPressTimeoutValueToTitleMap = new HashMap<>();
 
     private final Handler mHandler = new Handler();
 
@@ -129,7 +139,7 @@
         @Override
         public void run() {
             if (getActivity() != null) {
-                updateServicesPreferences();
+                updateServicePreferences();
             }
         }
     };
@@ -164,7 +174,7 @@
             new SettingsContentObserver(mHandler) {
                 @Override
                 public void onChange(boolean selfChange, Uri uri) {
-                    updateServicesPreferences();
+                    updateServicePreferences();
                 }
             };
 
@@ -175,9 +185,12 @@
         }
     };
 
-    // Preference controls.
-    private PreferenceCategory mServicesCategory;
-    private PreferenceCategory mSystemsCategory;
+    private final Map<String, PreferenceCategory> mCategoryToPrefCategoryMap =
+            new ArrayMap<>();
+    private final Map<Preference, PreferenceCategory> mServicePreferenceToPreferenceCategoryMap =
+            new ArrayMap<>();
+    private final Map<ComponentName, PreferenceCategory> mPreBundledServiceComponentToCategoryMap =
+            new ArrayMap<>();
 
     private SwitchPreference mToggleHighTextContrastPreference;
     private SwitchPreference mTogglePowerButtonEndsCallPreference;
@@ -260,7 +273,7 @@
         Settings.Secure.putInt(getContentResolver(),
                 Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
         mSelectLongPressTimeoutPreference.setSummary(
-                mLongPressTimeoutValuetoTitleMap.get(stringValue));
+                mLongPressTimeoutValueToTitleMap.get(stringValue));
     }
 
     private void handleToggleInversionPreferenceChange(boolean checked) {
@@ -386,8 +399,10 @@
     }
 
     private void initializeAllPreferences() {
-        mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
-        mSystemsCategory = (PreferenceCategory) findPreference(SYSTEM_CATEGORY);
+        for (int i = 0; i < CATEGORIES.length; i++) {
+            PreferenceCategory prefCategory = (PreferenceCategory) findPreference(CATEGORIES[i]);
+            mCategoryToPrefCategoryMap.put(CATEGORIES[i], prefCategory);
+        }
 
         // Text contrast.
         mToggleHighTextContrastPreference =
@@ -402,14 +417,16 @@
                 (SwitchPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
         if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
                 || !Utils.isVoiceCapable(getActivity())) {
-            mSystemsCategory.removePreference(mTogglePowerButtonEndsCallPreference);
+            mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL)
+                    .removePreference(mTogglePowerButtonEndsCallPreference);
         }
 
         // Lock screen rotation.
         mToggleLockScreenRotationPreference =
                 (SwitchPreference) findPreference(TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE);
         if (!RotationPolicy.isRotationSupported(getActivity())) {
-            mSystemsCategory.removePreference(mToggleLockScreenRotationPreference);
+            mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL)
+                    .removePreference(mToggleLockScreenRotationPreference);
         }
 
         // Large pointer icon.
@@ -424,7 +441,7 @@
         mSelectLongPressTimeoutPreference =
                 (ListPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
         mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
-        if (mLongPressTimeoutValuetoTitleMap.size() == 0) {
+        if (mLongPressTimeoutValueToTitleMap.size() == 0) {
             String[] timeoutValues = getResources().getStringArray(
                     R.array.long_press_timeout_selector_values);
             mLongPressTimeoutDefault = Integer.parseInt(timeoutValues[0]);
@@ -432,7 +449,7 @@
                     R.array.long_press_timeout_selector_titles);
             final int timeoutValueCount = timeoutValues.length;
             for (int i = 0; i < timeoutValueCount; i++) {
-                mLongPressTimeoutValuetoTitleMap.put(timeoutValues[i], timeoutTitles[i]);
+                mLongPressTimeoutValueToTitleMap.put(timeoutValues[i], timeoutTitles[i]);
             }
         }
 
@@ -459,17 +476,32 @@
     }
 
     private void updateAllPreferences() {
-        updateServicesPreferences();
         updateSystemPreferences();
+        updateServicePreferences();
     }
 
-    private void updateServicesPreferences() {
+    private void updateServicePreferences() {
         // Since services category is auto generated we have to do a pass
         // to generate it since services can come and go and then based on
         // the global accessibility state to decided whether it is enabled.
 
         // Generate.
-        mServicesCategory.removeAll();
+        ArrayList<Preference> servicePreferences =
+                new ArrayList<>(mServicePreferenceToPreferenceCategoryMap.keySet());
+        for (int i = 0; i < servicePreferences.size(); i++) {
+            Preference service = servicePreferences.get(i);
+            PreferenceCategory category = mServicePreferenceToPreferenceCategoryMap.get(service);
+            category.removePreference(service);
+        }
+
+        initializePreBundledServicesMapFromArray(CATEGORY_SCREEN_READER,
+                R.array.config_preinstalled_screen_reader_services);
+        initializePreBundledServicesMapFromArray(CATEGORY_AUDIO_AND_CAPTIONS,
+                R.array.config_preinstalled_audio_and_caption_services);
+        initializePreBundledServicesMapFromArray(CATEGORY_DISPLAY,
+                R.array.config_preinstalled_display_services);
+        initializePreBundledServicesMapFromArray(CATEGORY_INTERACTION_CONTROL,
+                R.array.config_preinstalled_interaction_control_services);
 
         AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getActivity());
 
@@ -482,36 +514,49 @@
         final boolean accessibilityEnabled = Settings.Secure.getInt(getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
 
+        PreferenceCategory downloadedServicesCategory =
+                mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES);
+        // Temporarily add the downloaded services category back if it was previously removed.
+        if (findPreference(CATEGORY_DOWNLOADED_SERVICES) == null) {
+            getPreferenceScreen().addPreference(downloadedServicesCategory);
+        }
+
         for (int i = 0, count = installedServices.size(); i < count; ++i) {
             AccessibilityServiceInfo info = installedServices.get(i);
 
-            RestrictedPreference preference =
-                    new RestrictedPreference(mServicesCategory.getContext());
+            SingleLineSummaryPreference preference =
+                    new SingleLineSummaryPreference(downloadedServicesCategory.getContext(), null);
             String title = info.getResolveInfo().loadLabel(getPackageManager()).toString();
 
+            Drawable icon = info.getResolveInfo().loadIcon(getPackageManager());
+            if (icon == null) {
+                // todo (saigem): add a default
+            }
+
             ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
-            ComponentName componentName = new ComponentName(serviceInfo.packageName,
-                    serviceInfo.name);
+            String packageName = serviceInfo.packageName;
+            ComponentName componentName = new ComponentName(packageName, serviceInfo.name);
+            String componentNameKey = componentName.flattenToString();
 
             preference.setKey(componentName.flattenToString());
 
             preference.setTitle(title);
+            preference.setIcon(icon);
             final boolean serviceEnabled = accessibilityEnabled
                     && enabledServices.contains(componentName);
-            String serviceEnabledString;
-            if (serviceEnabled) {
-                serviceEnabledString = getString(R.string.accessibility_feature_state_on);
-            } else {
-                serviceEnabledString = getString(R.string.accessibility_feature_state_off);
-            }
+            String serviceState = serviceEnabled ?
+                    getString(R.string.accessibility_feature_state_on) :
+                    getString(R.string.accessibility_feature_state_off);
+            String serviceSummary = info.loadSummary(getPackageManager());
+            serviceSummary = (TextUtils.isEmpty(serviceSummary)) ? serviceState :
+                    serviceSummary;
 
             // Disable all accessibility services that are not permitted.
-            String packageName = serviceInfo.packageName;
             boolean serviceAllowed =
                     permittedServices == null || permittedServices.contains(packageName);
             if (!serviceAllowed && !serviceEnabled) {
                 EnforcedAdmin admin = RestrictedLockUtils.checkIfAccessibilityServiceDisallowed(
-                        getActivity(), serviceInfo.packageName, UserHandle.myUserId());
+                        getActivity(), packageName, UserHandle.myUserId());
                 if (admin != null) {
                     preference.setDisabledByAdmin(admin);
                 } else {
@@ -521,9 +566,7 @@
                 preference.setEnabled(true);
             }
 
-            preference.setSummary(serviceEnabledString);
-
-            preference.setOrder(i);
+            preference.setSummary(serviceSummary);
             preference.setFragment(ToggleAccessibilityServicePreferenceFragment.class.getName());
             preference.setPersistent(true);
 
@@ -543,26 +586,33 @@
                 extras.putString(EXTRA_SETTINGS_TITLE,
                         getString(R.string.accessibility_menu_item_settings));
                 extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
-                        new ComponentName(info.getResolveInfo().serviceInfo.packageName,
-                                settingsClassName).flattenToString());
+                        new ComponentName(packageName, settingsClassName).flattenToString());
             }
-
             extras.putParcelable(EXTRA_COMPONENT_NAME, componentName);
 
-            mServicesCategory.addPreference(preference);
+            PreferenceCategory prefCategory = downloadedServicesCategory;
+            // Set the appropriate category if the service comes pre-installed.
+            if (mPreBundledServiceComponentToCategoryMap.containsKey(componentName)) {
+                prefCategory = mPreBundledServiceComponentToCategoryMap.get(componentName);
+            }
+            preference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX);
+            prefCategory.addPreference(preference);
+            mServicePreferenceToPreferenceCategoryMap.put(preference, prefCategory);
         }
 
-        if (mServicesCategory.getPreferenceCount() == 0) {
-            if (mNoServicesMessagePreference == null) {
-                mNoServicesMessagePreference = new Preference(getPrefContext());
-                mNoServicesMessagePreference.setPersistent(false);
-                mNoServicesMessagePreference.setLayoutResource(
-                        R.layout.text_description_preference);
-                mNoServicesMessagePreference.setSelectable(false);
-                mNoServicesMessagePreference.setSummary(
-                        getString(R.string.accessibility_no_services_installed));
-            }
-            mServicesCategory.addPreference(mNoServicesMessagePreference);
+        // If the user has not installed any additional services, hide the category.
+        if (downloadedServicesCategory.getPreferenceCount() == 0) {
+            PreferenceScreen screen = getPreferenceScreen();
+            screen.removePreference(downloadedServicesCategory);
+        }
+    }
+
+    private void initializePreBundledServicesMapFromArray(String categoryKey, int key) {
+        String[] services = getResources().getStringArray(key);
+        PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey);
+        for (int i = 0; i < services.length; i++) {
+            ComponentName component = ComponentName.unflattenFromString(services[i]);
+            mPreBundledServiceComponentToCategoryMap.put(component, category);
         }
     }
 
@@ -602,7 +652,7 @@
                 Settings.Secure.LONG_PRESS_TIMEOUT, mLongPressTimeoutDefault);
         String value = String.valueOf(longPressTimeout);
         mSelectLongPressTimeoutPreference.setValue(value);
-        mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValuetoTitleMap.get(value));
+        mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValueToTitleMap.get(value));
 
         updateFeatureSummary(Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
                 mCaptioningPreferenceScreen);
@@ -706,7 +756,7 @@
                     context.getSystemService(AccessibilityManager.class);
 
             String screenTitle = context.getResources().getString(
-                    R.string.accessibility_services_title);
+                    R.string.accessibility_settings);
 
             // Indexing all services, regardless if enabled.
             List<AccessibilityServiceInfo> services = accessibilityManager
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
index 3252f4e..7eb7fdd 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
@@ -118,13 +118,6 @@
                             context, deviceAddress, deviceName)) {
                 context.startActivity(connectionAccessIntent);
             } else {
-                // Acquire wakelock so that LCD comes up since screen is off
-                PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK |
-                    PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE,
-                        "ConnectionAccessActivity");
-                wakeLock.setReferenceCounted(false);
-                wakeLock.acquire();
-
                 // Put up a notification that leads to the dialog
 
                 // Create an intent triggered by clicking on the
@@ -181,7 +174,6 @@
 
                 notificationManager.notify(getNotificationTag(mRequestType), NOTIFICATION_ID,
                         notification);
-                wakeLock.release();
             }
         } else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)) {
             // Remove the notification
diff --git a/src/com/android/settings/connecteddevice/UsbModePreferenceController.java b/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
index 5f700bd..6c1a28b 100644
--- a/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
@@ -119,7 +119,7 @@
                 preference.setEnabled(true);
                 preference.setSummary(getTitle(mode));
             } else {
-                preference.setSummary(R.string.usb_nothing_connected);
+                preference.setSummary(R.string.disconnected);
                 preference.setEnabled(false);
             }
         }
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProvider.java b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
index 20bcd3d..1c55bbb 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProvider.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
@@ -16,8 +16,8 @@
 package com.android.settings.dashboard;
 
 import android.app.Activity;
-import android.app.Fragment;
 import android.content.Context;
+import android.os.Bundle;
 import android.support.v7.preference.Preference;
 
 import com.android.settingslib.drawer.DashboardCategory;
@@ -78,7 +78,7 @@
      * Returns a {@link ProgressiveDisclosureMixin} for specified fragment.
      */
     ProgressiveDisclosureMixin getProgressiveDisclosureMixin(Context context,
-            DashboardFragment fragment);
+            DashboardFragment fragment, Bundle args);
 
     /**
      * Returns additional intent filter action for dashboard tiles
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index 9c21720..722f9e1 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -168,8 +168,12 @@
 
     @Override
     public ProgressiveDisclosureMixin getProgressiveDisclosureMixin(Context context,
-            DashboardFragment fragment) {
-        return new ProgressiveDisclosureMixin(context, mMetricsFeatureProvider, fragment);
+            DashboardFragment fragment, Bundle args) {
+        boolean keepExpanded = false;
+        if (args != null) {
+            keepExpanded = args.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY) != null;
+        }
+        return new ProgressiveDisclosureMixin(context, fragment, keepExpanded);
     }
 
     @Override
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index e3845cd..3687929 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -69,7 +69,7 @@
         mDashboardFeatureProvider =
                 FeatureFactory.getFactory(context).getDashboardFeatureProvider(context);
         mProgressiveDisclosureMixin = mDashboardFeatureProvider
-                .getProgressiveDisclosureMixin(context, this);
+                .getProgressiveDisclosureMixin(context, this, getArguments());
         getLifecycle().addObserver(mProgressiveDisclosureMixin);
 
         List<PreferenceController> controllers = getPreferenceControllers(context);
diff --git a/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java b/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
index be5e21b..07a7293 100644
--- a/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
+++ b/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java
@@ -33,6 +33,7 @@
 import com.android.settings.core.lifecycle.LifecycleObserver;
 import com.android.settings.core.lifecycle.events.OnCreate;
 import com.android.settings.core.lifecycle.events.OnSaveInstanceState;
+import com.android.settings.overlay.FeatureFactory;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -56,13 +57,13 @@
     private boolean mUserExpanded;
 
     public ProgressiveDisclosureMixin(Context context,
-            MetricsFeatureProvider metricsFeatureProvider,
-            PreferenceFragment fragment) {
+            PreferenceFragment fragment, boolean keepExpanded) {
         mContext = context;
         mFragment = fragment;
         mExpandButton = new ExpandPreference(context);
         mExpandButton.setOnPreferenceClickListener(this);
-        mMetricsFeatureProvider = metricsFeatureProvider;
+        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+        mUserExpanded = keepExpanded;
     }
 
     @Override
@@ -119,7 +120,7 @@
      * Whether the screen should be collapsed.
      */
     public boolean shouldCollapse(PreferenceScreen screen) {
-        return screen.getPreferenceCount() >= mTileLimit && !mUserExpanded;
+        return !mUserExpanded && screen.getPreferenceCount() >= mTileLimit;
     }
 
     /**
diff --git a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java
index 5176e09..ae5e5f1 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java
@@ -89,6 +89,8 @@
             // code size.
             if (!app.isSystemApp() || app.isUpdatedSystemApp()) {
                 attributedAppSizeInBytes += stats.getCodeBytes();
+            } else {
+                result.systemSize += stats.getCodeBytes();
             }
             switch (app.category) {
                 case CATEGORY_GAME:
@@ -122,6 +124,7 @@
         public long gamesSize;
         public long musicAppsSize;
         public long otherAppsSize;
+        public long systemSize;
         public StorageStatsSource.ExternalStorageStats externalStats;
     }
 
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
index 2fa1b18..36cf73e 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -181,7 +181,7 @@
         mGamePreference.setStorageSize(data.gamesSize);
         mAppPreference.setStorageSize(data.otherAppsSize);
         if (mSystemPreference != null) {
-            mSystemPreference.setStorageSize(mSystemSize);
+            mSystemPreference.setStorageSize(mSystemSize + data.systemSize);
         }
 
         long unattributedBytes = data.externalStats.totalBytes - data.externalStats.audioBytes
diff --git a/src/com/android/settings/network/VpnPreferenceController.java b/src/com/android/settings/network/VpnPreferenceController.java
index 86ff175..72b361a 100644
--- a/src/com/android/settings/network/VpnPreferenceController.java
+++ b/src/com/android/settings/network/VpnPreferenceController.java
@@ -150,13 +150,13 @@
             uid = userInfo.id;
         }
         VpnConfig vpn = vpns.get(uid);
-        final String vpnName;
+        final String summary;
         if (vpn == null) {
-            vpnName = null;
+            summary = mContext.getString(R.string.vpn_disconnected_summary);
         } else {
-            vpnName = getNameForVpnConfig(vpn, UserHandle.of(uid));
+            summary = getNameForVpnConfig(vpn, UserHandle.of(uid));
         }
-        new Handler(Looper.getMainLooper()).post(() -> mPreference.setSummary(vpnName));
+        new Handler(Looper.getMainLooper()).post(() -> mPreference.setSummary(summary));
     }
 
     private String getNameForVpnConfig(VpnConfig cfg, UserHandle user) {
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index d12842c..24405b3 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -34,6 +34,7 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.AppHeader;
+import com.android.settings.DimmableIconPreference;
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.applications.AppHeaderController;
@@ -66,14 +67,18 @@
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    public void onResume() {
+        super.onResume();
+
         if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) {
             Log.w(TAG, "Missing package or uid or packageinfo");
-            toastAndFinish();
+            finish();
             return;
         }
-        final Activity activity = getActivity();
+
+        if (getPreferenceScreen() != null) {
+            getPreferenceScreen().removeAll();
+        }
 
         addPreferencesFromResource(R.xml.app_notification_settings);
         getPreferenceScreen().setOrderingAsAdded(true);
@@ -81,44 +86,38 @@
         mBlock = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BLOCK);
         mBadge = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BADGE);
 
-        if (mPkgInfo != null) {
-            setupBlock();
-            setupBadge();
-            // load settings intent
-            ArrayMap<String, AppRow> rows = new ArrayMap<String, AppRow>();
-            rows.put(mAppRow.pkg, mAppRow);
-            collectConfigActivities(rows);
-            new AsyncTask<Void, Void, Void>() {
-                @Override
-                protected Void doInBackground(Void... unused) {
-                    mChannelGroupList = mBackend.getChannelGroups(mPkg, mUid).getList();
-                    Collections.sort(mChannelGroupList, mChannelGroupComparator);
-                    return null;
-                }
+        setupBlock();
+        setupBadge();
+        // load settings intent
+        ArrayMap<String, AppRow> rows = new ArrayMap<String, AppRow>();
+        rows.put(mAppRow.pkg, mAppRow);
+        collectConfigActivities(rows);
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... unused) {
+                mChannelGroupList = mBackend.getChannelGroups(mPkg, mUid).getList();
+                Collections.sort(mChannelGroupList, mChannelGroupComparator);
+                return null;
+            }
 
-                @Override
-                protected void onPostExecute(Void unused) {
-                    populateChannelList();
-                }
-            }.execute();
-        }
-        final Preference pref = FeatureFactory.getFactory(activity)
-            .getApplicationFeatureProvider(activity)
-            .newAppHeaderController(this /* fragment */, null /* appHeader */)
-            .setIcon(mAppRow.icon)
-            .setLabel(mAppRow.label)
-            .setPackageName(mAppRow.pkg)
-            .setUid(mAppRow.uid)
-            .setAppNotifPrefIntent(mAppRow.settingsIntent)
-            .setButtonActions(AppHeaderController.ActionType.ACTION_APP_INFO,
-                AppHeaderController.ActionType.ACTION_NOTIF_PREFERENCE)
-            .done(getPrefContext());
+            @Override
+            protected void onPostExecute(Void unused) {
+                populateChannelList();
+            }
+        }.execute();
+
+        final Preference pref = FeatureFactory.getFactory(getActivity())
+                .getApplicationFeatureProvider(getActivity())
+                .newAppHeaderController(this /* fragment */, null /* appHeader */)
+                .setIcon(mAppRow.icon)
+                .setLabel(mAppRow.label)
+                .setPackageName(mAppRow.pkg)
+                .setUid(mAppRow.uid)
+                .setButtonActions(AppHeaderController.ActionType.ACTION_APP_INFO,
+                        AppHeaderController.ActionType.ACTION_NOTIF_PREFERENCE)
+                .done(getPrefContext());
         getPreferenceScreen().addPreference(pref);
-    }
 
-    @Override
-    public void onResume() {
-        super.onResume();
         if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) {
             Log.w(TAG, "Missing package or uid or packageinfo");
             finish();
@@ -145,7 +144,7 @@
                             ? R.string.notification_channels_other
                             : R.string.notification_channels);
                 } else {
-                    groupCategory.setTitle(getNotificationGroupLabel(group));
+                    groupCategory.setTitle(group.getName());
                 }
                 groupCategory.setKey(group.getId());
                 groupCategory.setOrderingAsAdded(true);
@@ -161,45 +160,55 @@
                             getPrefContext());
                     channelPref.setDisabledByAdmin(mSuspendedAppsAdmin);
                     channelPref.setKey(channel.getId());
-                    channelPref.setTitle(getNotificationChannelLabel(channel));
+                    channelPref.setTitle(channel.getName());
                     channelPref.setChecked(channel.getImportance() != IMPORTANCE_NONE);
                     channelPref.setMultiLine(true);
+                    channelPref.setSummary(getImportanceSummary(channel.getImportance()));
+                    Bundle channelArgs = new Bundle();
+                    channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
+                    channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
+                    channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
+                    channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
+                    Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
+                            ChannelNotificationSettings.class.getName(),
+                            channelArgs, null, 0, null, false, getMetricsCategory());
+                    channelPref.setIntent(channelIntent);
 
-                    if (channel.isDeleted()) {
-                        channelPref.setTitle(getString(R.string.deleted_channel_name,
-                                getNotificationChannelLabel(channel)));
-                        channelPref.setEnabled(false);
-                    } else {
-                        channelPref.setSummary(getImportanceSummary(channel.getImportance()));
-                        Bundle channelArgs = new Bundle();
-                        channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
-                        channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
-                        channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
-                        channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
-                        Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
-                                ChannelNotificationSettings.class.getName(),
-                                channelArgs, null, 0, null, false, getMetricsCategory());
-                        channelPref.setIntent(channelIntent);
+                    channelPref.setOnPreferenceChangeListener(
+                            new Preference.OnPreferenceChangeListener() {
+                                @Override
+                                public boolean onPreferenceChange(Preference preference,
+                                        Object o) {
+                                    boolean value = (Boolean) o;
+                                    int importance = value ?  IMPORTANCE_LOW : IMPORTANCE_NONE;
+                                    channel.setImportance(importance);
+                                    channel.lockFields(
+                                            NotificationChannel.USER_LOCKED_IMPORTANCE);
+                                    mBackend.updateChannel(mPkg, mUid, channel);
 
-                        channelPref.setOnPreferenceChangeListener(
-                                new Preference.OnPreferenceChangeListener() {
-                                    @Override
-                                    public boolean onPreferenceChange(Preference preference,
-                                            Object o) {
-                                        boolean value = (Boolean) o;
-                                        int importance = value ?  IMPORTANCE_LOW : IMPORTANCE_NONE;
-                                        channel.setImportance(importance);
-                                        channel.lockFields(
-                                                NotificationChannel.USER_LOCKED_IMPORTANCE);
-                                        mBackend.updateChannel(mPkg, mUid, channel);
-
-                                        return true;
-                                    }
-                                });
-                    }
+                                    return true;
+                                }
+                            });
                     groupCategory.addPreference(channelPref);
                 }
             }
+
+            if (mAppRow.settingsIntent != null) {
+                Preference intentPref = new Preference(getPrefContext());
+                intentPref.setIntent(mAppRow.settingsIntent);
+                intentPref.setTitle(mContext.getString(R.string.app_settings_link));
+                getPreferenceScreen().addPreference(intentPref);
+            }
+
+            int deletedChannelCount = mBackend.getDeletedChannelCount(mAppRow.pkg, mAppRow.uid);
+            if (deletedChannelCount > 0) {
+                DimmableIconPreference deletedPref = new DimmableIconPreference(getPrefContext());
+                deletedPref.setEnabled(false);
+                deletedPref.setTitle(getResources().getQuantityString(
+                        R.plurals.deleted_channels, deletedChannelCount, deletedChannelCount));
+                deletedPref.setIcon(R.drawable.ic_info);
+                getPreferenceScreen().addPreference(deletedPref);
+            }
         }
         updateDependents(mAppRow.banned);
     }
@@ -257,8 +266,8 @@
             if (left.isDeleted() != right.isDeleted()) {
                 return Boolean.compare(left.isDeleted(), right.isDeleted());
             }
-            CharSequence leftName = getNotificationChannelLabel(left);
-            CharSequence rightName = getNotificationChannelLabel(right);
+            CharSequence leftName = left.getName();
+            CharSequence rightName = right.getName();
             if (!Objects.equals(leftName, rightName)) {
                 return sCollator.compare(leftName.toString(), rightName.toString());
             }
@@ -278,8 +287,8 @@
                     } else if (right.getId() == null && left.getId() != null) {
                         return -1;
                     }
-                    CharSequence leftName = getNotificationGroupLabel(left);
-                    CharSequence rightName = getNotificationGroupLabel(right);
+                    CharSequence leftName = left.getName();
+                    CharSequence rightName = right.getName();
                     // sort rest of the groups by name
                     if (!Objects.equals(leftName, rightName)) {
                         return sCollator.compare(leftName.toString(), rightName.toString());
diff --git a/src/com/android/settings/notification/ChannelNotificationSettings.java b/src/com/android/settings/notification/ChannelNotificationSettings.java
index 18e00f8..7f7aa08 100644
--- a/src/com/android/settings/notification/ChannelNotificationSettings.java
+++ b/src/com/android/settings/notification/ChannelNotificationSettings.java
@@ -73,19 +73,22 @@
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    public void onResume() {
+        super.onResume();
         if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null || mChannel == null) {
             Log.w(TAG, "Missing package or uid or packageinfo or channel");
-            toastAndFinish();
+            finish();
             return;
         }
-        final Activity activity = getActivity();
+
+        if (getPreferenceScreen() != null) {
+            getPreferenceScreen().removeAll();
+        }
         addPreferencesFromResource(R.xml.channel_notification_settings);
+        getPreferenceScreen().setOrderingAsAdded(true);
 
         // load settings intent
-        ArrayMap<String, NotificationBackend.AppRow>
-                rows = new ArrayMap<String, NotificationBackend.AppRow>();
+        ArrayMap<String, NotificationBackend.AppRow> rows = new ArrayMap<String, NotificationBackend.AppRow>();
         rows.put(mAppRow.pkg, mAppRow);
         collectConfigActivities(rows);
 
@@ -109,36 +112,25 @@
             setupBlockAndImportance();
             updateDependents();
         }
-        final Preference pref = FeatureFactory.getFactory(activity)
-            .getApplicationFeatureProvider(activity)
-            .newAppHeaderController(this /* fragment */, null /* appHeader */)
-            .setIcon(mAppRow.icon)
-            .setLabel(getNotificationChannelLabel(mChannel))
-            .setSummary(mAppRow.label)
-            .setPackageName(mAppRow.pkg)
-            .setUid(mAppRow.uid)
-            .setAppNotifPrefIntent(mAppRow.settingsIntent)
-            .setButtonActions(AppHeaderController.ActionType.ACTION_APP_INFO,
-                AppHeaderController.ActionType.ACTION_NOTIF_PREFERENCE)
-            .done(getPrefContext());
+        final Preference pref = FeatureFactory.getFactory(getActivity())
+                .getApplicationFeatureProvider(getActivity())
+                .newAppHeaderController(this /* fragment */, null /* appHeader */)
+                .setIcon(mAppRow.icon)
+                .setLabel(mChannel.getName())
+                .setSummary(mAppRow.label)
+                .setPackageName(mAppRow.pkg)
+                .setUid(mAppRow.uid)
+                .setButtonActions(AppHeaderController.ActionType.ACTION_APP_INFO,
+                        AppHeaderController.ActionType.ACTION_NOTIF_PREFERENCE)
+                .done(getPrefContext());
         getPreferenceScreen().addPreference(pref);
-    }
 
-    @Override
-    public void onResume() {
-        super.onResume();
-        if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null || mChannel == null) {
-            Log.w(TAG, "Missing package or uid or packageinfo or channel");
-            finish();
-            return;
+        if (mAppRow.settingsIntent != null) {
+            Preference intentPref = new Preference(getPrefContext());
+            intentPref.setIntent(mAppRow.settingsIntent);
+            intentPref.setTitle(mContext.getString(R.string.app_settings_link));
+            getPreferenceScreen().addPreference(intentPref);
         }
-        mLights.setDisabledByAdmin(mSuspendedAppsAdmin);
-        mVibrate.setDisabledByAdmin(mSuspendedAppsAdmin);
-        if (mImportance.isEnabled()) {
-            mImportance.setDisabledByAdmin(mSuspendedAppsAdmin);
-        }
-        mPriority.setDisabledByAdmin(mSuspendedAppsAdmin);
-        mVisibilityOverride.setDisabledByAdmin(mSuspendedAppsAdmin);
     }
 
     private void setupLights() {
@@ -321,6 +313,7 @@
                         return true;
                     }
                 });
+        mVisibilityOverride.setDisabledByAdmin(mSuspendedAppsAdmin);
     }
 
     private void setRestrictedIfNotificationFeaturesDisabled(CharSequence entry,
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index 0881eb7..c1ef018 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -124,7 +124,7 @@
 
     public ParceledListSlice<NotificationChannelGroup> getChannelGroups(String pkg, int uid) {
         try {
-            return sINM.getNotificationChannelGroupsForPackage(pkg, uid, true);
+            return sINM.getNotificationChannelGroupsForPackage(pkg, uid, false);
         } catch (Exception e) {
             Log.w(TAG, "Error calling NoMan", e);
             return ParceledListSlice.emptyList();
@@ -139,6 +139,15 @@
         }
     }
 
+    public int getDeletedChannelCount(String pkg, int uid) {
+        try {
+            return sINM.getDeletedChannelCount(pkg, uid);
+        } catch (Exception e) {
+            Log.w(TAG, "Error calling NoMan", e);
+            return 0;
+        }
+    }
+
     static class Row {
         public String section;
     }
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 6a40ea5..960c3b8 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -127,15 +127,6 @@
         }
 
         mUserId = UserHandle.getUserId(mUid);
-        mAppRow = mBackend.loadAppRow(mContext, mPm, mPkgInfo);
-        mChannel = (args != null && args.containsKey(Settings.EXTRA_CHANNEL_ID)) ?
-                mBackend.getChannel(mPkg, mUid, args.getString(Settings.EXTRA_CHANNEL_ID)) : null;
-
-        mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
-                mContext, mPkg, mUserId);
-        NotificationManager.Policy policy =
-                NotificationManager.from(mContext).getNotificationPolicy();
-        mDndVisualEffectsSuppressed = policy == null ? false : policy.suppressedVisualEffects != 0;
     }
 
     @Override
@@ -146,12 +137,19 @@
             finish();
             return;
         }
+        mAppRow = mBackend.loadAppRow(mContext, mPm, mPkgInfo);
+        Bundle args = getArguments();
+        mChannel = (args != null && args.containsKey(Settings.EXTRA_CHANNEL_ID)) ?
+                mBackend.getChannel(mPkg, mUid, args.getString(Settings.EXTRA_CHANNEL_ID)) : null;
+
         mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
                 mContext, mPkg, mUserId);
-        if (mBlock.isEnabled()) {
-            mBlock.setDisabledByAdmin(mSuspendedAppsAdmin);
-        }
-        mBadge.setDisabledByAdmin(mSuspendedAppsAdmin);
+        NotificationManager.Policy policy =
+                NotificationManager.from(mContext).getNotificationPolicy();
+        mDndVisualEffectsSuppressed = policy == null ? false : policy.suppressedVisualEffects != 0;
+
+        mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
+                mContext, mPkg, mUserId);
     }
 
     protected void setVisible(Preference p, boolean visible) {
@@ -251,25 +249,4 @@
                 return getContext().getString(R.string.notification_importance_high);
         }
     }
-
-    protected CharSequence getNotificationGroupLabel(NotificationChannelGroup group) {
-        return getLabel(group.getName(), group.getNameResId());
-    }
-
-    protected CharSequence getNotificationChannelLabel(NotificationChannel channel) {
-        return getLabel(channel.getName(), channel.getNameResId());
-    }
-
-    private CharSequence getLabel(CharSequence name, int nameResId) {
-        if (!TextUtils.isEmpty(name)) {
-            return name;
-        }
-        try {
-            ApplicationInfo info = mPm.getApplicationInfoAsUser(mAppRow.pkg, 0, mAppRow.userId);
-            return mPm.getText(mAppRow.pkg, nameResId, info);
-        } catch (NameNotFoundException e) {
-            e.printStackTrace();
-        }
-        return null;
-    }
 }
diff --git a/src/com/android/settings/search2/DatabaseIndexingManager.java b/src/com/android/settings/search2/DatabaseIndexingManager.java
index d6e6959..6e91f5c 100644
--- a/src/com/android/settings/search2/DatabaseIndexingManager.java
+++ b/src/com/android/settings/search2/DatabaseIndexingManager.java
@@ -27,7 +27,6 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteFullException;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.provider.SearchIndexableData;
@@ -53,10 +52,12 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE;
@@ -82,9 +83,40 @@
 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RANK;
 import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID;
 
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.CLASS_NAME;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_ENTRIES;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEY_REF;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_RANK;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DOCID;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ENABLED;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ICON;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_ACTION;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.LOCALE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.PAYLOAD;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.SCREEN_TITLE;
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.USER_ID;
+import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX;
+
+import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_ID;
+import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE;
+import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_KEY;
+import static com.android.settings.search2.DatabaseResultLoader.SELECT_COLUMNS;
+
 /**
  * Consumes the SearchIndexableProvider content providers.
  * Updates the Resource, Raw Data and non-indexable data for Search.
+ *
+ * TODO this class needs to be refactored by moving most of its methods into controllers
  */
 public class DatabaseIndexingManager {
     private static final String LOG_TAG = "DatabaseIndexingManager";
@@ -93,51 +125,14 @@
     private static final String NODE_NAME_CHECK_BOX_PREFERENCE = "CheckBoxPreference";
     private static final String NODE_NAME_LIST_PREFERENCE = "ListPreference";
 
-    private static final List<String> EMPTY_LIST = Collections.<String>emptyList();
+    private static final List<String> EMPTY_LIST = Collections.emptyList();
 
     private final String mBaseAuthority;
 
-    /**
-     * A private class to describe the update data for the Index database
-     */
-    private static class UpdateData {
-        public List<SearchIndexableData> dataToUpdate;
-        public List<SearchIndexableData> dataToDelete;
-        public Map<String, List<String>> nonIndexableKeys;
-
-        public boolean forceUpdate;
-        public boolean fullIndex;
-
-        public UpdateData() {
-            dataToUpdate = new ArrayList<>();
-            dataToDelete = new ArrayList<>();
-            nonIndexableKeys = new HashMap<>();
-        }
-
-        public UpdateData(DatabaseIndexingManager.UpdateData other) {
-            dataToUpdate = new ArrayList<>(other.dataToUpdate);
-            dataToDelete = new ArrayList<>(other.dataToDelete);
-            nonIndexableKeys = new HashMap<>(other.nonIndexableKeys);
-            forceUpdate = other.forceUpdate;
-            fullIndex = other.fullIndex;
-        }
-
-        public DatabaseIndexingManager.UpdateData copy() {
-            return new DatabaseIndexingManager.UpdateData(this);
-        }
-
-        public void clear() {
-            dataToUpdate.clear();
-            dataToDelete.clear();
-            nonIndexableKeys.clear();
-            forceUpdate = false;
-            fullIndex = false;
-        }
-    }
-
     private final AtomicBoolean mIsAvailable = new AtomicBoolean(false);
-    private final DatabaseIndexingManager.UpdateData mDataToProcess =
-            new DatabaseIndexingManager.UpdateData();
+
+    @VisibleForTesting
+    final UpdateData mDataToProcess = new UpdateData();
     private Context mContext;
 
     public DatabaseIndexingManager(Context context, String baseAuthority) {
@@ -157,31 +152,201 @@
         AsyncTask.execute(new Runnable() {
             @Override
             public void run() {
-                final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
-                List<ResolveInfo> list =
-                        mContext.getPackageManager().queryIntentContentProviders(intent, 0);
-
-                final int size = list.size();
-                for (int n = 0; n < size; n++) {
-                    final ResolveInfo info = list.get(n);
-                    if (!DatabaseIndexingUtils.isWellKnownProvider(info, mContext)) {
-                        continue;
-                    }
-                    final String authority = info.providerInfo.authority;
-                    final String packageName = info.providerInfo.packageName;
-
-                    addIndexablesFromRemoteProvider(packageName, authority);
-                    addNonIndexablesKeysFromRemoteProvider(packageName, authority);
-                }
-
-                mDataToProcess.fullIndex = true;
-                updateInternal();
+                performIndexing();
             }
         });
     }
 
-    private boolean addIndexablesFromRemoteProvider(String packageName, String authority) {
+    /**
+     * Accumulate all data and non-indexable keys from each of the content-providers.
+     * Only the first indexing for the default language gets static search results - subsequent
+     * calls will only gather non-indexable keys.
+     */
+    @VisibleForTesting
+    void performIndexing() {
+        final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
+        final List<ResolveInfo> list =
+                mContext.getPackageManager().queryIntentContentProviders(intent, 0);
+
+        final boolean isLocaleIndexed = isLocaleIndexed();
+
+        for (final ResolveInfo info : list) {
+            if (!DatabaseIndexingUtils.isWellKnownProvider(info, mContext)) {
+                continue;
+            }
+            final String authority = info.providerInfo.authority;
+            final String packageName = info.providerInfo.packageName;
+
+            if (!isLocaleIndexed) {
+                addIndexablesFromRemoteProvider(packageName, authority);
+            }
+            addNonIndexablesKeysFromRemoteProvider(packageName, authority);
+        }
+
+        final String localeStr = Locale.getDefault().toString();
+        updateDatabase(isLocaleIndexed, localeStr);
+    }
+
+    @VisibleForTesting
+    boolean isLocaleIndexed() {
+        final String locale = Locale.getDefault().toString();
+        return IndexDatabaseHelper.getInstance(mContext).isLocaleAlreadyIndexed(mContext, locale);
+    }
+
+    /**
+     * Adds new data to the database and verifies the correctness of the ENABLED column.
+     * First, the data to be updated and all non-indexable keys are copied locally.
+     * Then all new data to be added is inserted.
+     * Then search results are verified to have the correct value of enabled.
+     * Finally, we record that the locale has been indexed.
+     *
+     * @param isIncrementalUpdate true when the language has already been indexed.
+     * @param localeStr the default locale for the device.
+     */
+    @VisibleForTesting
+    void updateDatabase(boolean isIncrementalUpdate, String localeStr) {
+        mIsAvailable.set(false);
+        final UpdateData copy;
+
+        synchronized (mDataToProcess) {
+            copy = mDataToProcess.copy();
+            mDataToProcess.clear();
+        }
+
+        final List<SearchIndexableData> dataToUpdate = copy.dataToUpdate;
+        final Map<String, Set<String>> nonIndexableKeys = copy.nonIndexableKeys;
+
+        final SQLiteDatabase database = getWritableDatabase();
+        if (database == null) {
+            Log.w(LOG_TAG, "Cannot indexDatabase Index as I cannot get a writable database");
+            return;
+        }
+
         try {
+            database.beginTransaction();
+
+            // Add new data from Providers at initial index time, or inserted later.
+            if (dataToUpdate.size() > 0) {
+                addDataToDatabase(database, localeStr, dataToUpdate, nonIndexableKeys);
+            }
+
+            // Only check for non-indexable key updates after initial index.
+            // Enabled state with non-indexable keys is checked when items are first inserted.
+            if (isIncrementalUpdate) {
+                updateDataInDatabase(database, nonIndexableKeys);
+            }
+
+            database.setTransactionSuccessful();
+        } finally {
+            database.endTransaction();
+        }
+        // TODO Refactor: move the locale out of the helper class
+        IndexDatabaseHelper.setLocaleIndexed(mContext, localeStr);
+
+        mIsAvailable.set(true);
+    }
+
+    /**
+     * Inserts {@link SearchIndexableData} into the database.
+     *
+     * @param database where the data will be inserted.
+     * @param localeStr is the locale of the data to be inserted.
+     * @param dataToUpdate is a {@link List} of the data to be inserted.
+     * @param nonIndexableKeys is a {@link Map} from Package Name to a {@link Set} of keys which
+     *                         identify search results which should not be surfaced.
+     */
+    @VisibleForTesting
+    void addDataToDatabase(SQLiteDatabase database, String localeStr,
+            List<SearchIndexableData> dataToUpdate, Map<String, Set<String>> nonIndexableKeys) {
+        final long current = System.currentTimeMillis();
+
+        for (SearchIndexableData data : dataToUpdate) {
+            try {
+                indexOneSearchIndexableData(database, localeStr, data, nonIndexableKeys);
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Cannot index: " + (data != null ? data.className : data)
+                        + " for locale: " + localeStr, e);
+            }
+        }
+
+        final long now = System.currentTimeMillis();
+        Log.d(LOG_TAG, "Indexing locale '" + localeStr + "' took " +
+                (now - current) + " millis");
+    }
+
+    /**
+     * Upholds the validity of enabled data for the user.
+     * All rows which are enabled but are now flagged with non-indexable keys will become disabled.
+     * All rows which are disabled but no longer a non-indexable key will become enabled.
+     *
+     * @param database The database to validate.
+     * @param nonIndexableKeys A map between package name and the set of non-indexable keys for it.
+     */
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    void updateDataInDatabase(SQLiteDatabase database,
+            Map<String, Set<String>> nonIndexableKeys) {
+        final String whereEnabled = ENABLED + " = 1";
+        final String whereDisabled = ENABLED + " = 0";
+
+        final Cursor enabledResults = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS,
+                whereEnabled, null, null, null, null);
+
+        final ContentValues enabledToDisabledValue = new ContentValues();
+        enabledToDisabledValue.put(ENABLED, 0);
+
+        String packageName;
+        // TODO Refactor: Move these two loops into one method.
+        while (enabledResults.moveToNext()) {
+            // Package name is the key for remote providers.
+            // If package name is null, the provider is Settings.
+            packageName = enabledResults.getString(COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
+            if (packageName == null) {
+                packageName = mContext.getPackageName();
+            }
+
+            final String key = enabledResults.getString(COLUMN_INDEX_KEY);
+            final Set<String> packageKeys = nonIndexableKeys.get(packageName);
+
+            // The indexed item is set to Enabled but is now non-indexable
+            if (packageKeys != null && packageKeys.contains(key)) {
+                final String whereClause = DOCID + " = " + enabledResults.getInt(COLUMN_INDEX_ID);
+                database.update(TABLE_PREFS_INDEX, enabledToDisabledValue, whereClause, null);
+            }
+        }
+        enabledResults.close();
+
+        final Cursor disabledResults = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS,
+                whereDisabled, null, null, null, null);
+
+        final ContentValues disabledToEnabledValue = new ContentValues();
+        disabledToEnabledValue.put(ENABLED, 1);
+
+        while (disabledResults.moveToNext()) {
+            // Package name is the key for remote providers.
+            // If package name is null, the provider is Settings.
+            packageName = disabledResults.getString(COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
+            if (packageName == null) {
+                packageName = mContext.getPackageName();
+            }
+
+            final String key = disabledResults.getString(COLUMN_INDEX_KEY);
+            final Set<String> packageKeys = nonIndexableKeys.get(packageName);
+
+            // The indexed item is set to Disabled but is no longer non-indexable.
+            // We do not enable keys when packageKeys is null because it means the keys came
+            // from an unrecognized package and therefore should not be surfaced as results.
+            if (packageKeys != null && !packageKeys.contains(key)) {
+                String whereClause = DOCID + " = " + disabledResults.getInt(COLUMN_INDEX_ID);
+                database.update(TABLE_PREFS_INDEX, disabledToEnabledValue, whereClause, null);
+            }
+        }
+        disabledResults.close();
+    }
+
+    @VisibleForTesting
+    boolean addIndexablesFromRemoteProvider(String packageName, String authority) {
+        try {
+            // TODO delete base rank. does nothing.
             final int baseRank = Ranking.getBaseRankForAuthority(authority);
 
             final Context context = mBaseAuthority.equals(authority) ?
@@ -202,11 +367,12 @@
         }
     }
 
-    private void addNonIndexablesKeysFromRemoteProvider(String packageName,
+    @VisibleForTesting
+    void addNonIndexablesKeysFromRemoteProvider(String packageName,
             String authority) {
         final List<String> keys =
                 getNonIndexablesKeysFromRemoteProvider(packageName, authority);
-        addNonIndexableKeys(packageName, keys);
+        addNonIndexableKeys(packageName, new HashSet<>(keys));
     }
 
     private List<String> getNonIndexablesKeysFromRemoteProvider(String packageName,
@@ -235,7 +401,7 @@
             return EMPTY_LIST;
         }
 
-        List<String> result = new ArrayList<String>();
+        final List<String> result = new ArrayList<>();
         try {
             final int count = cursor.getCount();
             if (count > 0) {
@@ -256,31 +422,19 @@
         }
     }
 
-    public void deleteIndexableData(SearchIndexableData data) {
-        synchronized (mDataToProcess) {
-            mDataToProcess.dataToDelete.add(data);
-        }
-    }
-
-    public void addNonIndexableKeys(String authority, List<String> keys) {
+    public void addNonIndexableKeys(String authority, Set<String> keys) {
         synchronized (mDataToProcess) {
             mDataToProcess.nonIndexableKeys.put(authority, keys);
         }
     }
 
-    private void updateFromRemoteProvider(String packageName, String authority) {
-        if (addIndexablesFromRemoteProvider(packageName, authority)) {
-            updateInternal();
-        }
-    }
-
     /**
      * Update the Index for a specific class name resources
      *
-     * @param className the class name (typically a fragment name).
-     * @param rebuild true means that you want to delete the data from the Index first.
+     * @param className              the class name (typically a fragment name).
+     * @param rebuild                true means that you want to delete the data from the Index first.
      * @param includeInSearchResults true means that you want the bit "enabled" set so that the
-     * data will be seen included into the search results
+     *                               data will be seen included into the search results
      */
     public void updateFromClassNameResource(String className, final boolean rebuild,
             boolean includeInSearchResults) {
@@ -297,12 +451,8 @@
         AsyncTask.execute(new Runnable() {
             @Override
             public void run() {
-                if (rebuild) {
-                    deleteIndexableData(res);
-                }
                 addIndexableData(res);
-                mDataToProcess.forceUpdate = true;
-                updateInternal();
+                performIndexing();
                 res.enabled = false;
             }
         });
@@ -313,8 +463,7 @@
             @Override
             public void run() {
                 addIndexableData(data);
-                mDataToProcess.forceUpdate = true;
-                updateInternal();
+                performIndexing();
             }
         });
     }
@@ -347,16 +496,6 @@
                 SearchIndexablesContract.NON_INDEXABLES_KEYS_PATH);
     }
 
-    private void updateInternal() {
-        synchronized (mDataToProcess) {
-            final DatabaseIndexingManager.UpdateIndexTask task =
-                    new DatabaseIndexingManager.UpdateIndexTask();
-            DatabaseIndexingManager.UpdateData copy = mDataToProcess.copy();
-            task.execute(copy);
-            mDataToProcess.clear();
-        }
-    }
-
     private void addIndexablesForXmlResourceUri(Context packageContext, String packageName,
             Uri uri, String[] projection, int baseRank) {
 
@@ -468,7 +607,7 @@
     }
 
     public void indexOneSearchIndexableData(SQLiteDatabase database, String localeStr,
-            SearchIndexableData data, Map<String, List<String>> nonIndexableKeys) {
+            SearchIndexableData data, Map<String, Set<String>> nonIndexableKeys) {
         if (data instanceof SearchIndexableResource) {
             indexOneResource(database, localeStr, (SearchIndexableResource) data, nonIndexableKeys);
         } else if (data instanceof SearchIndexableRaw) {
@@ -502,7 +641,7 @@
     }
 
     private void indexOneResource(SQLiteDatabase database, String localeStr,
-            SearchIndexableResource sir, Map<String, List<String>> nonIndexableKeysFromResource) {
+            SearchIndexableResource sir, Map<String, Set<String>> nonIndexableKeysFromResource) {
 
         if (sir == null) {
             Log.e(LOG_TAG, "Cannot index a null resource!");
@@ -512,9 +651,9 @@
         final List<String> nonIndexableKeys = new ArrayList<String>();
 
         if (sir.xmlResId > SearchIndexableResources.NO_DATA_RES_ID) {
-            List<String> resNonIndxableKeys = nonIndexableKeysFromResource.get(sir.packageName);
-            if (resNonIndxableKeys != null && resNonIndxableKeys.size() > 0) {
-                nonIndexableKeys.addAll(resNonIndxableKeys);
+            Set<String> resNonIndexableKeys = nonIndexableKeysFromResource.get(sir.packageName);
+            if (resNonIndexableKeys != null && resNonIndexableKeys.size() > 0) {
+                nonIndexableKeys.addAll(resNonIndexableKeys);
             }
 
             indexFromResource(database, localeStr, sir, nonIndexableKeys);
@@ -605,6 +744,7 @@
             headerKeywords = XmlParserUtils.getDataKeywords(context, attrs);
             enabled = !nonIndexableKeys.contains(key);
 
+            // TODO: Set payload type for header results
             DatabaseRow.Builder headerBuilder = new DatabaseRow.Builder();
             headerBuilder.setLocale(localeStr)
                     .setEntries(null)
@@ -799,31 +939,29 @@
 
         ContentValues values = new ContentValues();
         values.put(IndexDatabaseHelper.IndexColumns.DOCID, row.getDocId());
-        values.put(IndexDatabaseHelper.IndexColumns.LOCALE, row.locale);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, row.rank);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, row.updatedTitle);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, row.normalizedTitle);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, row.updatedSummaryOn);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED,
-                row.normalizedSummaryOn);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, row.updatedSummaryOff);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED,
-                row.normalizedSummaryOff);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, row.entries);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, row.spaceDelimitedKeywords);
-        values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, row.className);
-        values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, row.screenTitle);
-        values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, row.intentAction);
-        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, row.intentTargetPackage);
-        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, row.intentTargetClass);
-        values.put(IndexDatabaseHelper.IndexColumns.ICON, row.iconResId);
-        values.put(IndexDatabaseHelper.IndexColumns.ENABLED, row.enabled);
-        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, row.key);
-        values.put(IndexDatabaseHelper.IndexColumns.USER_ID, row.userId);
-        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, row.payloadType);
-        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, row.payload);
+        values.put(LOCALE, row.locale);
+        values.put(DATA_RANK, row.rank);
+        values.put(DATA_TITLE, row.updatedTitle);
+        values.put(DATA_TITLE_NORMALIZED, row.normalizedTitle);
+        values.put(DATA_SUMMARY_ON, row.updatedSummaryOn);
+        values.put(DATA_SUMMARY_ON_NORMALIZED, row.normalizedSummaryOn);
+        values.put(DATA_SUMMARY_OFF, row.updatedSummaryOff);
+        values.put(DATA_SUMMARY_OFF_NORMALIZED, row.normalizedSummaryOff);
+        values.put(DATA_ENTRIES, row.entries);
+        values.put(DATA_KEYWORDS, row.spaceDelimitedKeywords);
+        values.put(CLASS_NAME, row.className);
+        values.put(SCREEN_TITLE, row.screenTitle);
+        values.put(INTENT_ACTION, row.intentAction);
+        values.put(INTENT_TARGET_PACKAGE, row.intentTargetPackage);
+        values.put(INTENT_TARGET_CLASS, row.intentTargetClass);
+        values.put(ICON, row.iconResId);
+        values.put(ENABLED, row.enabled);
+        values.put(DATA_KEY_REF, row.key);
+        values.put(USER_ID, row.userId);
+        values.put(PAYLOAD_TYPE, row.payloadType);
+        values.put(PAYLOAD, row.payload);
 
-        database.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
+        database.replaceOrThrow(TABLE_PREFS_INDEX, null, values);
 
         if (!TextUtils.isEmpty(row.className) && !TextUtils.isEmpty(row.childClassName)) {
             ContentValues siteMapPair = new ContentValues();
@@ -839,129 +977,34 @@
     }
 
     /**
-     * A private class for updating the Index database
+     * A private class to describe the indexDatabase data for the Index database
      */
-    private class UpdateIndexTask extends AsyncTask<DatabaseIndexingManager.UpdateData, Integer,
-            Void> {
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    static class UpdateData {
+        public List<SearchIndexableData> dataToUpdate;
+        public List<SearchIndexableData> dataToDisable;
+        public Map<String, Set<String>> nonIndexableKeys;
 
-        @Override
-        protected void onPreExecute() {
-            super.onPreExecute();
-            mIsAvailable.set(false);
+        public UpdateData() {
+            dataToUpdate = new ArrayList<>();
+            dataToDisable = new ArrayList<>();
+            nonIndexableKeys = new HashMap<>();
         }
 
-        @Override
-        protected void onPostExecute(Void aVoid) {
-            super.onPostExecute(aVoid);
-            mIsAvailable.set(true);
+        public UpdateData(UpdateData other) {
+            dataToUpdate = new ArrayList<>(other.dataToUpdate);
+            dataToDisable = new ArrayList<>(other.dataToDisable);
+            nonIndexableKeys = new HashMap<>(other.nonIndexableKeys);
         }
 
-        @Override
-        protected Void doInBackground(DatabaseIndexingManager.UpdateData... params) {
-            try {
-                final List<SearchIndexableData> dataToUpdate = params[0].dataToUpdate;
-                final List<SearchIndexableData> dataToDelete = params[0].dataToDelete;
-                final Map<String, List<String>> nonIndexableKeys = params[0].nonIndexableKeys;
-
-                final boolean forceUpdate = params[0].forceUpdate;
-                final boolean fullIndex = params[0].fullIndex;
-
-                final SQLiteDatabase database = getWritableDatabase();
-                if (database == null) {
-                    Log.e(LOG_TAG, "Cannot update Index as I cannot get a writable database");
-                    return null;
-                }
-                final String localeStr = Locale.getDefault().toString();
-
-                try {
-                    database.beginTransaction();
-                    if (dataToDelete.size() > 0) {
-                        processDataToDelete(database, localeStr, dataToDelete);
-                    }
-                    if (dataToUpdate.size() > 0) {
-                        processDataToUpdate(database, localeStr, dataToUpdate, nonIndexableKeys,
-                                forceUpdate);
-                    }
-                    database.setTransactionSuccessful();
-                } finally {
-                    database.endTransaction();
-                }
-                if (fullIndex) {
-                    IndexDatabaseHelper.setLocaleIndexed(mContext, localeStr);
-                }
-            } catch (SQLiteFullException e) {
-                Log.e(LOG_TAG, "Unable to index search, out of space", e);
-            }
-
-            return null;
+        public UpdateData copy() {
+            return new UpdateData(this);
         }
 
-        private boolean processDataToUpdate(SQLiteDatabase database, String localeStr,
-                List<SearchIndexableData> dataToUpdate, Map<String, List<String>> nonIndexableKeys,
-                boolean forceUpdate) {
-
-            if (!forceUpdate && IndexDatabaseHelper.isLocaleAlreadyIndexed(mContext, localeStr)) {
-                Log.d(LOG_TAG, "Locale '" + localeStr + "' is already indexed");
-                return true;
-            }
-
-            boolean result = false;
-            final long current = System.currentTimeMillis();
-
-            final int count = dataToUpdate.size();
-            for (int n = 0; n < count; n++) {
-                final SearchIndexableData data = dataToUpdate.get(n);
-                try {
-                    indexOneSearchIndexableData(database, localeStr, data, nonIndexableKeys);
-                } catch (Exception e) {
-                    Log.e(LOG_TAG, "Cannot index: " + (data != null ? data.className : data)
-                            + " for locale: " + localeStr, e);
-                }
-            }
-
-            final long now = System.currentTimeMillis();
-            Log.d(LOG_TAG, "Indexing locale '" + localeStr + "' took " +
-                    (now - current) + " millis");
-            return result;
-        }
-
-        private boolean processDataToDelete(SQLiteDatabase database, String localeStr,
-                List<SearchIndexableData> dataToDelete) {
-
-            boolean result = false;
-            final long current = System.currentTimeMillis();
-
-            final int count = dataToDelete.size();
-            for (int n = 0; n < count; n++) {
-                final SearchIndexableData data = dataToDelete.get(n);
-                if (data == null) {
-                    continue;
-                }
-                if (!TextUtils.isEmpty(data.className)) {
-                    delete(database, IndexDatabaseHelper.IndexColumns.CLASS_NAME, data.className);
-                } else {
-                    if (data instanceof SearchIndexableRaw) {
-                        final SearchIndexableRaw raw = (SearchIndexableRaw) data;
-                        if (!TextUtils.isEmpty(raw.title)) {
-                            delete(database, IndexDatabaseHelper.IndexColumns.DATA_TITLE,
-                                    raw.title);
-                        }
-                    }
-                }
-            }
-
-            final long now = System.currentTimeMillis();
-            Log.d(LOG_TAG, "Deleting data for locale '" + localeStr + "' took " +
-                    (now - current) + " millis");
-            return result;
-        }
-
-        private int delete(SQLiteDatabase database, String columName, String value) {
-            final String whereClause = columName + "=?";
-            final String[] whereArgs = new String[]{value};
-
-            return database.delete(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, whereClause,
-                    whereArgs);
+        public void clear() {
+            dataToUpdate.clear();
+            dataToDisable.clear();
+            nonIndexableKeys.clear();
         }
     }
 
diff --git a/src/com/android/settings/search2/SavedQueryController.java b/src/com/android/settings/search2/SavedQueryController.java
new file mode 100644
index 0000000..92ca42a
--- /dev/null
+++ b/src/com/android/settings/search2/SavedQueryController.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 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.search2;
+
+import android.app.LoaderManager;
+import android.content.Context;
+import android.content.Loader;
+import android.os.Bundle;
+
+import com.android.settings.overlay.FeatureFactory;
+
+import java.util.List;
+
+public class SavedQueryController implements LoaderManager.LoaderCallbacks {
+
+    // TODO: make a generic background task manager to handle one-off tasks like this one.
+
+    private static final int LOADER_ID_SAVE_QUERY_TASK = 0;
+    private static final int LOADER_ID_REMOVE_QUERY_TASK = 1;
+    private static final int LOADER_ID_SAVED_QUERIES = 2;
+    private static final String ARG_QUERY = "remove_query";
+
+    private final Context mContext;
+    private final LoaderManager mLoaderManager;
+    private final SearchFeatureProvider mSearchFeatureProvider;
+    private final SearchResultsAdapter mResultAdapter;
+
+    public SavedQueryController(Context context, LoaderManager loaderManager,
+            SearchResultsAdapter resultsAdapter) {
+        mContext = context;
+        mLoaderManager = loaderManager;
+        mResultAdapter = resultsAdapter;
+        mSearchFeatureProvider = FeatureFactory.getFactory(context)
+                .getSearchFeatureProvider();
+    }
+
+    @Override
+    public Loader onCreateLoader(int id, Bundle args) {
+        switch (id) {
+            case LOADER_ID_SAVE_QUERY_TASK:
+                return new SavedQueryRecorder(mContext, args.getString(ARG_QUERY));
+            case LOADER_ID_REMOVE_QUERY_TASK:
+                return new SavedQueryRemover(mContext, args.getString(ARG_QUERY));
+            case LOADER_ID_SAVED_QUERIES:
+                return mSearchFeatureProvider.getSavedQueryLoader(mContext);
+        }
+        return null;
+    }
+
+    @Override
+    public void onLoadFinished(Loader loader, Object data) {
+        switch (loader.getId()) {
+            case LOADER_ID_REMOVE_QUERY_TASK:
+                mLoaderManager.restartLoader(LOADER_ID_SAVED_QUERIES, null, this);
+                break;
+            case LOADER_ID_SAVED_QUERIES:
+                mResultAdapter.displaySavedQuery((List<SearchResult>) data);
+                break;
+        }
+    }
+
+    @Override
+    public void onLoaderReset(Loader loader) {
+
+    }
+
+    public void saveQuery(String query) {
+        final Bundle args = new Bundle();
+        args.putString(ARG_QUERY, query);
+        mLoaderManager.restartLoader(LOADER_ID_SAVE_QUERY_TASK, args, this);
+    }
+
+    public void removeQuery(String query) {
+        final Bundle args = new Bundle();
+        args.putString(ARG_QUERY, query);
+        mLoaderManager.restartLoader(LOADER_ID_REMOVE_QUERY_TASK, args, this);
+    }
+
+    public void loadSavedQueries() {
+        mLoaderManager.restartLoader(LOADER_ID_SAVED_QUERIES, null, this);
+    }
+}
diff --git a/src/com/android/settings/search2/SearchFragment.java b/src/com/android/settings/search2/SearchFragment.java
index 02ff2c8..eb760ee 100644
--- a/src/com/android/settings/search2/SearchFragment.java
+++ b/src/com/android/settings/search2/SearchFragment.java
@@ -54,11 +54,11 @@
 
     // State values
     private static final String STATE_QUERY = "state_query";
+    private static final String STATE_SHOWING_SAVED_QUERY = "state_showing_saved_query";
     private static final String STATE_NEVER_ENTERED_QUERY = "state_never_entered_query";
     private static final String STATE_RESULT_CLICK_COUNT = "state_result_click_count";
 
     // Loader IDs
-    private static final int LOADER_ID_RECENTS = 0;
     private static final int LOADER_ID_DATABASE = 1;
     private static final int LOADER_ID_INSTALLED_APPS = 2;
 
@@ -74,12 +74,11 @@
     @VisibleForTesting
     String mQuery;
 
-    private final SaveQueryCallback mSaveQueryCallback =
-            new SaveQueryCallback();
-
     private boolean mNeverEnteredQuery = true;
+    private boolean mShowingSavedQuery;
     private int mResultClickCount;
     private MetricsFeatureProvider mMetricsFeatureProvider;
+    private SavedQueryController mSavedQueryController;
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     SearchFeatureProvider mSearchFeatureProvider;
@@ -117,20 +116,26 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setHasOptionsMenu(true);
-        mSearchAdapter = new SearchResultsAdapter(this);
-
-        mSearchFeatureProvider.initFeedbackButton();
-
         final LoaderManager loaderManager = getLoaderManager();
+        mSearchAdapter = new SearchResultsAdapter(this);
+        mSavedQueryController = new SavedQueryController(
+                getContext(), loaderManager, mSearchAdapter);
+        mSearchFeatureProvider.initFeedbackButton();
 
         if (savedInstanceState != null) {
             mQuery = savedInstanceState.getString(STATE_QUERY);
             mNeverEnteredQuery = savedInstanceState.getBoolean(STATE_NEVER_ENTERED_QUERY);
             mResultClickCount = savedInstanceState.getInt(STATE_RESULT_CLICK_COUNT);
-            loaderManager.initLoader(LOADER_ID_DATABASE, null, this);
-            loaderManager.initLoader(LOADER_ID_INSTALLED_APPS, null, this);
+            mShowingSavedQuery = savedInstanceState.getBoolean(STATE_SHOWING_SAVED_QUERY);
+            if (mShowingSavedQuery) {
+                mSavedQueryController.loadSavedQueries();
+            } else {
+                loaderManager.initLoader(LOADER_ID_DATABASE, null, this);
+                loaderManager.initLoader(LOADER_ID_INSTALLED_APPS, null, this);
+            }
         } else {
-            loaderManager.initLoader(LOADER_ID_RECENTS, null, this);
+            mShowingSavedQuery = true;
+            mSavedQueryController.loadSavedQueries();
         }
 
         final Activity activity = getActivity();
@@ -180,6 +185,7 @@
         super.onSaveInstanceState(outState);
         outState.putString(STATE_QUERY, mQuery);
         outState.putBoolean(STATE_NEVER_ENTERED_QUERY, mNeverEnteredQuery);
+        outState.putBoolean(STATE_SHOWING_SAVED_QUERY, mShowingSavedQuery);
         outState.putInt(STATE_RESULT_CLICK_COUNT, mResultClickCount);
     }
 
@@ -206,7 +212,8 @@
             final LoaderManager loaderManager = getLoaderManager();
             loaderManager.destroyLoader(LOADER_ID_DATABASE);
             loaderManager.destroyLoader(LOADER_ID_INSTALLED_APPS);
-            loaderManager.restartLoader(LOADER_ID_RECENTS, null /* args */, this /* callback */);
+            mShowingSavedQuery = true;
+            mSavedQueryController.loadSavedQueries();
             mSearchFeatureProvider.hideFeedbackButton();
         } else {
             restartLoaders();
@@ -218,8 +225,7 @@
     @Override
     public boolean onQueryTextSubmit(String query) {
         // Save submitted query.
-        getLoaderManager().restartLoader(SaveQueryCallback.LOADER_ID_SAVE_QUERY_TASK, null,
-                mSaveQueryCallback);
+        mSavedQueryController.saveQuery(mQuery);
         hideKeyboard();
         return true;
     }
@@ -233,8 +239,6 @@
                 return mSearchFeatureProvider.getDatabaseSearchLoader(activity, mQuery);
             case LOADER_ID_INSTALLED_APPS:
                 return mSearchFeatureProvider.getInstalledAppSearchLoader(activity, mQuery);
-            case LOADER_ID_RECENTS:
-                return mSearchFeatureProvider.getSavedQueryLoader(activity);
             default:
                 return null;
         }
@@ -243,18 +247,11 @@
     @Override
     public void onLoadFinished(Loader<List<? extends SearchResult>> loader,
             List<? extends SearchResult> data) {
-        final int resultCount;
-        switch (loader.getId()) {
-            case LOADER_ID_RECENTS:
-                resultCount = mSearchAdapter.displaySavedQuery(data);
-                break;
-            default:
-                mSearchAdapter.addSearchResults(data, loader.getClass().getName());
-                if (mUnfinishedLoadersCount.decrementAndGet() != 0) {
-                    return;
-                }
-                resultCount = mSearchAdapter.displaySearchResults();
+        mSearchAdapter.addSearchResults(data, loader.getClass().getName());
+        if (mUnfinishedLoadersCount.decrementAndGet() != 0) {
+            return;
         }
+        final int resultCount = mSearchAdapter.displaySearchResults();
         mNoResultsView.setVisibility(resultCount == 0 ? View.VISIBLE : View.GONE);
         mSearchFeatureProvider.showFeedbackButton(this, getView());
     }
@@ -264,8 +261,7 @@
     }
 
     public void onSearchResultClicked() {
-        getLoaderManager().restartLoader(SaveQueryCallback.LOADER_ID_SAVE_QUERY_TASK, null,
-                mSaveQueryCallback);
+        mSavedQueryController.saveQuery(mQuery);
         mResultClickCount++;
     }
 
@@ -278,13 +274,11 @@
     }
 
     public void onRemoveSavedQueryClicked(CharSequence title) {
-        final Bundle args = new Bundle();
-        args.putString(SaveQueryCallback.ARG_REMOVE_QUERY, title.toString());
-        getLoaderManager().restartLoader(SaveQueryCallback.LOADER_ID_REMOVE_QUERY_TASK,
-                args, mSaveQueryCallback);
+        mSavedQueryController.removeQuery(title.toString());
     }
 
     private void restartLoaders() {
+        mShowingSavedQuery = false;
         final LoaderManager loaderManager = getLoaderManager();
         mUnfinishedLoadersCount.set(NUM_QUERY_LOADERS);
         loaderManager.restartLoader(LOADER_ID_DATABASE, null /* args */, this /* callback */);
@@ -325,37 +319,4 @@
             mResultsRecyclerView.requestFocus();
         }
     }
-
-    private class SaveQueryCallback implements LoaderManager.LoaderCallbacks<Void> {
-        // TODO: make a generic background task manager to handle one-off tasks like this one.
-
-        private static final int LOADER_ID_SAVE_QUERY_TASK = 0;
-        private static final int LOADER_ID_REMOVE_QUERY_TASK = 1;
-        private static final String ARG_REMOVE_QUERY = "remove_query";
-
-        @Override
-        public Loader<Void> onCreateLoader(int id, Bundle args) {
-            switch (id) {
-                case LOADER_ID_SAVE_QUERY_TASK:
-                    return new SavedQueryRecorder(getActivity(), mQuery);
-                case LOADER_ID_REMOVE_QUERY_TASK:
-                    return new SavedQueryRemover(getActivity(), args.getString(ARG_REMOVE_QUERY));
-            }
-            return null;
-        }
-
-        @Override
-        public void onLoadFinished(Loader<Void> loader, Void data) {
-            switch (loader.getId()) {
-                case LOADER_ID_REMOVE_QUERY_TASK:
-                    getLoaderManager().restartLoader(LOADER_ID_RECENTS, null, SearchFragment.this);
-                    break;
-            }
-        }
-
-        @Override
-        public void onLoaderReset(Loader<Void> loader) {
-
-        }
-    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/sim/SimDialogActivity.java b/src/com/android/settings/sim/SimDialogActivity.java
index dccba13..853f80d 100644
--- a/src/com/android/settings/sim/SimDialogActivity.java
+++ b/src/com/android/settings/sim/SimDialogActivity.java
@@ -59,8 +59,7 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        final Bundle extras = getIntent().getExtras();
-        final int dialogType = extras.getInt(DIALOG_TYPE_KEY, INVALID_PICK);
+        final int dialogType = getIntent().getIntExtra(DIALOG_TYPE_KEY, INVALID_PICK);
 
         switch (dialogType) {
             case DATA_PICK:
@@ -69,7 +68,7 @@
                 createDialog(this, dialogType).show();
                 break;
             case PREFERRED_PICK:
-                displayPreferredDialog(extras.getInt(PREFERRED_SIM));
+                displayPreferredDialog(getIntent().getIntExtra(PREFERRED_SIM, 0));
                 break;
             default:
                 throw new IllegalArgumentException("Invalid dialog type " + dialogType + " sent.");
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 5f489f2..1ed25f2 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -32,6 +32,7 @@
 import android.support.v7.preference.PreferenceScreen;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.core.PreferenceController;
 import com.android.settings.core.lifecycle.Lifecycle;
@@ -53,15 +54,24 @@
         LifecycleObserver, OnResume {
     private static final String TAG = "WifiDetailsPrefCtrl";
 
-    private static final String KEY_CONNECTION_DETAIL_PREF = "connection_detail";
-    private static final String KEY_SIGNAL_STRENGTH_PREF = "signal_strength";
-    private static final String KEY_FREQUENCY_PREF = "frequency";
-    private static final String KEY_SECURITY_PREF = "security";
-    private static final String KEY_IP_ADDRESS_PREF = "ip_address";
-    private static final String KEY_ROUTER_PREF = "router";
-    private static final String KEY_SUBNET_MASK_PREF = "subnet_mask";
-    private static final String KEY_DNS_PREF = "dns";
-    private static final String KEY_IPV6_ADDRESS_CATEGORY = "ipv6_details_category";
+    @VisibleForTesting
+    static final String KEY_CONNECTION_DETAIL_PREF = "connection_detail";
+    @VisibleForTesting
+    static final String KEY_SIGNAL_STRENGTH_PREF = "signal_strength";
+    @VisibleForTesting
+    static final String KEY_FREQUENCY_PREF = "frequency";
+    @VisibleForTesting
+    static final String KEY_SECURITY_PREF = "security";
+    @VisibleForTesting
+    static final String KEY_IP_ADDRESS_PREF = "ip_address";
+    @VisibleForTesting
+    static final String KEY_ROUTER_PREF = "router";
+    @VisibleForTesting
+    static final String KEY_SUBNET_MASK_PREF = "subnet_mask";
+    @VisibleForTesting
+    static final String KEY_DNS_PREF = "dns";
+    @VisibleForTesting
+    static final String KEY_IPV6_ADDRESS_CATEGORY = "ipv6_details_category";
 
     private AccessPoint mAccessPoint;
     private NetworkInfo mNetworkInfo;
@@ -166,7 +176,7 @@
                 R.color.wifi_details_icon_color, mContext.getTheme()));
         mSignalStrengthPref.setIcon(wifiIconDark);
 
-        int summarySignalLevel = WifiManager.calculateSignalLevel(mRssi, mSignalStr.length);
+        int summarySignalLevel = mAccessPoint.getLevel();
         mSignalStrengthPref.setDetailText(mSignalStr[summarySignalLevel]);
 
         // Frequency Pref
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index 0a80f21..0073202 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -23,7 +23,6 @@
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
-import com.android.settings.SettingsActivity;
 import com.android.settings.applications.LayoutPreference;
 import com.android.settings.core.PreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
diff --git a/tests/app/src/com/android/settings/ConfirmLockPasswordTest.java b/tests/app/src/com/android/settings/ConfirmLockPasswordTest.java
new file mode 100644
index 0000000..05464ad
--- /dev/null
+++ b/tests/app/src/com/android/settings/ConfirmLockPasswordTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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 static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.pressKey;
+import static android.support.test.espresso.action.ViewActions.typeText;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.KeyEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ConfirmLockPasswordTest {
+
+    private Instrumentation mInstrumentation;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
+    }
+
+    @Test
+    public void enterWrongPin_shouldShowErrorMessage() {
+        mInstrumentation.startActivitySync(
+                new Intent(mContext, ConfirmLockPassword.class));
+        onView(withId(R.id.password_entry)).perform(typeText("1234"))
+                .perform(pressKey(KeyEvent.KEYCODE_ENTER));
+        onView(withId(R.id.errorText)).check(matches(withText(R.string.lockpassword_invalid_pin)));
+    }
+
+    @Test
+    public void enterWrongPin_darkTheme_shouldShowErrorMessage() {
+        mInstrumentation.startActivitySync(
+                new Intent(mContext, ConfirmLockPassword.class)
+                        .putExtra(ConfirmDeviceCredentialBaseFragment.DARK_THEME, true));
+        onView(withId(R.id.password_entry)).perform(typeText("1234"))
+                .perform(pressKey(KeyEvent.KEYCODE_ENTER));
+        onView(withId(R.id.errorText)).check(matches(withText(R.string.lockpassword_invalid_pin)));
+    }
+}
diff --git a/tests/robotests/src/android/net/NetworkBadging.java b/tests/robotests/src/android/net/NetworkBadging.java
new file mode 100644
index 0000000..32bb31f
--- /dev/null
+++ b/tests/robotests/src/android/net/NetworkBadging.java
@@ -0,0 +1,34 @@
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Implementation for {@link android.net.NetworkBadging}.
+ *
+ * <p>Can be removed once Robolectric supports Android O.
+ */
+public class NetworkBadging {
+    @IntDef({BADGING_NONE, BADGING_SD, BADGING_HD, BADGING_4K})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Badging {}
+
+    public static final int BADGING_NONE = 0;
+    public static final int BADGING_SD = 10;
+    public static final int BADGING_HD = 20;
+    public static final int BADGING_4K = 30;
+
+    private static Drawable drawable;
+
+    public static Drawable getWifiIcon(
+            int signalLevel, @NetworkBadging.Badging int badging, @Nullable Resources.Theme theme) {
+        return new ColorDrawable(Color.GREEN);
+    }
+}
diff --git a/tests/robotests/src/android/net/wifi/WifiNetworkScoreCache.java b/tests/robotests/src/android/net/wifi/WifiNetworkScoreCache.java
new file mode 100644
index 0000000..08b2971
--- /dev/null
+++ b/tests/robotests/src/android/net/wifi/WifiNetworkScoreCache.java
@@ -0,0 +1,10 @@
+package android.net.wifi;
+
+/**
+ * Empty class def for {@link android.net.wifi.WifiNetworkScoreCache}.
+ *
+ * <p>Can be removed once Robolectric supports Android O.
+ */
+public class WifiNetworkScoreCache {
+
+}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/UsbModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/UsbModePreferenceControllerTest.java
index da25f0f..8b6e900 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/UsbModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/UsbModePreferenceControllerTest.java
@@ -113,7 +113,7 @@
         preference.setEnabled(true);
         mController.updateState(preference);
         assertThat(preference.getSummary()).isEqualTo(
-                mContext.getString(R.string.usb_nothing_connected));
+                mContext.getString(R.string.disconnected));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
index 31ffad0..e35fa33 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
@@ -74,8 +74,8 @@
         mDashboardCategory.tiles = new ArrayList<>();
         mDashboardCategory.tiles.add(new Tile());
         mTestFragment = new TestFragment(ShadowApplication.getInstance().getApplicationContext());
-        when(mFakeFeatureFactory.dashboardFeatureProvider
-                .getProgressiveDisclosureMixin(any(Context.class), eq(mTestFragment)))
+        when(mFakeFeatureFactory.dashboardFeatureProvider.getProgressiveDisclosureMixin(
+                any(Context.class), eq(mTestFragment), any(Bundle.class)))
                 .thenReturn(mDisclosureMixin);
         when(mFakeFeatureFactory.dashboardFeatureProvider.getTilesForCategory(anyString()))
                 .thenReturn(mDashboardCategory);
diff --git a/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java b/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
index e872a09..bae6f8f 100644
--- a/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/ProgressiveDisclosureTest.java
@@ -77,8 +77,7 @@
         mAppContext = ShadowApplication.getInstance().getApplicationContext();
         mFakeFeatureFactory = (FakeFeatureFactory) FeatureFactory.getFactory(mContext);
         mMixin = new ProgressiveDisclosureMixin(mAppContext,
-                mFakeFeatureFactory.metricsFeatureProvider,
-                mPreferenceFragment);
+                mPreferenceFragment, false /* keepExpanded */);
         ReflectionHelpers.setField(mMixin, "mExpandButton", mExpandButton);
         mPreference = new Preference(mAppContext);
         mPreference.setKey("test");
@@ -94,6 +93,17 @@
     }
 
     @Test
+    public void shouldNotCollapse_whenStartAsExpanded() {
+        when(mScreen.getPreferenceCount()).thenReturn(5);
+
+        mMixin = new ProgressiveDisclosureMixin(mAppContext,
+                mPreferenceFragment, true /* keepExpanded */);
+        mMixin.setTileLimit(10);
+
+        assertThat(mMixin.shouldCollapse(mScreen)).isFalse();
+    }
+
+    @Test
     public void shouldCollapse_morePreferenceThanLimit() {
         when(mScreen.getPreferenceCount()).thenReturn(5);
         mMixin.setTileLimit(3);
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
index 4622850..961a6c7 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -216,6 +216,7 @@
         result.gamesSize = KILOBYTE * 8;
         result.musicAppsSize = KILOBYTE * 4;
         result.otherAppsSize = KILOBYTE * 9;
+        result.systemSize = KILOBYTE * 10;
         result.externalStats = new StorageStatsSource.ExternalStorageStats(
                 KILOBYTE * 50, // total
                 KILOBYTE * 10, // audio
@@ -230,7 +231,7 @@
         assertThat(image.getSummary().toString()).isEqualTo("35.00KB"); // 15KB video + 20KB images
         assertThat(games.getSummary().toString()).isEqualTo("8.00KB");
         assertThat(apps.getSummary().toString()).isEqualTo("9.00KB");
-        assertThat(system.getSummary().toString()).isEqualTo("6.00KB");
+        assertThat(system.getSummary().toString()).isEqualTo("16.00KB");
         assertThat(files.getSummary().toString()).isEqualTo("5.00KB");
     }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java b/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
index fdc1052..d537bc9 100644
--- a/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
+++ b/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -17,37 +17,65 @@
 
 package com.android.settings.search2;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentProvider;
+import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
 import android.database.Cursor;
+import android.database.MatrixCursor;
 import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
 import android.provider.SearchIndexableResource;
-
+import android.provider.SearchIndexablesContract;
+import android.util.ArrayMap;
 import com.android.settings.R;
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 import com.android.settings.search.IndexDatabaseHelper;
 import com.android.settings.search.SearchIndexableRaw;
 import com.android.settings.testutils.DatabaseTestUtils;
-
+import com.android.settings.testutils.shadow.ShadowDatabaseIndexingUtils;
+import com.android.settings.testutils.shadow.ShadowRunnableAsyncTask;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowContentResolver;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyList;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 @RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
+        shadows={ShadowRunnableAsyncTask.class})
 public class DatabaseIndexingManagerTest {
     private final String localeStr = "en_US";
 
@@ -75,15 +103,30 @@
     private final int userId = -1;
     private final boolean enabled = true;
 
+    private final String AUTHORITY_ONE = "authority";
+    private final String PACKAGE_ONE = "com.android.settings";
+
+    private final String TITLE_ONE = "title one";
+    private final String TITLE_TWO = "title two";
+    private final String KEY_ONE = "key one";
+    private final String KEY_TWO = "key two";
+
     private Context mContext;
+
     private DatabaseIndexingManager mManager;
     private SQLiteDatabase mDb;
 
+    @Mock
+    private PackageManager mPackageManager;
+
     @Before
     public void setUp() {
-        mContext = ShadowApplication.getInstance().getApplicationContext();
-        mManager = spy(new DatabaseIndexingManager(mContext, mContext.getPackageName()));
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mManager = spy(new DatabaseIndexingManager(mContext,"com.android.settings"));
         mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
+
+        doReturn(mPackageManager).when(mContext).getPackageManager();
     }
 
     @After
@@ -126,7 +169,7 @@
     // Tests for the flow: IndexOneRaw -> UpdateOneRowWithFilteredData -> UpdateOneRow
 
     @Test
-    public void testInsertRawColumn_RowInserted() {
+    public void testInsertRawColumn_rowInserted() {
         SearchIndexableRaw raw = getFakeRaw();
         mManager.indexOneSearchIndexableData(mDb, localeStr, raw, null /* Non-indexable keys */);
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
@@ -134,7 +177,7 @@
     }
 
     @Test
-    public void testInsertRawColumn_RowMatches() {
+    public void testInsertRawColumn_rowMatches() {
         SearchIndexableRaw raw = getFakeRaw();
         mManager.indexOneSearchIndexableData(mDb, localeStr, raw, null /* Non-indexable keys */);
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
@@ -185,7 +228,7 @@
     }
 
     @Test
-    public void testInsertRawColumnMismatchedLocale_NoRowInserted() {
+    public void testInsertRawColumn_mismatchedLocale_noRowInserted() {
         SearchIndexableRaw raw = getFakeRaw("ca-fr");
         mManager.indexOneSearchIndexableData(mDb, localeStr, raw, null /* Non-indexable keys */);
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
@@ -206,18 +249,18 @@
     @Test
     public void testAddResource_RowsInserted() {
         SearchIndexableResource resource = getFakeResource(R.xml.ia_display_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<>());
+        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
         assertThat(cursor.getCount()).isEqualTo(16);
     }
 
     @Test
-    public void testAddResourceWithNIKs_RowsInsertedDisabled() {
+    public void testAddResource_withNIKs_rowsInsertedDisabled() {
         SearchIndexableResource resource = getFakeResource(R.xml.ia_display_settings);
         // Only add 2 of 16 items to be disabled.
         String[] keys = {"brightness", "wallpaper"};
-        Map<String, List<String>> niks = getNonIndexableKeys(keys);
+        Map<String, Set<String>> niks = getNonIndexableKeys(keys);
+
         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, niks);
 
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
@@ -227,10 +270,9 @@
     }
 
     @Test
-    public void testAddResourceHeader_RowsMatch() {
+    public void testAddResourceHeader_rowsMatch() {
         SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<>());
+        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
 
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
         cursor.moveToPosition(1);
@@ -280,7 +322,7 @@
     }
 
     @Test
-    public void testAddResourceWithChildFragment_shouldUpdateSiteMapDb() {
+    public void testAddResource_withChildFragment_shouldUpdateSiteMapDb() {
         // FIXME: This test was failing. (count = 6 at the end)
 
 //        SearchIndexableResource resource = getFakeResource(R.xml.network_and_internet);
@@ -305,10 +347,9 @@
     }
 
     @Test
-    public void testAddResourceCustomSetting_RowsMatch() {
+    public void testAddResource_customSetting_rowsMatch() {
         SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<>());
+        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
         final String prefTitle =
                 mContext.getString(R.string.fingerprint_swipe_for_notifications_title);
         final String prefSummary =
@@ -363,10 +404,9 @@
     }
 
     @Test
-    public void testAddResourceCheckboxPreference_RowsMatch() {
+    public void testAddResource_checkboxPreference_rowsMatch() {
         SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<>());
+        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
 
         /* Should return 6 results, with the following titles:
          * Advanced Settings, Apps, Manage Apps, Preferred install location, Running Services
@@ -418,10 +458,9 @@
     }
 
     @Test
-    public void testAddResourceListPreference_RowsMatch() {
+    public void testAddResource_listPreference_rowsMatch() {
         SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<>());
+        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
 
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
         cursor.moveToPosition(3);
@@ -476,25 +515,23 @@
     //                     UpdateOneRowWithFilteredData -> UpdateOneRow
 
     @Test
-    public void testResourceProvider_RowInserted() {
+    public void testResourceProvider_rowInserted() {
         SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
         resource.xmlResId = 0;
         resource.className = "com.android.settings.display.ScreenZoomSettings";
 
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<>());
+        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
         assertThat(cursor.getCount()).isEqualTo(1);
     }
 
     @Test
-    public void testResourceProvider_Matches() {
+    public void testResourceProvider_rowMatches() {
         SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
         resource.xmlResId = 0;
         resource.className = "com.android.settings.display.ScreenZoomSettings";
 
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<>());
+        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
         cursor.moveToPosition(0);
 
@@ -544,23 +581,21 @@
     }
 
     @Test
-    public void testResourceProvider_ResourceRowInserted() {
+    public void testResourceProvider_resourceRowInserted() {
         SearchIndexableResource resource = getFakeResource(0);
         resource.className = "com.android.settings.LegalSettings";
 
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<>());
+        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
         assertThat(cursor.getCount()).isEqualTo(6);
     }
 
     @Test
-    public void testResourceProvider_ResourceRowMatches() {
+    public void testResourceProvider_resourceRowMatches() {
         SearchIndexableResource resource = getFakeResource(0);
         resource.className = "com.android.settings.display.ScreenZoomSettings";
 
-        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<>());
+        mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
         cursor.moveToPosition(0);
 
@@ -611,12 +646,12 @@
     }
 
     @Test
-    public void testResourceProvider_DisabledResourceRowsInserted() {
+    public void testResourceProvider_disabledResource_rowsInserted() {
         SearchIndexableResource resource = getFakeResource(0);
         resource.className = "com.android.settings.LegalSettings";
 
         mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
-                new HashMap<String, List<String>>());
+                new HashMap<String, Set<String>>());
 
         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
         assertThat(cursor.getCount()).isEqualTo(2);
@@ -625,7 +660,7 @@
     }
 
     @Test
-    public void testResourceWithTitleAndSettingName_TitleNotInserted() {
+    public void testResource_withTitleAndSettingName_titleNotInserted() {
         SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
         mManager.indexFromResource(mDb, localeStr, resource, new ArrayList<String>());
 
@@ -634,6 +669,176 @@
         assertThat(cursor.getCount()).isEqualTo(1);
     }
 
+    // Test new public indexing flow
+
+    @Test
+    @Config(shadows= {
+            ShadowDatabaseIndexingUtils.class,
+    })
+    public void testPerformIndexing_fullIndex_getsDataFromProviders() {
+        DummyProvider provider = new DummyProvider();
+        provider.onCreate();
+        ShadowContentResolver.registerProvider(
+                AUTHORITY_ONE, provider
+        );
+
+        // Test that Indexables are added for Full indexing
+        when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
+                .thenReturn(getDummyResolveInfo());
+
+        DatabaseIndexingManager manager =
+                spy(new DatabaseIndexingManager(mContext, "com.android.settings"));
+        doReturn(false).when(manager).isLocaleIndexed();
+
+        manager.performIndexing();
+
+        verify(manager).updateDatabase(false, Locale.getDefault().toString());
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        cursor.moveToPosition(0);
+
+        // Data Title
+        assertThat(cursor.getString(2)).isEqualTo(TITLE_ONE);
+    }
+
+    @Test
+    @Config(shadows= {
+            ShadowDatabaseIndexingUtils.class,
+    })
+    public void testPerformIndexing_incrementalIndex_noDataAdded() {
+        DummyProvider provider = new DummyProvider();
+        provider.onCreate();
+        ShadowContentResolver.registerProvider(
+                AUTHORITY_ONE, provider
+        );
+
+        // Test that Indexables are added for Full indexing
+        when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
+                .thenReturn(getDummyResolveInfo());
+
+        DatabaseIndexingManager manager =
+                spy(new DatabaseIndexingManager(mContext, "com.android.settings"));
+        doReturn(true).when(manager).isLocaleIndexed();
+
+        manager.performIndexing();
+
+        final Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+
+        assertThat(cursor.getCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void testFullUpdatedDatabase_noData_addDataToDatabaseNotCalled() {
+        mManager.updateDatabase(false, localeStr);
+        mManager.mDataToProcess.dataToUpdate.clear();
+        verify(mManager, times(0)).addDataToDatabase(any(SQLiteDatabase.class), anyString(),
+                anyList(), anyMap());
+    }
+
+    @Test
+    public void testFullUpdatedDatabase_updatedDataInDatabaseNotCalled() {
+        mManager.updateDatabase(false, localeStr);
+        verify(mManager, times(0)).updateDataInDatabase(any(SQLiteDatabase.class), anyMap());
+    }
+
+    @Test
+    public void testLocaleUpdated_afterIndexing_localeAdded() {
+        mManager.updateDatabase(false, localeStr);
+        assertThat(IndexDatabaseHelper.getInstance(mContext)
+                .isLocaleAlreadyIndexed(mContext, localeStr)).isTrue();
+    }
+
+    @Test
+    public void testUpdateDatabase_newEligibleData_addedToDatabase() {
+        // Test that addDataToDatabase is called when dataToUpdate is non-empty
+        mManager.mDataToProcess.dataToUpdate.add(getFakeRaw());
+        mManager.updateDatabase(false, localeStr);
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
+        cursor.moveToPosition(0);
+
+        // Locale
+        assertThat(cursor.getString(0)).isEqualTo(localeStr);
+        // Data Rank
+        assertThat(cursor.getInt(1)).isEqualTo(rank);
+        // Data Title
+        assertThat(cursor.getString(2)).isEqualTo(updatedTitle);
+        // Normalized Title
+        assertThat(cursor.getString(3)).isEqualTo(normalizedTitle);
+        // Summary On
+        assertThat(cursor.getString(4)).isEqualTo(updatedSummaryOn);
+        // Summary On Normalized
+        assertThat(cursor.getString(5)).isEqualTo(normalizedSummaryOn);
+        // Summary Off
+        assertThat(cursor.getString(6)).isEqualTo(updatedSummaryOff);
+        // Summary off normalized
+        assertThat(cursor.getString(7)).isEqualTo(normalizedSummaryOff);
+        // Entries
+        assertThat(cursor.getString(8)).isEqualTo(entries);
+        // Keywords
+        assertThat(cursor.getString(9)).isEqualTo(spaceDelimittedKeywords);
+        // Screen Title
+        assertThat(cursor.getString(10)).isEqualTo(screenTitle);
+        // Class Name
+        assertThat(cursor.getString(11)).isEqualTo(className);
+        // Icon
+        assertThat(cursor.getInt(12)).isEqualTo(iconResId);
+        // Intent Action
+        assertThat(cursor.getString(13)).isEqualTo(action);
+        // Target Package
+        assertThat(cursor.getString(14)).isEqualTo(targetPackage);
+        // Target Class
+        assertThat(cursor.getString(15)).isEqualTo(targetClass);
+        // Enabled
+        assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
+        // Data ref key
+        assertThat(cursor.getString(17)).isNotNull();
+        // User Id
+        assertThat(cursor.getInt(18)).isEqualTo(userId);
+        // Payload Type - default is 0
+        assertThat(cursor.getInt(19)).isEqualTo(0);
+        // Payload
+        assertThat(cursor.getBlob(20)).isNull();
+    }
+
+    @Test
+    public void testUpdateDataInDatabase_enabledResultsAreNonIndexable_becomeDisabled() {
+        // Both results are enabled, and then TITLE_ONE gets disabled.
+        final boolean enabled = true;
+        insertSpecialCase(TITLE_ONE, enabled, KEY_ONE);
+        insertSpecialCase(TITLE_TWO, enabled, KEY_TWO);
+        Map<String, Set<String>> niks = new ArrayMap<>();
+        Set<String> keys = new HashSet<>();
+        keys.add(KEY_ONE);
+        niks.put(targetPackage, keys);
+
+        mManager.updateDataInDatabase(mDb, niks);
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
+        cursor.moveToPosition(0);
+
+        assertThat(cursor.getString(2)).isEqualTo(TITLE_ONE);
+    }
+
+    @Test
+    public void testUpdateDataInDatabase_DisabledResultsAreIndexable_BecomeEnabled() {
+        // Both results are initially disabled, and then TITLE_TWO gets enabled.
+        final boolean enabled = false;
+        insertSpecialCase(TITLE_ONE, enabled, KEY_ONE);
+        insertSpecialCase(TITLE_TWO, enabled, KEY_TWO);
+        Map<String, Set<String>> niks = new ArrayMap<>();
+        Set<String> keys = new HashSet<>();
+        keys.add(KEY_ONE);
+        niks.put(targetPackage, keys);
+
+        mManager.updateDataInDatabase(mDb, niks);
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
+        cursor.moveToPosition(0);
+
+        assertThat(cursor.getString(2)).isEqualTo(TITLE_TWO);
+    }
+
     // Util functions
 
     private SearchIndexableRaw getFakeRaw() {
@@ -676,10 +881,119 @@
         return sir;
     }
 
-    private Map<String, List<String>> getNonIndexableKeys(String[] keys) {
-        Map<String, List<String>> niks = new HashMap<>();
-        List<String> keysList = new ArrayList<>(Arrays.asList(keys));
+    private Map<String, Set<String>> getNonIndexableKeys(String[] keys) {
+        Map<String, Set<String>> niks = new HashMap<>();
+        Set<String> keysList = new HashSet<>();
+        keysList.addAll(Arrays.asList(keys));
         niks.put(packageName, keysList);
         return niks;
     }
+
+    private List<ResolveInfo> getDummyResolveInfo() {
+        List<ResolveInfo> infoList = new ArrayList<>();
+        ResolveInfo info = new ResolveInfo();
+        info.providerInfo = new ProviderInfo();
+        info.providerInfo.exported = true;
+        info.providerInfo.authority = AUTHORITY_ONE;
+        info.providerInfo.packageName = PACKAGE_ONE;
+        infoList.add(info);
+
+        return infoList;
+    }
+
+    // TODO move this method and its counterpart in CursorToSearchResultConverterTest into
+    // a util class with public fields to assert values.
+    private Cursor getDummyCursor() {
+        MatrixCursor cursor = new MatrixCursor(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS);
+        final String BLANK = "";
+
+        ArrayList<String> item =
+                new ArrayList<>(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS.length);
+        item.add("42"); // Rank
+        item.add(TITLE_ONE); // Title
+        item.add(BLANK); // Summary on
+        item.add(BLANK); // summary off
+        item.add(BLANK); // entries
+        item.add(BLANK); // keywords
+        item.add(BLANK); // screen title
+        item.add(BLANK); // classname
+        item.add("123"); // Icon
+        item.add(BLANK); // Intent action
+        item.add(BLANK); // target package
+        item.add(BLANK); // target class
+        item.add(KEY_ONE); // Key
+        item.add("-1"); // userId
+        cursor.addRow(item);
+
+        return cursor;
+    }
+
+    private void insertSpecialCase(String specialCase, boolean enabled, String key) {
+
+        ContentValues values = new ContentValues();
+        values.put(IndexDatabaseHelper.IndexColumns.DOCID, specialCase.hashCode());
+        values.put(IndexDatabaseHelper.IndexColumns.LOCALE, localeStr);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, specialCase);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "");
+        values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, "");
+        values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, "");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, targetPackage);
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ICON, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ENABLED, enabled);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, key);
+        values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null);
+
+        mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
+    }
+
+    private class DummyProvider extends ContentProvider {
+
+        @Override
+        public boolean onCreate() {
+            return false;
+        }
+
+        @Override
+        public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+                @Nullable String selection, @Nullable String[] selectionArgs,
+                @Nullable String sortOrder) {
+            if (uri.toString().contains("xml")) {
+                return null;
+            }
+            return getDummyCursor();
+        }
+
+        @Override
+        public String getType(@NonNull Uri uri) {
+            return null;
+        }
+
+        @Override
+        public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+            return null;
+        }
+
+        @Override
+        public int delete(@NonNull Uri uri, @Nullable String selection,
+                @Nullable String[] selectionArgs) {
+            return 0;
+        }
+
+        @Override
+        public int update(@NonNull Uri uri, @Nullable ContentValues values,
+                @Nullable String selection, @Nullable String[] selectionArgs) {
+            return 0;
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java b/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java
index 3e22d56..2b6ebaf 100644
--- a/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java
@@ -43,7 +43,6 @@
 import java.util.List;
 
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyList;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
@@ -66,7 +65,8 @@
 
     @Mock
     private SavedQueryLoader mSavedQueryLoader;
-
+    @Mock
+    private SavedQueryController mSavedQueryController;
     private FakeFeatureFactory mFeatureFactory;
 
     @Before
@@ -96,6 +96,7 @@
         SearchFragment fragment = (SearchFragment) activityController.get().getFragmentManager()
                 .findFragmentById(R.id.main_content);
 
+        ReflectionHelpers.setField(fragment, "mShowingSavedQuery", false);
         fragment.mQuery = testQuery;
 
         activityController.saveInstanceState(bundle).pause().stop().destroy();
@@ -111,12 +112,6 @@
 
     @Test
     public void screenRotateEmptyString_ShouldNotCrash() {
-        when(mFeatureFactory.searchFeatureProvider
-                .getDatabaseSearchLoader(any(Context.class), anyString()))
-                .thenReturn(mDatabaseResultLoader);
-        when(mFeatureFactory.searchFeatureProvider
-                .getInstalledAppSearchLoader(any(Context.class), anyString()))
-                .thenReturn(mInstalledAppResultLoader);
         when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
                 .thenReturn(mSavedQueryLoader);
 
@@ -134,10 +129,12 @@
         activityController = Robolectric.buildActivity(SearchActivity.class);
         activityController.setup(bundle);
 
-        verify(mFeatureFactory.searchFeatureProvider)
+        verify(mFeatureFactory.searchFeatureProvider, never())
                 .getDatabaseSearchLoader(any(Context.class), anyString());
-        verify(mFeatureFactory.searchFeatureProvider)
+        verify(mFeatureFactory.searchFeatureProvider, never())
                 .getInstalledAppSearchLoader(any(Context.class), anyString());
+        verify(mFeatureFactory.searchFeatureProvider, times(2))
+                .getSavedQueryLoader(any(Context.class));
     }
 
     @Test
@@ -160,6 +157,7 @@
 
         fragment.onQueryTextChange(testQuery);
         activityController.get().onBackPressed();
+
         activityController.pause().stop().destroy();
 
         verify(mFeatureFactory.metricsFeatureProvider, never()).action(
@@ -174,7 +172,7 @@
     }
 
     @Test
-    public void queryTextChangeToEmpty_shouldTriggerSavedQueryLoader() {
+    public void queryTextChangeToEmpty_shouldLoadSavedQuery() {
         when(mFeatureFactory.searchFeatureProvider
                 .getDatabaseSearchLoader(any(Context.class), anyString()))
                 .thenReturn(mDatabaseResultLoader);
@@ -190,20 +188,15 @@
 
         SearchFragment fragment = spy((SearchFragment) activityController.get().getFragmentManager()
                 .findFragmentById(R.id.main_content));
-
-        final SearchResultsAdapter adapter = mock(SearchResultsAdapter.class);
-        ReflectionHelpers.setField(fragment, "mSearchAdapter", adapter);
+        ReflectionHelpers.setField(fragment, "mSavedQueryController", mSavedQueryController);
+        fragment.mQuery = "123";
+        fragment.onQueryTextChange("");
 
         verify(mFeatureFactory.searchFeatureProvider, never())
                 .getDatabaseSearchLoader(any(Context.class), anyString());
         verify(mFeatureFactory.searchFeatureProvider, never())
                 .getInstalledAppSearchLoader(any(Context.class), anyString());
-        verify(mFeatureFactory.searchFeatureProvider)
-                .getSavedQueryLoader(any(Context.class));
-
-        fragment.onLoadFinished(mSavedQueryLoader, null /* data */);
-
-        verify(adapter).displaySavedQuery(anyList());
+        verify(mSavedQueryController).loadSavedQueries();
     }
 
     @Test
@@ -235,6 +228,8 @@
         when(mFeatureFactory.searchFeatureProvider
                 .getInstalledAppSearchLoader(any(Context.class), anyString()))
                 .thenReturn(new MockAppLoader(RuntimeEnvironment.application));
+        when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
+                .thenReturn(mSavedQueryLoader);
 
         ActivityController<SearchActivity> activityController =
                 Robolectric.buildActivity(SearchActivity.class);
@@ -258,6 +253,8 @@
         when(mFeatureFactory.searchFeatureProvider
                 .getInstalledAppSearchLoader(any(Context.class), anyString()))
                 .thenReturn(new MockAppLoader(RuntimeEnvironment.application));
+        when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
+                .thenReturn(mSavedQueryLoader);
 
         ActivityController<SearchActivity> activityController =
                 Robolectric.buildActivity(SearchActivity.class);
@@ -282,12 +279,14 @@
         when(mFeatureFactory.searchFeatureProvider
                 .getInstalledAppSearchLoader(any(Context.class), anyString()))
                 .thenReturn(new MockAppLoader(RuntimeEnvironment.application));
+        when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class)))
+                .thenReturn(mSavedQueryLoader);
 
         ActivityController<SearchActivity> activityController =
                 Robolectric.buildActivity(SearchActivity.class);
         activityController.setup();
-        SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager()
-                .findFragmentById(R.id.main_content));
+        SearchFragment fragment = (SearchFragment) activityController.get().getFragmentManager()
+                .findFragmentById(R.id.main_content);
 
         fragment.onQueryTextChange("non-empty");
 
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowContentResolver.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowContentResolver.java
index bc43fc3..6ae695b 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowContentResolver.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowContentResolver.java
@@ -29,5 +29,4 @@
     public static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
         return new SyncAdapterType[0];
     }
-
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDatabaseIndexingUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDatabaseIndexingUtils.java
new file mode 100644
index 0000000..724b9c0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDatabaseIndexingUtils.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 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.testutils.shadow;
+
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import com.android.settings.search2.DatabaseIndexingUtils;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/**
+ * Shadow of {@link DatabaseIndexingUtils}
+ */
+@Implements(DatabaseIndexingUtils.class)
+public class ShadowDatabaseIndexingUtils {
+    @Implementation
+    public static boolean isWellKnownProvider(ResolveInfo info, Context context) {
+        return true;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRunnableAsyncTask.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRunnableAsyncTask.java
new file mode 100644
index 0000000..5a71b58
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRunnableAsyncTask.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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.testutils.shadow;
+
+import android.os.AsyncTask;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowAsyncTask;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Shadow async task to handle runnables in roboletric
+ */
+@Implements(AsyncTask.class)
+public class ShadowRunnableAsyncTask<Params, Progress, Result> extends
+        ShadowAsyncTask<Params, Progress, Result> {
+
+    @Implementation
+    public AsyncTask<Params, Progress, Result> executeOnExecutor(Executor executor,
+            Params... params) {
+        return super.execute(params);
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
new file mode 100644
index 0000000..b2648ac
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017 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.wifi.details;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.net.NetworkBadging;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.core.lifecycle.Lifecycle;
+import com.android.settings.wifi.WifiDetailPreference;
+import com.android.settingslib.wifi.AccessPoint;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class WifiDetailPreferenceControllerTest {
+
+    private static final int LEVEL = 1;
+    private static final int RSSI = -55;
+    private static final String SECURITY = "None";
+
+    private Context mContext = RuntimeEnvironment.application;
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Drawable mockWifiIcon;
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private PreferenceScreen mockScreen;
+
+    @Mock private AccessPoint mockAccessPoint;
+    @Mock private WifiManager mockWifiManager;
+    @Mock private NetworkInfo mockNetworkInfo;
+    @Mock private WifiConfiguration mockWifiConfig;
+    @Mock private WifiInfo mockWifiInfo;
+
+    @Mock private Preference mockConnectionDetailPref;
+    @Mock private WifiDetailPreference mockSignalStrengthPref;
+    @Mock private WifiDetailPreference mockFrequencyPref;
+    @Mock private WifiDetailPreference mockSecurityPref;
+    @Mock private WifiDetailPreference mockIpAddressPref;
+    @Mock private WifiDetailPreference mockRouterPref;
+    @Mock private WifiDetailPreference mockSubnetPref;
+    @Mock private WifiDetailPreference mockDnsPref;
+    @Mock private PreferenceCategory mockIpv6AddressCategory;
+
+    private Lifecycle mLifecycle;
+    private WifiDetailPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mLifecycle = new Lifecycle();
+        mController = new WifiDetailPreferenceController(
+                mockAccessPoint, mContext, mLifecycle, mockWifiManager);
+
+        when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig);
+        when(mockAccessPoint.getLevel()).thenReturn(LEVEL);
+        when(mockAccessPoint.getNetworkInfo()).thenReturn(mockNetworkInfo);
+        when(mockAccessPoint.getRssi()).thenReturn(RSSI);
+        when(mockAccessPoint.getSecurityString(false)).thenReturn(SECURITY);
+
+        setupMockedPreferenceScreen();
+
+        when (mockWifiInfo.getRssi()).thenReturn(RSSI);
+        when(mockWifiManager.getConnectionInfo()).thenReturn(mockWifiInfo);
+        when(mockWifiManager.getWifiApConfiguration()).thenReturn(mockWifiConfig);
+    }
+
+    private void setupMockedPreferenceScreen() {
+
+        when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_CONNECTION_DETAIL_PREF))
+                .thenReturn(mockConnectionDetailPref);
+        when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SIGNAL_STRENGTH_PREF))
+                .thenReturn(mockSignalStrengthPref);
+        when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_FREQUENCY_PREF))
+                .thenReturn(mockFrequencyPref);
+        when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SECURITY_PREF))
+                .thenReturn(mockSecurityPref);
+        when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IP_ADDRESS_PREF))
+                .thenReturn(mockIpAddressPref);
+        when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_ROUTER_PREF))
+                .thenReturn(mockRouterPref);
+        when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SUBNET_MASK_PREF))
+                .thenReturn(mockSubnetPref);
+        when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_DNS_PREF))
+                .thenReturn(mockDnsPref);
+        when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_ADDRESS_CATEGORY))
+                .thenReturn(mockIpv6AddressCategory);
+
+        mController.displayPreference(mockScreen);
+    }
+
+    @Test
+    public void isAvailable_shouldAlwaysReturnTrue() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void securityPreference_stringShouldBeSet() {
+        verify(mockSecurityPref).setDetailText(SECURITY);
+    }
+
+    @Test
+    public void latestWifiInfoAndConfig_shouldBeFetchedOnResume() {
+        mController.onResume();
+
+        verify(mockWifiManager).getConnectionInfo();
+        verify(mockWifiManager).getWifiApConfiguration();
+    }
+
+    @Test
+    public void connectionDetailPref_shouldHaveIconSet() {
+        Drawable expectedIcon =
+                NetworkBadging.getWifiIcon(LEVEL, NetworkBadging.BADGING_NONE, mContext.getTheme());
+
+        mController.onResume();
+
+        verify(mockConnectionDetailPref).setIcon(expectedIcon);
+    }
+
+    @Test
+    public void connectionDetailPref_shouldHaveTitleSet() {
+        String summary = "summary";
+        when(mockAccessPoint.getSettingsSummary()).thenReturn(summary);
+
+        mController.onResume();
+
+        verify(mockConnectionDetailPref).setTitle(summary);
+    }
+
+    @Test
+    public void signalStrengthPref_shouldHaveIconSet() {
+        mController.onResume();
+
+        verify(mockSignalStrengthPref).setIcon(any(Drawable.class));
+    }
+
+    @Test
+    public void signalStrengthPref_shouldHaveDetailTextSet() {
+        String expectedStrength =
+                mContext.getResources().getStringArray(R.array.wifi_signal)[LEVEL];
+
+        mController.onResume();
+
+        verify(mockSignalStrengthPref).setDetailText(expectedStrength);
+    }
+}
diff --git a/tests/unit/Android.mk b/tests/unit/Android.mk
index f98fccd..f9c0489 100644
--- a/tests/unit/Android.mk
+++ b/tests/unit/Android.mk
@@ -18,6 +18,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := SettingsUnitTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 LOCAL_INSTRUMENTATION_FOR := Settings
 
diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java
index c83a594..617e9bb 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java
@@ -145,7 +145,7 @@
     }
 
     @Test
-    public void testSystemAppsBaseSizeIsIgnored() throws Exception {
+    public void testSystemAppsBaseSizeIsAddedToSystem() throws Exception {
         ApplicationInfo systemApp =
                 addPackage(PACKAGE_NAME_1, 100, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
         systemApp.flags = ApplicationInfo.FLAG_SYSTEM;
@@ -154,6 +154,7 @@
 
         assertThat(result.size()).isEqualTo(1);
         assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(10L);
+        assertThat(result.get(PRIMARY_USER_ID).systemSize).isEqualTo(1L);
     }
 
     @Test