Merge "Allow page to suppress all of its content from search."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2229d01..26a5e10 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -159,7 +159,7 @@
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.VOICE_LAUNCH" />
             </intent-filter>
-            <intent-filter android:priority="10">
+            <intent-filter android:priority="11">
                 <action android:name="com.android.settings.action.SETTINGS"/>
             </intent-filter>
             <meta-data android:name="com.android.settings.category"
@@ -2976,7 +2976,7 @@
         <activity android:name=".Settings$SystemDashboardActivity"
                   android:label="@string/header_category_system"
                   android:icon="@drawable/ic_settings_about">
-            <intent-filter android:priority="1">
+            <intent-filter android:priority="-1">
                 <action android:name="com.android.settings.action.SETTINGS"/>
             </intent-filter>
             <meta-data android:name="com.android.settings.category"
@@ -2991,7 +2991,7 @@
                   android:label="@string/page_tab_title_support"
                   android:icon="@drawable/ic_help"
                   android:enabled="@bool/config_support_enabled">
-            <intent-filter android:priority="0">
+            <intent-filter android:priority="-2">
                 <action android:name="com.android.settings.action.SETTINGS"/>
             </intent-filter>
             <meta-data android:name="com.android.settings.category"
diff --git a/res/drawable/ic_frequency_antenna.xml b/res/drawable/ic_frequency_antenna.xml
new file mode 100644
index 0000000..581b83e
--- /dev/null
+++ b/res/drawable/ic_frequency_antenna.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:width="24dp"
+        android:height="24dp"
+        android:tint="@color/wifi_details_icon_color">
+    <path
+        android:pathData="M12,5c-3.9,0-7,3.1-7,7h2c0-2.8,2.2-5,5-5s5,2.2,5,5h2C19,8.1,15.9,5,12,5z M13,14.3c0.9-0.4,1.5-1.3,1.5-2.3
+                c0-1.4-1.1-2.5-2.5-2.5S9.5,10.6,9.5,12c0,1,0.6,1.9,1.5,2.3v3.3L7.6,21L9,22.4l3-3l3,3l1.4-1.4L13,17.6V14.3z M12,1
+                C5.9,1,1,5.9,1,12h2c0-5,4-9,9-9s9,4,9,9h2C23,5.9,18.1,1,12,1z"
+        android:fillColor="#FFFFFFFF" />
+</vector>
diff --git a/res/drawable/ic_security_lock_24dp.xml b/res/drawable/ic_security_lock_24dp.xml
new file mode 100644
index 0000000..fd49b23
--- /dev/null
+++ b/res/drawable/ic_security_lock_24dp.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:width="24dp"
+        android:height="24dp"
+        android:tint="@color/wifi_details_icon_color">
+    <path
+        android:pathData="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"
+        android:fillColor="#FFFFFFFF" />
+</vector>
diff --git a/res/drawable/ic_settings_widget_background.xml b/res/drawable/ic_settings_widget_background.xml
new file mode 100644
index 0000000..6d81d47
--- /dev/null
+++ b/res/drawable/ic_settings_widget_background.xml
@@ -0,0 +1,24 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="192"
+        android:viewportHeight="192"
+        android:width="72dp"
+        android:height="72dp">
+    <path
+        android:pathData="M184 96A88 88 0 0 1 96 184 88 88 0 0 1 8 96 88 88 0 0 1 96 8 88 88 0 0 1 184 96Z"
+        android:fillColor="@android:color/white" />
+</vector>
diff --git a/res/drawable/selectable_card.xml b/res/drawable/selectable_card.xml
index df9ddb1..3a1e8b2 100644
--- a/res/drawable/selectable_card.xml
+++ b/res/drawable/selectable_card.xml
@@ -18,5 +18,5 @@
 <ripple
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:color="?android:attr/colorControlHighlight">
-    <item android:drawable="@color/card_background"/>
+    <item android:drawable="?android:attr/colorBackground"/>
 </ripple>
\ No newline at end of file
diff --git a/res/drawable/selectable_card_grey.xml b/res/drawable/selectable_card_grey.xml
index e4c73ba..225e72f 100644
--- a/res/drawable/selectable_card_grey.xml
+++ b/res/drawable/selectable_card_grey.xml
@@ -18,5 +18,5 @@
 <ripple
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:color="?android:attr/colorControlHighlight">
-    <item android:drawable="@color/card_background_grey"/>
+    <item android:drawable="?android:attr/colorSecondary"/>
 </ripple>
diff --git a/res/layout-land/fingerprint_enroll_enrolling.xml b/res/layout-land/fingerprint_enroll_enrolling.xml
index c89bc42..5c4e99b 100644
--- a/res/layout-land/fingerprint_enroll_enrolling.xml
+++ b/res/layout-land/fingerprint_enroll_enrolling.xml
@@ -82,15 +82,6 @@
 
             </FrameLayout>
 
-            <Button
-                android:id="@+id/skip_button"
-                style="@style/SetupWizardButton.Negative"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="8dp"
-                android:text="@string/skip_label"
-                android:visibility="gone" />
-
         </LinearLayout>
 
         <FrameLayout
diff --git a/res/layout/connection_detail_pref.xml b/res/layout/connection_detail_pref.xml
new file mode 100644
index 0000000..15f1c77
--- /dev/null
+++ b/res/layout/connection_detail_pref.xml
@@ -0,0 +1,50 @@
+<?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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/connection_detail_layout"
+    android:background="?android:attr/colorAccent"
+    android:layout_width="match_parent"
+    android:layout_height="144dp"
+    android:gravity="center_vertical"
+    android:orientation="horizontal">
+
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@drawable/ic_settings_widget_background"
+        android:layout_marginLeft="72dp"
+        android:elevation="2dp">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"/>
+
+    </FrameLayout>
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="20dp"
+        android:textAppearance="@android:style/TextAppearance.Material.Medium"
+        android:textColor="@android:color/white"/>
+
+</LinearLayout>
diff --git a/res/layout/crypt_keeper_password_field.xml b/res/layout/crypt_keeper_password_field.xml
index eb89b70..8102658 100644
--- a/res/layout/crypt_keeper_password_field.xml
+++ b/res/layout/crypt_keeper_password_field.xml
@@ -21,7 +21,7 @@
      switcher, if necessary. Assumed to be in a horizontal LinearLayout. -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <com.android.settings.widget.ImeAwareEditText android:id="@+id/passwordEntry"
+    <EditText android:id="@+id/passwordEntry"
         android:layout_height="wrap_content"
         android:layout_width="0dip"
         android:layout_weight="1"
diff --git a/res/layout/dashboard_category.xml b/res/layout/dashboard_category.xml
index 2e5dd5c..1314c16 100644
--- a/res/layout/dashboard_category.xml
+++ b/res/layout/dashboard_category.xml
@@ -19,8 +19,7 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/dashboard_category_height"
     android:orientation="vertical"
-    android:paddingBottom="8dip"
-    android:background="@color/card_background">
+    android:paddingBottom="8dip">
 
     <TextView android:id="@android:id/title"
         android:layout_width="match_parent"
diff --git a/res/layout/dashboard_spacer.xml b/res/layout/dashboard_spacer.xml
index 8d58c80..3ebcb09 100644
--- a/res/layout/dashboard_spacer.xml
+++ b/res/layout/dashboard_spacer.xml
@@ -18,4 +18,4 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="8dp"
-    android:background="@color/card_background_grey"/>
+    android:background="?android:attr/colorSecondary"/>
diff --git a/res/layout/fingerprint_enroll_enrolling_base.xml b/res/layout/fingerprint_enroll_enrolling_base.xml
index 33a5acf..bd1e2c2 100644
--- a/res/layout/fingerprint_enroll_enrolling_base.xml
+++ b/res/layout/fingerprint_enroll_enrolling_base.xml
@@ -71,14 +71,6 @@
             android:accessibilityLiveRegion="polite"
             android:visibility="invisible"/>
 
-        <Button
-            android:id="@+id/skip_button"
-            style="@style/SetupWizardButton.Negative"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/skip_label"
-            android:visibility="gone" />
-
     </LinearLayout>
 
 </com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout/search_saved_query_item.xml b/res/layout/search_saved_query_item.xml
index 71c8482..50001a5 100644
--- a/res/layout/search_saved_query_item.xml
+++ b/res/layout/search_saved_query_item.xml
@@ -20,26 +20,28 @@
     android:orientation="horizontal"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="?android:attr/selectableItemBackground"
     android:minHeight="?android:attr/listPreferredItemHeight"
-    android:gravity="center_vertical"
-    android:paddingStart="@dimen/preference_no_icon_padding_start"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+    android:gravity="center_vertical">
 
     <TextView
         android:id="@android:id/title"
-        android:textAppearance="?android:attr/textAppearanceListItem"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
         android:layout_width="wrap_content"
-        android:layout_weight="1"/>
+        android:layout_weight="1"
+        android:text="test"
+        android:gravity="center_vertical"
+        android:background="?android:attr/selectableItemBackground"
+        android:paddingStart="@dimen/preference_no_icon_padding_start"
+        android:textAppearance="?android:attr/textAppearanceListItem" />
 
     <ImageView
         android:id="@android:id/icon"
-        android:layout_width="@dimen/search_suggestion_item_image_size"
-        android:layout_height="@dimen/search_suggestion_item_image_size"
-        android:layout_marginStart="@dimen/search_suggestion_item_image_margin_start"
-        android:layout_marginEnd="@dimen/search_suggestion_item_image_margin_end"
-        android:scaleType="centerInside"
-        android:src="@drawable/ic_search_history"/>
+        android:background="?android:attr/selectableItemBackground"
+        android:layout_width="@dimen/dashboard_category_height"
+        android:layout_height="@dimen/dashboard_category_height"
+        android:paddingStart="@dimen/search_suggestion_item_image_margin_start"
+        android:paddingEnd="@dimen/search_suggestion_item_image_margin_end"
+        android:scaleType="center"
+        android:src="@drawable/ic_cross_grey_24dp" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/support_fragment.xml b/res/layout/support_fragment.xml
index 7c79a63..6864d32 100644
--- a/res/layout/support_fragment.xml
+++ b/res/layout/support_fragment.xml
@@ -27,6 +27,5 @@
     <android.support.v7.widget.RecyclerView
         android:id="@+id/support_items"
         android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:background="@color/card_background"/>
+        android:layout_width="match_parent"/>
 </FrameLayout>
diff --git a/res/layout/support_tile_spacer.xml b/res/layout/support_tile_spacer.xml
index 41cc221..aa86e1e 100644
--- a/res/layout/support_tile_spacer.xml
+++ b/res/layout/support_tile_spacer.xml
@@ -18,5 +18,4 @@
 <View
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/support_spacer_height"
-    android:background="@color/card_background"/>
+    android:layout_height="@dimen/support_spacer_height"/>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 8b172fa..8980568 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -320,6 +320,7 @@
     <!-- Wi-Fi settings. The signal strength a Wi-Fi network has. -->
     <string-array name="wifi_signal">
         <item>Poor</item>
+        <item>Poor</item>
         <item>Fair</item>
         <item>Good</item>
         <item>Excellent</item>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 6705494..ec8fca9 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -55,8 +55,6 @@
     <color name="running_processes_system_ram">#ff384248</color>
     <color name="running_processes_free_ram">#ffced7db</color>
 
-    <color name="card_background">#fffafafa</color>
-
     <color name="wifi_divider">#ffe0e0e0</color>
     <color name="sim_noitification">@*android:color/material_deep_teal_500</color>
 
@@ -99,8 +97,6 @@
 
     <color name="usage_graph_dots">#B0BEC5</color>
 
-    <color name="card_background_grey">#eeeeee</color>
-
     <!-- Gestures settings -->
     <color name="gestures_setting_background_color">#f5f5f5</color>
 
@@ -112,4 +108,7 @@
     <!-- Color for the background of the shortcut icons.-->
     <color name="shortcut_background">#fff5f5f5</color>
 
+    <!-- Color for preference icons on the Wifi Network Details page -->
+    <color name="wifi_details_icon_color">#8A000000</color>
+
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index fe5845a..f03a073 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -137,7 +137,7 @@
 
     <!-- Suggestion item image margin start / end -->
     <dimen name="search_suggestion_item_image_margin_start">32dp</dimen>
-    <dimen name="search_suggestion_item_image_margin_end">16dp</dimen>
+    <dimen name="search_suggestion_item_image_margin_end">32dp</dimen>
 
     <!-- Dimensions for Wifi Assistant Card -->
     <dimen name="wifi_assistant_padding_top_bottom">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f7b171f..79042c4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1836,6 +1836,14 @@
     <!-- Wi-Fi settings screen, advanced, title of the item to show the Wi-Fi device's current IP address. -->
     <string name="wifi_advanced_ip_address_title">IP address</string>
 
+    <!-- Wifi Network Details -->
+    <!-- Wifi details preference title to display router IP subnet mask -->
+    <string name="wifi_details_subnet_mask">Subnet Mask</string>
+    <!-- Wifi details preference title to display router DNS info -->
+    <string name="wifi_details_dns">DNS</string>
+    <!-- Wifi details preference category title for IPv6 information -->
+    <string name="wifi_details_ipv6_address_header">IPv6 Addresses</string>
+
     <!-- Wifi saved access points.  Used as a label under the shortcut icon that goes to Wifi saved access points. [CHAR LIMIT=20] -->
     <string name="wifi_saved_access_points_label">Saved networks</string>
     <!-- Wifi Advanced settings.  Used as a label under the shortcut icon that goes to Wifi advanced settings. [CHAR LIMIT=20] -->
@@ -8137,7 +8145,7 @@
 
     <!-- Enterprise Privacy --> <skip />
 
-    <!-- Title of setting on security settings screen. This will take the user to a screen with information about admin powers and their impact on the user's privacy on a managed device. Shown on enterprise-managed devices only. -->
+    <!-- Title of setting on security settings screen. This will take the user to a screen with information about admin powers and their impact on the user's privacy on a managed device. Shown on enterprise-managed devices only. Note: "Device" is singular and refers to the device (e.g. phone or tablet) that the user is holding in their hand. -->
     <string name="enterprise_privacy_settings">Managed device details</string>
     <!-- Summary for Enterprise Privacy settings, explaining what the user can expect to find under it [CHAR LIMIT=NONE]-->
     <string name="enterprise_privacy_settings_summary_generic">Changes &amp; settings managed by your organization</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d193c30..95efaec 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -393,7 +393,7 @@
     </style>
 
     <style name="SupportEscalationCard">
-        <item name="android:background">@color/card_background_grey</item>
+        <item name="android:background">?android:attr/colorSecondary</item>
         <item name="android:gravity">center</item>
         <item name="android:minHeight">368dp</item>
         <item name="android:paddingStart">@dimen/support_escalation_card_padding_start</item>
@@ -414,7 +414,7 @@
     </style>
 
     <style name="EntityHeader">
-        <item name="android:background">@color/card_background_grey</item>
+        <item name="android:background">?android:attr/colorSecondary</item>
         <item name="android:gravity">center_horizontal</item>
         <item name="android:paddingTop">16dp</item>
         <item name="android:paddingStart">16dp</item>
diff --git a/res/xml/wifi_network_details_fragment.xml b/res/xml/wifi_network_details_fragment.xml
new file mode 100644
index 0000000..dbbf0c3
--- /dev/null
+++ b/res/xml/wifi_network_details_fragment.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<PreferenceScreen
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" >
+
+    <!-- Connected Network Header -->
+    <Preference
+            android:key="connection_detail"
+            android:layout="@layout/connection_detail_pref"/>
+
+    <!-- General Details Category -->
+    <PreferenceCategory
+            android:key="general_details_category" >
+        <!-- Buttons -->
+        <com.android.settings.applications.LayoutPreference
+                android:key="forget_button"
+                android:selectable="false"
+                android:layout="@layout/single_button_panel" />
+
+        <com.android.settings.wifi.WifiDetailPreference
+                android:key="signal_strength"
+                android:title="@string/wifi_signal" />
+
+        <com.android.settings.wifi.WifiDetailPreference
+                android:key="frequency"
+                android:icon="@drawable/ic_frequency_antenna"
+                android:title="@string/wifi_frequency" />
+
+        <com.android.settings.wifi.WifiDetailPreference
+                android:key="security"
+                android:icon="@drawable/ic_security_lock_24dp"
+                android:title="@string/wifi_security" />
+    </PreferenceCategory>
+
+    <!-- IP Details -->
+    <PreferenceCategory
+            android:key="ip_details_category"
+            android:title="@string/wifi_ip_address">
+        <com.android.settings.wifi.WifiDetailPreference
+                android:key="ip_address"
+                android:title="@string/wifi_ip_address" />
+        <com.android.settings.wifi.WifiDetailPreference
+                android:key="router"
+                android:title="@string/wifi_gateway" />
+        <com.android.settings.wifi.WifiDetailPreference
+                android:key="subnet_mask"
+                android:title="@string/wifi_details_subnet_mask" />
+        <com.android.settings.wifi.WifiDetailPreference
+                android:key="dns"
+                android:title="@string/wifi_details_dns" />
+    </PreferenceCategory>
+
+    <!-- IPv6 Details -->
+    <PreferenceCategory
+            android:key="ipv6_details_category"
+            android:title="@string/wifi_details_ipv6_address_header" />
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
index 40972ac..a2e9fe9 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
@@ -39,7 +39,6 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserManager;
-import android.security.KeyStore;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
@@ -76,6 +75,7 @@
     protected ImageView mFingerprintIcon;
     protected int mEffectiveUserId;
     protected int mUserId;
+    protected UserManager mUserManager;
     protected LockPatternUtils mLockPatternUtils;
     protected TextView mErrorTextView;
     protected final Handler mHandler = new Handler();
@@ -90,8 +90,8 @@
         // Only take this argument into account if it belongs to the current profile.
         Intent intent = getActivity().getIntent();
         mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras());
-        final UserManager userManager = UserManager.get(getActivity());
-        mEffectiveUserId = userManager.getCredentialOwnerProfile(mUserId);
+        mUserManager = UserManager.get(getActivity());
+        mEffectiveUserId = mUserManager.getCredentialOwnerProfile(mUserId);
         mLockPatternUtils = new LockPatternUtils(getActivity());
     }
 
@@ -117,7 +117,7 @@
                 Utils.getUserIdFromBundle(
                         getActivity(),
                         getActivity().getIntent().getExtras()));
-        if (UserManager.get(getActivity()).isManagedProfile(credentialOwnerUserId)) {
+        if (mUserManager.isManagedProfile(credentialOwnerUserId)) {
             setWorkChallengeBackground(view, credentialOwnerUserId);
         }
     }
@@ -135,7 +135,7 @@
     // fingerprint is disabled due to device restart.
     private boolean isFingerprintDisallowedByStrongAuth() {
         return !(mLockPatternUtils.isFingerprintAllowedForUser(mEffectiveUserId)
-                && KeyStore.getInstance().state(mUserId) == KeyStore.State.UNLOCKED);
+                && mUserManager.isUserUnlocked(mUserId));
     }
 
     @Override
@@ -262,7 +262,7 @@
     }
 
     protected boolean isProfileChallenge() {
-        return UserManager.get(getContext()).isManagedProfile(mEffectiveUserId);
+        return mUserManager.isManagedProfile(mEffectiveUserId);
     }
 
     protected void reportSuccessfullAttempt() {
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 99c6e8b..94ea2e7 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -57,6 +57,7 @@
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 import android.widget.Button;
+import android.widget.EditText;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
@@ -65,7 +66,6 @@
 import com.android.internal.widget.LockPatternView;
 import com.android.internal.widget.LockPatternView.Cell;
 import com.android.internal.widget.LockPatternView.DisplayMode;
-import com.android.settings.widget.ImeAwareEditText;
 
 import java.util.List;
 
@@ -122,7 +122,7 @@
     private boolean mCooldown = false;
 
     PowerManager.WakeLock mWakeLock;
-    private ImeAwareEditText mPasswordEntry;
+    private EditText mPasswordEntry;
     private LockPatternView mLockPatternView;
     /** Number of calls to {@link #notifyUser()} to ignore before notifying. */
     private int mNotificationCountdown = 0;
@@ -277,7 +277,9 @@
             // Reenable the password entry
             if (mPasswordEntry != null) {
                 mPasswordEntry.setEnabled(true);
-                mPasswordEntry.scheduleShowSoftInput();
+                final InputMethodManager imm = (InputMethodManager) getSystemService(
+                        Context.INPUT_METHOD_SERVICE);
+                imm.showSoftInput(mPasswordEntry, 0);
                 setBackFunctionality(true);
             }
         }
@@ -742,7 +744,7 @@
 
      private void passwordEntryInit() {
         // Password/pin case
-        mPasswordEntry = (ImeAwareEditText) findViewById(R.id.passwordEntry);
+        mPasswordEntry = (EditText) findViewById(R.id.passwordEntry);
         if (mPasswordEntry != null){
             mPasswordEntry.setOnEditorActionListener(this);
             mPasswordEntry.requestFocus();
@@ -795,13 +797,16 @@
             }
         }
 
-        // Make sure that the IME is shown when everything becomes ready.
+        // Asynchronously throw up the IME, since there are issues with requesting it to be shown
+        // immediately.
         if (mLockPatternView == null && !mCooldown) {
             getWindow().setSoftInputMode(
                                 WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
-            if (mPasswordEntry != null) {
-                mPasswordEntry.scheduleShowSoftInput();
-            }
+            mHandler.postDelayed(new Runnable() {
+                @Override public void run() {
+                    imm.showSoftInputUnchecked(0, null);
+                }
+            }, 0);
         }
 
         updateEmergencyCallButtonState();
diff --git a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
index bdf6cc4..9018d9b 100644
--- a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
+++ b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
@@ -43,6 +43,12 @@
     }
 
     @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        mProgressiveDisclosureMixin.setTileLimit(3);
+    }
+
+    @Override
     protected int getPreferenceScreenResId() {
         return R.xml.app_and_notification;
     }
diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java
index aa35328..d5d72bc 100644
--- a/src/com/android/settings/applications/AppStorageSettings.java
+++ b/src/com/android/settings/applications/AppStorageSettings.java
@@ -192,6 +192,8 @@
             } else if (mClearCacheObserver == null) { // Lazy initialization of observer
                 mClearCacheObserver = new ClearCacheObserver();
             }
+            mMetricsFeatureProvider.action(getContext(),
+                    MetricsEvent.ACTION_SETTINGS_CLEAR_APP_CACHE);
             mPm.deleteApplicationCacheFiles(mPackageName, mClearCacheObserver);
         } else if (v == mClearDataButton) {
             if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
@@ -340,6 +342,7 @@
      * button for a system package
      */
     private void initiateClearUserData() {
+        mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_SETTINGS_CLEAR_APP_DATA);
         mClearDataButton.setEnabled(false);
         // Invoke uninstall or clear user data based on sysPackage
         String packageName = mAppEntry.info.packageName;
diff --git a/src/com/android/settings/applications/ConfirmConvertToFbe.java b/src/com/android/settings/applications/ConfirmConvertToFbe.java
index 7ebca1d..1a4421e 100644
--- a/src/com/android/settings/applications/ConfirmConvertToFbe.java
+++ b/src/com/android/settings/applications/ConfirmConvertToFbe.java
@@ -40,6 +40,7 @@
             public void onClick(View v) {
                 Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
                 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                intent.setPackage("android");
                 intent.putExtra(Intent.EXTRA_REASON, "convert_fbe");
                 getActivity().sendBroadcast(intent);
             }
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index da6bbc0..08be7f7 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -157,8 +157,6 @@
     private static final String KEY_MEMORY = "memory";
     private static final String KEY_VERSION = "app_version";
 
-    private static final String NOTIFICATION_TUNER_SETTING = "show_importance_slider";
-
     private final HashSet<String> mHomePackages = new HashSet<>();
 
     private boolean mInitialized;
@@ -735,6 +733,8 @@
                                 new DialogInterface.OnClickListener() {
                             public void onClick(DialogInterface dialog, int which) {
                                 // Disable the app
+                                mMetricsFeatureProvider.action(getContext(),
+                                        MetricsEvent.ACTION_SETTINGS_DISABLE_APP);
                                 new DisableChanger(InstalledAppDetails.this, mAppEntry.info,
                                         PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
                                 .execute((Object)null);
@@ -749,6 +749,8 @@
                                 new DialogInterface.OnClickListener() {
                             public void onClick(DialogInterface dialog, int which) {
                                 // Disable the app and ask for uninstall
+                                mMetricsFeatureProvider.action(getContext(),
+                                        MetricsEvent.ACTION_SETTINGS_DISABLE_APP);
                                 uninstallPkg(mAppEntry.info.packageName,
                                         false, true);
                             }
@@ -777,13 +779,14 @@
         Uri packageURI = Uri.parse("package:"+packageName);
         Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
         uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
+        mMetricsFeatureProvider.action(
+                getContext(), MetricsEvent.ACTION_SETTINGS_UNINSTALL_APP);
         startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
         mDisableAfterUninstall = andDisable;
     }
 
     private void forceStopPackage(String pkgName) {
-        FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider().action(getContext(),
-                MetricsEvent.ACTION_APP_FORCE_STOP, pkgName);
+        mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_APP_FORCE_STOP, pkgName);
         ActivityManager am = (ActivityManager) getActivity().getSystemService(
                 Context.ACTIVITY_SERVICE);
         Log.d(LOG_TAG, "Stopping package " + pkgName);
@@ -802,7 +805,7 @@
             mForceStopButton.setEnabled(false);
         } else {
             mForceStopButton.setEnabled(enabled);
-            mForceStopButton.setOnClickListener(InstalledAppDetails.this);
+            mForceStopButton.setOnClickListener(this);
         }
     }
 
@@ -875,6 +878,8 @@
                 Intent uninstallDAIntent = new Intent(activity, DeviceAdminAdd.class);
                 uninstallDAIntent.putExtra(DeviceAdminAdd.EXTRA_DEVICE_ADMIN_PACKAGE_NAME,
                         mPackageName);
+                mMetricsFeatureProvider.action(
+                        activity, MetricsEvent.ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN);
                 activity.startActivityForResult(uninstallDAIntent, REQUEST_REMOVE_DEVICE_ADMIN);
                 return;
             }
@@ -895,6 +900,11 @@
                         showDialogInner(DLG_DISABLE, 0);
                     }
                 } else {
+                    mMetricsFeatureProvider.action(
+                            getActivity(),
+                            mAppEntry.info.enabled
+                                    ? MetricsEvent.ACTION_SETTINGS_DISABLE_APP
+                                    : MetricsEvent.ACTION_SETTINGS_ENABLE_APP);
                     new DisableChanger(this, mAppEntry.info,
                             PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
                                     .execute((Object) null);
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/fingerprint/FingerprintEnrollEnrolling.java
index d2cac09..e6e6bcd 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollEnrolling.java
@@ -237,12 +237,15 @@
 
     private void launchFinish(byte[] token) {
         Intent intent = getFinishIntent();
-        intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+        intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+                | Intent.FLAG_ACTIVITY_CLEAR_TOP
+                | Intent.FLAG_ACTIVITY_SINGLE_TOP);
         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
         if (mUserId != UserHandle.USER_NULL) {
             intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
         }
         startActivity(intent);
+        overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
         finish();
     }
 
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollFinish.java b/src/com/android/settings/fingerprint/FingerprintEnrollFinish.java
index 3379169..4bd438c 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollFinish.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollFinish.java
@@ -17,7 +17,6 @@
 package com.android.settings.fingerprint;
 
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.os.Bundle;
 import android.view.View;
@@ -32,19 +31,31 @@
  */
 public class FingerprintEnrollFinish extends FingerprintEnrollBase {
 
+    private static final int REQUEST_ADD_ANOTHER = 1;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.fingerprint_enroll_finish);
         setHeaderText(R.string.security_settings_fingerprint_enroll_finish_title);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
         Button addButton = (Button) findViewById(R.id.add_another_button);
 
         final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this);
-        int enrolled = fpm.getEnrolledFingerprints(mUserId).size();
-        int max = getResources().getInteger(
-                com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
-        if (enrolled >= max) {
-            /* Don't show "Add" button if too many fingerprints already added */
+        boolean hideAddAnother = false;
+        if (fpm != null) {
+            int enrolled = fpm.getEnrolledFingerprints(mUserId).size();
+            int max = getResources().getInteger(
+                    com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
+            hideAddAnother = enrolled >= max;
+        }
+        if (hideAddAnother) {
+            // Don't show "Add" button if too many fingerprints already added
             addButton.setVisibility(View.INVISIBLE);
         } else {
             addButton.setOnClickListener(this);
@@ -60,15 +71,22 @@
     @Override
     public void onClick(View v) {
         if (v.getId() == R.id.add_another_button) {
-            final Intent intent = getEnrollingIntent();
-            intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
-            startActivity(intent);
-            finish();
+            startActivityForResult(getEnrollingIntent(), REQUEST_ADD_ANOTHER);
         }
         super.onClick(v);
     }
 
     @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_ADD_ANOTHER && resultCode != RESULT_CANCELED) {
+            setResult(resultCode, data);
+            finish();
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsEvent.FINGERPRINT_ENROLL_FINISH;
     }
diff --git a/src/com/android/settings/fingerprint/SetupFingerprintEnrollEnrolling.java b/src/com/android/settings/fingerprint/SetupFingerprintEnrollEnrolling.java
index 2c44f6d..5d0152c 100644
--- a/src/com/android/settings/fingerprint/SetupFingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/fingerprint/SetupFingerprintEnrollEnrolling.java
@@ -16,26 +16,14 @@
 
 package com.android.settings.fingerprint;
 
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.FragmentManager;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Resources;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.R;
 import com.android.settings.SetupWizardUtils;
-import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 
 public class SetupFingerprintEnrollEnrolling extends FingerprintEnrollEnrolling {
 
-    private static final String TAG_DIALOG = "dialog";
-
     @Override
     protected Intent getFinishIntent() {
         final Intent intent = new Intent(this, SetupFingerprintEnrollFinish.class);
@@ -50,71 +38,7 @@
     }
 
     @Override
-    protected void initViews() {
-        super.initViews();
-        final Button skipButton = (Button) findViewById(R.id.skip_button);
-        skipButton.setVisibility(View.VISIBLE);
-        skipButton.setOnClickListener(this);
-    }
-
-    @Override
-    public void onClick(View v) {
-        switch (v.getId()) {
-            case R.id.skip_button:
-                new SkipDialog().show(getFragmentManager(), TAG_DIALOG);
-                break;
-            default:
-                super.onClick(v);
-        }
-    }
-
-    @Override
     public int getMetricsCategory() {
         return MetricsEvent.FINGERPRINT_ENROLLING_SETUP;
     }
-
-    public static class SkipDialog extends InstrumentedDialogFragment {
-
-        @Override
-        public void show(FragmentManager manager, String tag) {
-            if (manager.findFragmentByTag(tag) == null) {
-                super.show(manager, tag);
-            }
-        }
-
-        public SkipDialog() {
-            // no-arg constructor for fragment
-        }
-
-        @Override
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            return new AlertDialog.Builder(getActivity())
-                    .setTitle(R.string.setup_fingerprint_enroll_enrolling_skip_title)
-                    .setMessage(R.string.setup_fingerprint_enroll_enrolling_skip_message)
-                    .setCancelable(false)
-                    .setPositiveButton(R.string.skip_anyway_button_label,
-                            new DialogInterface.OnClickListener() {
-                                @Override
-                                public void onClick(DialogInterface dialog, int id) {
-                                    Activity activity = getActivity();
-                                    if (activity != null) {
-                                        activity.setResult(RESULT_SKIP);
-                                        activity.finish();
-                                    }
-                                }
-                            })
-                    .setNegativeButton(R.string.go_back_button_label,
-                            new DialogInterface.OnClickListener() {
-                                @Override
-                                public void onClick(DialogInterface dialog, int id) {
-                                }
-                            })
-                    .create();
-        }
-
-        @Override
-        public int getMetricsCategory() {
-            return MetricsEvent.DIALOG_FINGERPRINT_CANCEL_SETUP;
-        }
-    }
 }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
index 96ac042..c3a4d90 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
@@ -126,7 +126,6 @@
         final DrainType drainType = sipper.drainType;
         final int uid = sipper.getUid();
 
-        // TODO(b/34385770): add logic to extract type service
         if (drainType == DrainType.WIFI) {
             return UsageType.WIFI;
         } else if (drainType == DrainType.BLUETOOTH) {
@@ -164,7 +163,7 @@
             usageData.totalPowerMah += sipper.totalPowerMah;
         }
 
-        // TODO(b/34385770): add logic to extract the summary
+        // TODO(b/35396770): add logic to extract the summary
         final List<PowerUsageData> batteryDataList = new ArrayList<>(batteryDataMap.values());
         final double totalPower = statusHelper.getTotalPower();
         for (final PowerUsageData usageData : batteryDataList) {
diff --git a/src/com/android/settings/search2/InlineSwitchViewHolder.java b/src/com/android/settings/search2/InlineSwitchViewHolder.java
index ac49b1c..d4a0ca2 100644
--- a/src/com/android/settings/search2/InlineSwitchViewHolder.java
+++ b/src/com/android/settings/search2/InlineSwitchViewHolder.java
@@ -18,10 +18,11 @@
 package com.android.settings.search2;
 
 import android.content.Context;
+import android.util.Pair;
 import android.view.View;
-import android.widget.CompoundButton;
 import android.widget.Switch;
 
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 
 /**
@@ -36,7 +37,7 @@
     public InlineSwitchViewHolder(View view, Context context) {
         super(view);
         mContext = context;
-        switchView = (Switch) view.findViewById(R.id.switchView);
+        switchView = view.findViewById(R.id.switchView);
     }
 
     @Override
@@ -47,12 +48,21 @@
         }
         final InlineSwitchPayload payload = (InlineSwitchPayload) result.payload;
         switchView.setChecked(payload.getSwitchValue(mContext));
-        switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                fragment.onSearchResultClicked();
-                payload.setSwitchValue(mContext, isChecked);
-            }
+        switchView.setOnCheckedChangeListener((buttonView, isChecked) -> {
+            final Pair<Integer, Object> name = Pair.create(
+                    MetricsEvent.FIELD_SETTINGS_SEARCH_INLINE_RESULT_NAME, payload.settingsUri);
+            final Pair<Integer, Object> value = Pair.create(
+                    MetricsEvent.FIELD_SETTINGS_SEARCH_INLINE_RESULT_VALUE, isChecked
+                            ? "checked"
+                            : "not-checked");
+            final Pair<Integer, Object> rank = Pair.create(
+                    MetricsEvent.FIELD_SETTINGS_SERACH_RESULT_RANK, getAdapterPosition());
+            mMetricsFeatureProvider.action(mContext,
+                    MetricsEvent.ACTION_CLICK_SETTINGS_SEARCH_INLINE_RESULT,
+                    name, value, rank);
+
+            fragment.onSearchResultClicked();
+            payload.setSwitchValue(mContext, isChecked);
         });
     }
 }
diff --git a/src/com/android/settings/search2/IntentSearchViewHolder.java b/src/com/android/settings/search2/IntentSearchViewHolder.java
index 79e1cc8..f0cbc51 100644
--- a/src/com/android/settings/search2/IntentSearchViewHolder.java
+++ b/src/com/android/settings/search2/IntentSearchViewHolder.java
@@ -23,8 +23,6 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.SettingsActivity;
-import com.android.settings.core.instrumentation.MetricsFeatureProvider;
-import com.android.settings.overlay.FeatureFactory;
 
 /**
  * ViewHolder for intent based search results.
@@ -32,12 +30,8 @@
  */
 public class IntentSearchViewHolder extends SearchViewHolder {
 
-    private final MetricsFeatureProvider mMetricsFeatureProvider;
-
     public IntentSearchViewHolder(View view) {
         super(view);
-        mMetricsFeatureProvider = FeatureFactory.getFactory(view.getContext())
-                .getMetricsFeatureProvider();
     }
 
     @Override
diff --git a/src/com/android/settings/search2/SavedQueryRemover.java b/src/com/android/settings/search2/SavedQueryRemover.java
new file mode 100644
index 0000000..4395cb6
--- /dev/null
+++ b/src/com/android/settings/search2/SavedQueryRemover.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.search2;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.util.Log;
+
+import com.android.settings.search.IndexDatabaseHelper;
+import com.android.settings.utils.AsyncLoader;
+
+import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_SAVED_QUERIES;
+
+public class SavedQueryRemover extends AsyncLoader<Void> {
+
+    private static final String LOG_TAG = "SavedQueryRemover";
+
+    private final String mQuery;
+
+    public SavedQueryRemover(Context context, String query) {
+        super(context);
+        mQuery = query;
+    }
+
+    @Override
+    public Void loadInBackground() {
+        final SQLiteDatabase database = getWritableDatabase();
+        try {
+            // First, delete all saved queries that are the same
+            database.delete(TABLE_SAVED_QUERIES,
+                    IndexDatabaseHelper.SavedQueriesColumns.QUERY + " = ?",
+                    new String[]{mQuery});
+        } catch (Exception e) {
+            Log.d(LOG_TAG, "Cannot update saved Search queries", e);
+        }
+        return null;
+    }
+
+    @Override
+    protected void onDiscardResult(Void result) {
+
+    }
+
+    private SQLiteDatabase getWritableDatabase() {
+        try {
+            return IndexDatabaseHelper.getInstance(getContext()).getWritableDatabase();
+        } catch (SQLiteException e) {
+            Log.e(LOG_TAG, "Cannot open writable database", e);
+            return null;
+        }
+    }
+}
diff --git a/src/com/android/settings/search2/SavedQueryViewHolder.java b/src/com/android/settings/search2/SavedQueryViewHolder.java
index a32ed05..6629c89 100644
--- a/src/com/android/settings/search2/SavedQueryViewHolder.java
+++ b/src/com/android/settings/search2/SavedQueryViewHolder.java
@@ -22,17 +22,18 @@
 public class SavedQueryViewHolder extends SearchViewHolder {
 
     public final TextView titleView;
+    public final View removeButton;
 
     public SavedQueryViewHolder(View view) {
         super(view);
-        titleView = (TextView) view.findViewById(android.R.id.title);
+        titleView = view.findViewById(android.R.id.title);
+        removeButton = view.findViewById(android.R.id.icon);
     }
 
     @Override
     public void onBind(SearchFragment fragment, SearchResult result) {
         titleView.setText(result.title);
-        itemView.setOnClickListener(v -> {
-            fragment.onSavedQueryClicked(result.title);
-        });
+        titleView.setOnClickListener(v -> fragment.onSavedQueryClicked(result.title));
+        removeButton.setOnClickListener(v -> fragment.onRemoveSavedQueryClicked(result.title));
     }
 }
diff --git a/src/com/android/settings/search2/SearchFragment.java b/src/com/android/settings/search2/SearchFragment.java
index 957713b..02ff2c8 100644
--- a/src/com/android/settings/search2/SearchFragment.java
+++ b/src/com/android/settings/search2/SearchFragment.java
@@ -45,9 +45,8 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class SearchFragment extends InstrumentedFragment implements
-        SearchView.OnQueryTextListener, LoaderManager.LoaderCallbacks<List<? extends SearchResult>>
-{
+public class SearchFragment extends InstrumentedFragment implements SearchView.OnQueryTextListener,
+        LoaderManager.LoaderCallbacks<List<? extends SearchResult>> {
     private static final String TAG = "SearchFragment";
 
     @VisibleForTesting
@@ -66,7 +65,7 @@
     private static final int NUM_QUERY_LOADERS = 2;
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    AtomicInteger mUnfinishedLoadersCount = new AtomicInteger(NUM_QUERY_LOADERS);;
+    AtomicInteger mUnfinishedLoadersCount = new AtomicInteger(NUM_QUERY_LOADERS);
 
     // Logging
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
@@ -75,14 +74,14 @@
     @VisibleForTesting
     String mQuery;
 
-    private final SaveQueryRecorderCallback mSaveQueryRecorderCallback =
-            new SaveQueryRecorderCallback();
+    private final SaveQueryCallback mSaveQueryCallback =
+            new SaveQueryCallback();
 
     private boolean mNeverEnteredQuery = true;
     private int mResultClickCount;
     private MetricsFeatureProvider mMetricsFeatureProvider;
 
-    @VisibleForTesting (otherwise = VisibleForTesting.PRIVATE)
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     SearchFeatureProvider mSearchFeatureProvider;
 
     private SearchResultsAdapter mSearchAdapter;
@@ -93,8 +92,7 @@
     private LinearLayout mNoResultsView;
 
     @VisibleForTesting
-    final RecyclerView.OnScrollListener mScrollListener =
-            new RecyclerView.OnScrollListener() {
+    final RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
         @Override
         public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
             if (dy != 0) {
@@ -120,7 +118,7 @@
         super.onCreate(savedInstanceState);
         setHasOptionsMenu(true);
         mSearchAdapter = new SearchResultsAdapter(this);
-        
+
         mSearchFeatureProvider.initFeedbackButton();
 
         final LoaderManager loaderManager = getLoaderManager();
@@ -155,12 +153,12 @@
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         final View view = inflater.inflate(R.layout.search_panel_2, container, false);
-        mResultsRecyclerView = (RecyclerView) view.findViewById(R.id.list_results);
+        mResultsRecyclerView = view.findViewById(R.id.list_results);
         mResultsRecyclerView.setAdapter(mSearchAdapter);
         mResultsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
         mResultsRecyclerView.addOnScrollListener(mScrollListener);
 
-        mNoResultsView = (LinearLayout) view.findViewById(R.id.no_results_layout);
+        mNoResultsView = view.findViewById(R.id.no_results_layout);
         return view;
     }
 
@@ -220,8 +218,8 @@
     @Override
     public boolean onQueryTextSubmit(String query) {
         // Save submitted query.
-        getLoaderManager().restartLoader(SaveQueryRecorderCallback.LOADER_ID_SAVE_QUERY_TASK, null,
-                mSaveQueryRecorderCallback);
+        getLoaderManager().restartLoader(SaveQueryCallback.LOADER_ID_SAVE_QUERY_TASK, null,
+                mSaveQueryCallback);
         hideKeyboard();
         return true;
     }
@@ -245,16 +243,20 @@
     @Override
     public void onLoadFinished(Loader<List<? extends SearchResult>> loader,
             List<? extends SearchResult> data) {
-        mSearchAdapter.addResultsToMap(data, loader.getClass().getName());
-
-        if (mUnfinishedLoadersCount.decrementAndGet() == 0) {
-            final int resultCount = mSearchAdapter.mergeResults();
-            mSearchFeatureProvider.showFeedbackButton(this, getView());
-
-            if (resultCount == 0) {
-                mNoResultsView.setVisibility(View.VISIBLE);
-            }
+        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();
         }
+        mNoResultsView.setVisibility(resultCount == 0 ? View.VISIBLE : View.GONE);
+        mSearchFeatureProvider.showFeedbackButton(this, getView());
     }
 
     @Override
@@ -262,15 +264,26 @@
     }
 
     public void onSearchResultClicked() {
+        getLoaderManager().restartLoader(SaveQueryCallback.LOADER_ID_SAVE_QUERY_TASK, null,
+                mSaveQueryCallback);
         mResultClickCount++;
     }
 
     public void onSavedQueryClicked(CharSequence query) {
         final String queryString = query.toString();
+        mMetricsFeatureProvider.action(getContext(),
+                MetricsProto.MetricsEvent.ACTION_CLICK_SETTINGS_SEARCH_SAVED_QUERY);
         mSearchView.setQuery(queryString, false /* submit */);
         onQueryTextChange(queryString);
     }
 
+    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);
+    }
+
     private void restartLoaders() {
         final LoaderManager loaderManager = getLoaderManager();
         mUnfinishedLoadersCount.set(NUM_QUERY_LOADERS);
@@ -286,7 +299,7 @@
         return mSearchAdapter.getSearchResults();
     }
 
-    @VisibleForTesting (otherwise = VisibleForTesting.PRIVATE)
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     SearchView makeSearchView(ActionBar actionBar, String query) {
         final SearchView searchView = new SearchView(actionBar.getThemedContext());
         searchView.setIconifiedByDefault(false);
@@ -313,19 +326,31 @@
         }
     }
 
-    private class SaveQueryRecorderCallback implements LoaderManager.LoaderCallbacks<Void> {
+    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) {
-            return new SavedQueryRecorder(getActivity(), mQuery);
+            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
diff --git a/src/com/android/settings/search2/SearchResultsAdapter.java b/src/com/android/settings/search2/SearchResultsAdapter.java
index b76958a..6ff68b1 100644
--- a/src/com/android/settings/search2/SearchResultsAdapter.java
+++ b/src/com/android/settings/search2/SearchResultsAdapter.java
@@ -19,7 +19,7 @@
 import android.content.Context;
 import android.support.annotation.MainThread;
 import android.support.annotation.VisibleForTesting;
-import android.support.v7.widget.RecyclerView.Adapter;
+import android.support.v7.widget.RecyclerView;
 import android.util.ArrayMap;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -32,10 +32,10 @@
 import java.util.List;
 import java.util.Map;
 
-import static com.android.settings.search2.SearchResult.TOP_RANK;
 import static com.android.settings.search2.SearchResult.BOTTOM_RANK;
+import static com.android.settings.search2.SearchResult.TOP_RANK;
 
-public class SearchResultsAdapter extends Adapter<SearchViewHolder> {
+public class SearchResultsAdapter extends RecyclerView.Adapter<SearchViewHolder> {
 
     private final List<SearchResult> mSearchResults;
     private final SearchFragment mFragment;
@@ -91,16 +91,28 @@
 
     /**
      * Store the results from each of the loaders to be merged when all loaders are finished.
-     * @param freshResults are the results from the loader.
+     *
+     * @param results         the results from the loader.
      * @param loaderClassName class name of the loader.
      */
     @MainThread
-    public void addResultsToMap(List<? extends SearchResult> freshResults,
-            String loaderClassName) {
-        if (freshResults == null) {
+    public void addSearchResults(List<? extends SearchResult> results, String loaderClassName) {
+        if (results == null) {
             return;
         }
-        mResultsMap.put(loaderClassName, freshResults);
+        mResultsMap.put(loaderClassName, results);
+    }
+
+    /**
+     * Displays recent searched queries.
+     *
+     * @return The number of saved queries to display
+     */
+    public int displaySavedQuery(List<? extends SearchResult> data) {
+        clearResults();
+        mSearchResults.addAll(data);
+        notifyDataSetChanged();
+        return mSearchResults.size();
     }
 
     /**
@@ -109,7 +121,7 @@
      *
      * @return Number of matched results
      */
-    public int mergeResults() {
+    public int displaySearchResults() {
         final List<? extends SearchResult> databaseResults = mResultsMap
                 .get(DatabaseResultLoader.class.getName());
         final List<? extends SearchResult> installedAppResults = mResultsMap
@@ -129,7 +141,7 @@
             while ((appIndex < appSize) && (installedAppResults.get(appIndex).rank == rank)) {
                 results.add(installedAppResults.get(appIndex++));
             }
-            rank ++;
+            rank++;
         }
 
         while (dbIndex < dbSize) {
diff --git a/src/com/android/settings/search2/SearchViewHolder.java b/src/com/android/settings/search2/SearchViewHolder.java
index e369391..123a602 100644
--- a/src/com/android/settings/search2/SearchViewHolder.java
+++ b/src/com/android/settings/search2/SearchViewHolder.java
@@ -17,8 +17,6 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
 import android.view.View;
@@ -26,6 +24,8 @@
 import android.widget.TextView;
 
 import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
 
 /**
  * The ViewHolder for the Search RecyclerView.
@@ -39,12 +39,16 @@
     public final TextView breadcrumbView;
     public final ImageView iconView;
 
+    protected final MetricsFeatureProvider mMetricsFeatureProvider;
+
     public SearchViewHolder(View view) {
         super(view);
-        titleView = (TextView) view.findViewById(android.R.id.title);
-        summaryView = (TextView) view.findViewById(android.R.id.summary);
-        iconView = (ImageView) view.findViewById(android.R.id.icon);
-        breadcrumbView = (TextView) view.findViewById(R.id.breadcrumb);
+        mMetricsFeatureProvider = FeatureFactory.getFactory(view.getContext())
+                .getMetricsFeatureProvider();
+        titleView = view.findViewById(android.R.id.title);
+        summaryView = view.findViewById(android.R.id.summary);
+        iconView = view.findViewById(android.R.id.icon);
+        breadcrumbView = view.findViewById(R.id.breadcrumb);
     }
 
     public void onBind(SearchFragment fragment, SearchResult result) {
diff --git a/src/com/android/settings/widget/ImeAwareEditText.java b/src/com/android/settings/widget/ImeAwareEditText.java
deleted file mode 100644
index 6e70929..0000000
--- a/src/com/android/settings/widget/ImeAwareEditText.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-
-public class ImeAwareEditText extends EditText {
-    private boolean mHasPendingShowSoftInputRequest;
-    final Runnable mRunShowSoftInputIfNecessary = () -> showSoftInputIfNecessary();
-
-    public ImeAwareEditText(Context context) {
-        super(context, null);
-    }
-
-    public ImeAwareEditText(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public ImeAwareEditText(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    public ImeAwareEditText(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    /**
-     * This method is called back by the system when the system is about to establish a connection
-     * to the current input method.
-     *
-     * <p>This is a good and reliable signal to schedule a pending task to call
-     * {@link InputMethodManager#showSoftInput(View, int)}.</p>
-     *
-     * @param editorInfo context about the text input field.
-     * @return {@link InputConnection} to be passed to the input method.
-     */
-    @Override
-    public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
-        final InputConnection ic = super.onCreateInputConnection(editorInfo);
-        if (mHasPendingShowSoftInputRequest) {
-            removeCallbacks(mRunShowSoftInputIfNecessary);
-            post(mRunShowSoftInputIfNecessary);
-        }
-        return ic;
-    }
-
-    private void showSoftInputIfNecessary() {
-        if (mHasPendingShowSoftInputRequest) {
-            final InputMethodManager imm =
-                    getContext().getSystemService(InputMethodManager.class);
-            imm.showSoftInput(this, 0);
-            mHasPendingShowSoftInputRequest = false;
-        }
-    }
-
-    public void scheduleShowSoftInput() {
-        final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
-        if (imm.isActive(this)) {
-            // This means that ImeAwareEditText is already connected to the IME.
-            // InputMethodManager#showSoftInput() is guaranteed to pass client-side focus check.
-            mHasPendingShowSoftInputRequest = false;
-            removeCallbacks(mRunShowSoftInputIfNecessary);
-            imm.showSoftInput(this, 0);
-            return;
-        }
-
-        // Otherwise, InputMethodManager#showSoftInput() should be deferred after
-        // onCreateInputConnection().
-        mHasPendingShowSoftInputRequest = true;
-    }
-}
diff --git a/src/com/android/settings/wifi/WifiDetailPreference.java b/src/com/android/settings/wifi/WifiDetailPreference.java
new file mode 100644
index 0000000..6d34ad1
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiDetailPreference.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2009 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;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+/**
+ * A Preference to be used with the Wifi Network Detail Fragment that allows a summary text to be
+ * set inside the widget resource
+ */
+public class WifiDetailPreference extends Preference {
+    private String mDetailText;
+
+    public WifiDetailPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setWidgetLayoutResource(R.layout.preference_widget_summary);
+    }
+
+    public void setDetailText(String text) {
+        mDetailText = text;
+        notifyChanged();
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder view) {
+        super.onBindViewHolder(view);
+        TextView textView = ((TextView) view.findViewById(R.id.widget_summary));
+        textView.setText(mDetailText);
+        textView.setPadding(0, 0, 10, 0);
+    }
+}
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 8a3c8ac..dd17a64 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -42,7 +42,6 @@
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceCategory;
 import android.support.v7.preference.PreferenceManager;
-import android.support.v7.preference.PreferenceViewHolder;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.ContextMenu;
@@ -65,6 +64,7 @@
 import com.android.settings.search.SearchIndexableRaw;
 import com.android.settings.widget.SummaryUpdater.OnSummaryChangeListener;
 import com.android.settings.widget.SwitchBarController;
+import com.android.settings.wifi.details.WifiNetworkDetailsFragment;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.settingslib.wifi.AccessPoint.AccessPointListener;
@@ -178,15 +178,15 @@
         super.onViewCreated(view, savedInstanceState);
         final Activity activity = getActivity();
         if (activity != null) {
-            if (!isUiRestricted()) {
-                mProgressHeader = (ProgressBar) setPinnedHeaderView(R.layout.wifi_progress_header);
-            }
+            mProgressHeader = (ProgressBar) setPinnedHeaderView(R.layout.wifi_progress_header);
+            setProgressBarVisible(false);
         }
     }
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
+
         getPreferenceManager().setPreferenceComparisonCallback(
                 new PreferenceManager.SimplePreferenceComparisonCallback());
         addPreferencesFromResource(R.xml.wifi_settings);
@@ -496,6 +496,12 @@
 
     @Override
     public boolean onPreferenceTreeClick(Preference preference) {
+        // If the preference has a fragment set, open that
+        if (preference.getFragment() != null) {
+            preference.setOnPreferenceClickListener(null);
+            return super.onPreferenceTreeClick(preference);
+        }
+
         if (preference instanceof LongPressAccessPointPreference) {
             mSelectedAccessPoint = ((LongPressAccessPointPreference) preference).getAccessPoint();
             if (mSelectedAccessPoint == null) {
@@ -607,15 +613,19 @@
     public void onAccessPointsChanged() {
         // Safeguard from some delayed event handling
         if (getActivity() == null) return;
+        final int wifiState = mWifiManager.getWifiState();
         if (isUiRestricted()) {
             removeConnectedAccessPointPreference();
             mAccessPointsPreferenceCategory.removeAll();
             if (!isUiRestrictedByOnlyAdmin()) {
-                addMessagePreference(R.string.wifi_empty_list_user_restricted);
+                if (wifiState == WifiManager.WIFI_AP_STATE_DISABLED) {
+                    setOffMessage();
+                } else {
+                    addMessagePreference(R.string.wifi_empty_list_user_restricted);
+                }
             }
             return;
         }
-        final int wifiState = mWifiManager.getWifiState();
 
         switch (wifiState) {
             case WifiManager.WIFI_STATE_ENABLED:
@@ -635,7 +645,7 @@
                 for (; index < numAccessPointsToShow; index++) {
                     AccessPoint accessPoint = accessPoints.get(index);
                     // Ignore access points that are out of range.
-                    if (accessPoint.getLevel() != -1) {
+                    if (accessPoint.isReachable()) {
                         String key = accessPoint.getBssid();
                         if (TextUtils.isEmpty(key)) {
                             key = accessPoint.getSsidStr();
@@ -665,14 +675,7 @@
                 removeCachedPrefs(mAccessPointsPreferenceCategory);
                 if (!hasAvailableAccessPoints) {
                     setProgressBarVisible(true);
-                    Preference pref = new Preference(getContext()) {
-                        @Override
-                        public void onBindViewHolder(PreferenceViewHolder holder) {
-                            super.onBindViewHolder(holder);
-                            // Show a line on each side of add network.
-                            holder.setDividerAllowedBelow(true);
-                        }
-                    };
+                    Preference pref = new Preference(getPrefContext());
                     pref.setSelectable(false);
                     pref.setSummary(R.string.wifi_empty_list_wifi_on);
                     pref.setOrder(index++);
@@ -752,7 +755,10 @@
             return true;
         }
 
-        // Else same AP is connected, nothing to do
+        // Else same AP is connected, simply refresh the connected access point preference
+        // (first and only access point in this category).
+        ((LongPressAccessPointPreference) mConnectedAccessPointPreferenceCategory.getPreference(0))
+                .refresh();
         return true;
     }
 
@@ -767,6 +773,12 @@
         if (pref == null) {
             pref = createLongPressActionPointPreference(connectedAp);
         }
+
+        // Save the state of the current access point in the bundle so that we can restore it
+        // in the Wifi Network Details Fragment
+        pref.getAccessPoint().saveWifiState(pref.getExtras());
+        pref.setFragment(WifiNetworkDetailsFragment.class.getName());
+
         pref.refresh();
         mConnectedAccessPointPreferenceCategory.addPreference(pref);
         mConnectedAccessPointPreferenceCategory.setVisible(true);
@@ -792,22 +804,13 @@
     }
 
     private void setOffMessage() {
-        if (isUiRestricted()) {
-            removeConnectedAccessPointPreference();
-            mAccessPointsPreferenceCategory.removeAll();
-            if (!isUiRestrictedByOnlyAdmin()) {
-                addMessagePreference(R.string.wifi_empty_list_user_restricted);
-            }
-            return;
-        }
-
         final CharSequence briefText = getText(R.string.wifi_empty_list_wifi_off);
 
         // Don't use WifiManager.isScanAlwaysAvailable() to check the Wi-Fi scanning mode. Instead,
         // read the system settings directly. Because when the device is in Airplane mode, even if
         // Wi-Fi scanning mode is on, WifiManager.isScanAlwaysAvailable() still returns "off".
         final ContentResolver resolver = getActivity().getContentResolver();
-        final boolean wifiScanningMode = Settings.Global.getInt(
+        final boolean wifiScanningMode = !isUiRestricted() && Settings.Global.getInt(
                 resolver, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1;
 
         if (!wifiScanningMode) {
@@ -841,7 +844,7 @@
 
     protected void setProgressBarVisible(boolean visible) {
         if (mProgressHeader != null) {
-            mProgressHeader.setVisibility(visible ? View.VISIBLE : View.GONE);
+            mProgressHeader.setVisibility(visible && !isUiRestricted() ? View.VISIBLE : View.GONE);
         }
     }
 
@@ -862,6 +865,7 @@
 
     @Override
     public void onConnectedChanged() {
+        onAccessPointsChanged();
         changeNextButtonState(mWifiTracker.isConnected());
     }
 
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
new file mode 100644
index 0000000..5f489f2
--- /dev/null
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -0,0 +1,250 @@
+/*
+ * 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 android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.net.ConnectivityManager;
+import android.net.DhcpInfo;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkBadging;
+import android.net.NetworkInfo;
+import android.net.NetworkUtils;
+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 android.util.Log;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.core.lifecycle.Lifecycle;
+import com.android.settings.core.lifecycle.LifecycleObserver;
+import com.android.settings.core.lifecycle.events.OnResume;
+import com.android.settings.wifi.WifiDetailPreference;
+import com.android.settingslib.wifi.AccessPoint;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.List;
+
+/**
+ * Controller for logic pertaining to displaying Wifi information for the
+ * {@link WifiNetworkDetailsFragment}.
+ */
+public class WifiDetailPreferenceController extends PreferenceController implements
+        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";
+
+    private AccessPoint mAccessPoint;
+    private NetworkInfo mNetworkInfo;
+    private Context mPrefContext;
+    private int mRssi;
+    private String[] mSignalStr;
+    private WifiConfiguration mWifiConfig;
+    private WifiInfo mWifiInfo;
+    private final WifiManager mWifiManager;
+
+    // Preferences - in order of appearance
+    private Preference mConnectionDetailPref;
+    private WifiDetailPreference mSignalStrengthPref;
+    private WifiDetailPreference mFrequencyPref;
+    private WifiDetailPreference mSecurityPref;
+    private WifiDetailPreference mIpAddressPref;
+    private WifiDetailPreference mRouterPref;
+    private WifiDetailPreference mSubnetPref;
+    private WifiDetailPreference mDnsPref;
+    private PreferenceCategory mIpv6AddressCategory;
+
+    public WifiDetailPreferenceController(AccessPoint accessPoint, Context context,
+            Lifecycle lifecycle, WifiManager wifiManager) {
+        super(context);
+
+        mAccessPoint = accessPoint;
+        mNetworkInfo = accessPoint.getNetworkInfo();
+        mRssi = accessPoint.getRssi();
+        mSignalStr = context.getResources().getStringArray(R.array.wifi_signal);
+        mWifiConfig = accessPoint.getConfig();
+        mWifiManager = wifiManager;
+
+        lifecycle.addObserver(this);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        // Returns null since this controller contains more than one Preference
+        return null;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        mPrefContext = screen.getPreferenceManager().getContext();
+
+        mConnectionDetailPref = screen.findPreference(KEY_CONNECTION_DETAIL_PREF);
+
+        mSignalStrengthPref =
+                (WifiDetailPreference) screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
+        mFrequencyPref = (WifiDetailPreference) screen.findPreference(KEY_FREQUENCY_PREF);
+        mSecurityPref = (WifiDetailPreference) screen.findPreference(KEY_SECURITY_PREF);
+
+        mIpAddressPref = (WifiDetailPreference) screen.findPreference(KEY_IP_ADDRESS_PREF);
+        mRouterPref = (WifiDetailPreference) screen.findPreference(KEY_ROUTER_PREF);
+        mSubnetPref = (WifiDetailPreference) screen.findPreference(KEY_SUBNET_MASK_PREF);
+        mDnsPref = (WifiDetailPreference) screen.findPreference(KEY_DNS_PREF);
+
+        mIpv6AddressCategory =
+                (PreferenceCategory) screen.findPreference(KEY_IPV6_ADDRESS_CATEGORY);
+
+        mSecurityPref.setDetailText(mAccessPoint.getSecurityString(false /* concise */));
+    }
+
+    public WifiInfo getWifiInfo() {
+        return mWifiInfo;
+    }
+
+    @Override
+    public void onResume() {
+        mWifiInfo = mWifiManager.getConnectionInfo();
+        mWifiConfig = mWifiManager.getWifiApConfiguration();
+
+        refreshFromWifiInfo();
+        setIpText();
+    }
+
+    private void refreshFromWifiInfo() {
+        if (mWifiInfo == null) {
+            return;
+        }
+        mAccessPoint.update(mWifiConfig, mWifiInfo, mNetworkInfo);
+
+        int iconSignalLevel = WifiManager.calculateSignalLevel(
+                mWifiInfo.getRssi(), WifiManager.RSSI_LEVELS);
+        Drawable wifiIcon = NetworkBadging.getWifiIcon(
+                iconSignalLevel, NetworkBadging.BADGING_NONE, mContext.getTheme()).mutate();
+
+        // Connected Header Pref
+        mConnectionDetailPref.setIcon(wifiIcon);
+        mConnectionDetailPref.setTitle(mAccessPoint.getSettingsSummary());
+
+        // Signal Strength Pref
+        Drawable wifiIconDark = wifiIcon.getConstantState().newDrawable().mutate();
+        wifiIconDark.setTint(mContext.getResources().getColor(
+                R.color.wifi_details_icon_color, mContext.getTheme()));
+        mSignalStrengthPref.setIcon(wifiIconDark);
+
+        int summarySignalLevel = WifiManager.calculateSignalLevel(mRssi, mSignalStr.length);
+        mSignalStrengthPref.setDetailText(mSignalStr[summarySignalLevel]);
+
+        // Frequency Pref
+        final int frequency = mWifiInfo.getFrequency();
+        String band = null;
+        if (frequency >= AccessPoint.LOWER_FREQ_24GHZ
+                && frequency < AccessPoint.HIGHER_FREQ_24GHZ) {
+            band = mContext.getResources().getString(R.string.wifi_band_24ghz);
+        } else if (frequency >= AccessPoint.LOWER_FREQ_5GHZ
+                && frequency < AccessPoint.HIGHER_FREQ_5GHZ) {
+            band = mContext.getResources().getString(R.string.wifi_band_5ghz);
+        } else {
+            Log.e(TAG, "Unexpected frequency " + frequency);
+        }
+        mFrequencyPref.setDetailText(band);
+    }
+
+    private void setIpText() {
+        mIpv6AddressCategory.removeAll();
+        mIpv6AddressCategory.setVisible(false);
+
+        Network currentNetwork = mWifiManager.getCurrentNetwork();
+        if (currentNetwork == null) {
+            return;
+        }
+
+        ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        LinkProperties prop = cm.getLinkProperties(currentNetwork);
+        List<InetAddress> addresses = prop.getAllAddresses();
+
+        // Set ip addresses
+        for (int i = 0; i < addresses.size(); i++) {
+            InetAddress addr = addresses.get(i);
+            if (addr instanceof Inet4Address) {
+                mIpAddressPref.setDetailText(addr.getHostAddress());
+            } else if (addr instanceof Inet6Address) {
+                String ip = addr.getHostAddress();
+                Preference pref = new Preference(mPrefContext);
+                pref.setKey(ip);
+                pref.setTitle(ip);
+                mIpv6AddressCategory.addPreference(pref);
+                mIpv6AddressCategory.setVisible(true); // TODO(sghuman): Make sure to
+            }
+        }
+
+        String subnetMask = null;
+        String router;
+        DhcpInfo dhcp = mWifiManager.getDhcpInfo();
+        if (dhcp != null) {
+            if (dhcp.netmask == 0) {
+                Log.e(TAG, "invalid netmask value of 0 for DhcpInfo: " + dhcp);
+                mSubnetPref.setVisible(false);
+            } else {
+                subnetMask = NetworkUtils.intToInetAddress(dhcp.netmask).getHostAddress();
+                mSubnetPref.setVisible(true);
+            }
+
+            router = NetworkUtils.intToInetAddress(dhcp.gateway).getHostAddress();
+        } else { // Statically configured IP
+
+            // TODO(sghuman): How do we get subnet mask for static ips?
+            mSubnetPref.setVisible(false);
+
+            router = mWifiManager.getWifiApConfiguration().getStaticIpConfiguration().gateway
+                    .getHostAddress();
+        }
+        mRouterPref.setDetailText(router);
+        mSubnetPref.setDetailText(subnetMask);
+
+        // Set DNS
+        addresses = prop.getDnsServers();
+        StringBuilder builder = new StringBuilder();
+
+        // addresses is backed by an ArrayList, so use a hand-written iterator for performance gains
+        for (int i = 0; i < addresses.size(); i++) {
+            if (i > 0) builder.append(", ");
+            builder.append(addresses.get(i).getHostAddress());
+        }
+        mDnsPref.setDetailText(builder.toString());
+    }
+}
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
new file mode 100644
index 0000000..0a80f21
--- /dev/null
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -0,0 +1,113 @@
+/*
+ * 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 android.content.Context;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.widget.Button;
+
+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;
+import com.android.settingslib.wifi.AccessPoint;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Detail page for the currently connected wifi network.
+ *
+ * <p>The AccessPoint should be saved to the intent Extras when launching this class via
+ * {@link AccessPoint#saveWifiState(Bundle)} in order to properly render this page.
+ */
+public class WifiNetworkDetailsFragment extends DashboardFragment {
+    private static final String TAG = "WifiNetworkDetailsFrg";
+
+    // XML KEYS
+    private static final String KEY_FORGET_BUTTON = "forget_button";
+
+    private AccessPoint mAccessPoint;
+    private Button mForgetButton;
+    private WifiDetailPreferenceController mWifiDetailPreferenceController;
+    private WifiManager mWifiManager;
+
+    @Override
+    public void onAttach(Context context) {
+        mAccessPoint = new AccessPoint(context, getArguments());
+        mWifiManager = context.getSystemService(WifiManager.class);
+
+        super.onAttach(context);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Header Title set automatically from launching Preference
+
+        mForgetButton = (Button) ((LayoutPreference) findPreference(KEY_FORGET_BUTTON))
+                .findViewById(R.id.button);
+        mForgetButton.setText(R.string.forget);
+        mForgetButton.setOnClickListener(view -> forgetNetwork());
+    }
+
+    private void forgetNetwork() {
+        WifiInfo info = mWifiDetailPreferenceController.getWifiInfo();
+        mMetricsFeatureProvider.action(getActivity(), MetricsProto.MetricsEvent.ACTION_WIFI_FORGET);
+        if (!info.isEphemeral()) {
+                // Network is active but has no network ID - must be ephemeral.
+                mWifiManager.disableEphemeralNetwork(
+                        AccessPoint.convertToQuotedString(info.getSSID()));
+        } else if (mAccessPoint.getConfig().isPasspoint()) {
+            mWifiManager.removePasspointConfiguration(mAccessPoint.getConfig().FQDN);
+        } else {
+            mWifiManager.forget(info.getNetworkId(), null /* action listener */);
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.WIFI_NETWORK_DETAILS;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.wifi_network_details_fragment;
+    }
+
+    @Override
+    protected List<PreferenceController> getPreferenceControllers(Context context) {
+        mWifiDetailPreferenceController = new WifiDetailPreferenceController(
+                mAccessPoint,
+                context,
+                getLifecycle(),
+                mWifiManager);
+
+        ArrayList<PreferenceController> controllers = new ArrayList(1);
+        controllers.add(mWifiDetailPreferenceController);
+        return controllers;
+    }
+}
diff --git a/tests/app/src/com/android/settings/fingerprint/FingerprintEnrollFinishTest.java b/tests/app/src/com/android/settings/fingerprint/FingerprintEnrollFinishTest.java
new file mode 100644
index 0000000..b09d1bf
--- /dev/null
+++ b/tests/app/src/com/android/settings/fingerprint/FingerprintEnrollFinishTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.fingerprint;
+
+import static android.support.test.InstrumentationRegistry.getTargetContext;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.intent.Intents.intended;
+import static android.support.test.espresso.intent.Intents.intending;
+import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation.ActivityResult;
+import android.content.ComponentName;
+import android.support.test.espresso.intent.rule.IntentsTestRule;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.settings.R;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class FingerprintEnrollFinishTest {
+
+    @Rule
+    public IntentsTestRule<FingerprintEnrollFinish> mActivityRule =
+            new IntentsTestRule<>(FingerprintEnrollFinish.class);
+
+    @Test
+    public void clickAddAnother_shouldLaunchEnrolling() {
+        final ComponentName enrollingComponent = new ComponentName(
+                getTargetContext(),
+                FingerprintEnrollEnrolling.class);
+
+        intending(hasComponent(enrollingComponent))
+                .respondWith(new ActivityResult(Activity.RESULT_CANCELED, null));
+
+        onView(withId(R.id.add_another_button)).perform(click());
+
+        intended(hasComponent(enrollingComponent));
+        assertFalse(mActivityRule.getActivity().isFinishing());
+    }
+
+    @Test
+    public void clickAddAnother_shouldPropagateResults() {
+        final ComponentName enrollingComponent = new ComponentName(
+                getTargetContext(),
+                FingerprintEnrollEnrolling.class);
+
+        intending(hasComponent(enrollingComponent))
+                .respondWith(new ActivityResult(Activity.RESULT_OK, null));
+
+        onView(withId(R.id.add_another_button)).perform(click());
+
+        intended(hasComponent(enrollingComponent));
+        assertTrue(mActivityRule.getActivity().isFinishing());
+    }
+
+    @Test
+    public void clickNext_shouldFinish() {
+        onView(withId(R.id.next_button)).perform(click());
+        assertTrue(mActivityRule.getActivity().isFinishing());
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index a63bd7f..778440d 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -5,3 +5,4 @@
 com.android.settings.accounts.AccountDetailDashboardFragment
 com.android.settings.fuelgauge.PowerUsageDetail
 com.android.settings.deviceinfo.StorageProfileFragment
+com.android.settings.wifi.details.WifiNetworkDetailsFragment
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
index b1144f0..7f0229a 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java
@@ -27,6 +27,9 @@
 import com.android.settings.TestConfig;
 import com.android.settings.core.instrumentation.MetricsFeatureProvider;
 import com.android.settings.dashboard.conditional.Condition;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.Tile;
 import org.junit.Before;
@@ -52,7 +55,13 @@
 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 = {
+                SettingsShadowResources.class,
+                SettingsShadowResources.SettingsShadowTheme.class,
+                ShadowDynamicIndexableContentMonitor.class
+        })
 public class DashboardAdapterTest {
 
     @Mock
@@ -82,6 +91,7 @@
         when(mResources
                 .getQuantityString(any(int.class), any(int.class), Matchers.<Object>anyVararg()))
                 .thenReturn("");
+        FakeFeatureFactory.setupForTest(context);
         mDashboardAdapter = new DashboardAdapter(context, null, mMetricsFeatureProvider,
                 null, null);
         mSuggestionHeaderData = new DashboardData.SuggestionHeaderData(true, 1, 0);
diff --git a/tests/robotests/src/com/android/settings/search/InlineSwitchViewHolderTest.java b/tests/robotests/src/com/android/settings/search/InlineSwitchViewHolderTest.java
index b8fe3fc..ba9feb3 100644
--- a/tests/robotests/src/com/android/settings/search/InlineSwitchViewHolderTest.java
+++ b/tests/robotests/src/com/android/settings/search/InlineSwitchViewHolderTest.java
@@ -19,9 +19,10 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
+import android.util.Pair;
 import android.view.LayoutInflater;
-import android.view.View;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
@@ -29,19 +30,24 @@
 import com.android.settings.search2.InlineSwitchViewHolder;
 import com.android.settings.search2.SearchFragment;
 import com.android.settings.search2.SearchResult;
+import com.android.settings.testutils.FakeFeatureFactory;
 
 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;
-import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
 
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @RunWith(SettingsRobolectricTestRunner.class)
@@ -51,22 +57,31 @@
     private static final String TITLE = "title";
     private static final String SUMMARY = "summary";
 
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
     @Mock
     private SearchFragment mFragment;
 
     @Mock
     private InlineSwitchPayload mPayload;
+
+    private FakeFeatureFactory mFeatureFactory;
     private InlineSwitchViewHolder mHolder;
     private Drawable mIcon;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        final Context context = ShadowApplication.getInstance().getApplicationContext();
-        View view = LayoutInflater.from(context).inflate(R.layout.search_inline_switch_item, null);
-        mHolder = new InlineSwitchViewHolder(view, context);
-
+        final Context context = RuntimeEnvironment.application;
         mIcon = context.getDrawable(R.drawable.ic_search_history);
+        FakeFeatureFactory.setupForTest(mContext);
+        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+
+        mHolder = new InlineSwitchViewHolder(
+                LayoutInflater.from(context).inflate(R.layout.search_inline_switch_item, null),
+                context);
+        ReflectionHelpers.setField(mHolder, "mMetricsFeatureProvider",
+                mFeatureFactory.metricsFeatureProvider);
     }
 
     @Test
@@ -82,12 +97,19 @@
         when(mPayload.getSwitchValue(any(Context.class))).thenReturn(true);
         SearchResult result = getSearchResult();
         mHolder.onBind(mFragment, result);
-        mHolder.switchView.setChecked(true);
+        // Precondition: switch is on.
+        assertThat(mHolder.switchView.isChecked()).isTrue();
 
+        mHolder.switchView.performClick();
+
+        verify(mFeatureFactory.metricsFeatureProvider).action(
+                any(Context.class),
+                eq(MetricsProto.MetricsEvent.ACTION_CLICK_SETTINGS_SEARCH_INLINE_RESULT),
+                any(Pair.class), any(Pair.class), any(Pair.class));
         assertThat(mHolder.titleView.getText()).isEqualTo(TITLE);
         assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY);
         assertThat(mHolder.iconView.getDrawable()).isEqualTo(mIcon);
-        assertThat(mHolder.switchView.isChecked()).isTrue();
+        assertThat(mHolder.switchView.isChecked()).isFalse();
     }
 
     private SearchResult getSearchResult() {
diff --git a/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java b/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java
index 6100050..647d68c 100644
--- a/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java
@@ -21,9 +21,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
-
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
+
 import com.android.settings.R;
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
@@ -34,13 +34,12 @@
 import com.android.settings.search2.IntentPayload;
 import com.android.settings.search2.IntentSearchViewHolder;
 import com.android.settings.search2.ResultPayload;
-import com.android.settings.search2.SearchActivity;
 import com.android.settings.search2.SearchFragment;
 import com.android.settings.search2.SearchResult;
 import com.android.settings.search2.SearchResult.Builder;
 import com.android.settings.search2.SearchResultsAdapter;
-
 import com.android.settings.search2.SearchViewHolder;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -48,15 +47,11 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowApplication;
-import org.robolectric.shadows.ShadowViewGroup;
-import org.robolectric.util.ActivityController;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.doReturn;
 
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
@@ -85,15 +80,15 @@
     @Test
     public void testSingleSourceMerge_ExactCopyReturned() {
         ArrayList<SearchResult> intentResults = getIntentSampleResults();
-        mAdapter.addResultsToMap(intentResults, mLoaderClassName);
-        mAdapter.mergeResults();
+        mAdapter.addSearchResults(intentResults, mLoaderClassName);
+        mAdapter.displaySearchResults();
 
         List<SearchResult> updatedResults = mAdapter.getSearchResults();
         assertThat(updatedResults).containsAllIn(intentResults);
     }
 
     @Test
-    public void testCreatViewHolder_ReturnsIntentResult() {
+    public void testCreateViewHolder_ReturnsIntentResult() {
         ViewGroup group = new FrameLayout(mContext);
         SearchViewHolder view = mAdapter.onCreateViewHolder(group,
                 ResultPayload.PayloadType.INTENT);
@@ -101,7 +96,7 @@
     }
 
     @Test
-    public void testCreatViewHolder_ReturnsInlineSwitchResult() {
+    public void testCreateViewHolder_ReturnsInlineSwitchResult() {
         ViewGroup group = new FrameLayout(mContext);
         SearchViewHolder view = mAdapter.onCreateViewHolder(group,
                 ResultPayload.PayloadType.INLINE_SWITCH);
@@ -110,11 +105,11 @@
 
     @Test
     public void testEndToEndSearch_ProperResultsMerged() {
-        mAdapter.addResultsToMap(getDummyAppResults(),
+        mAdapter.addSearchResults(getDummyAppResults(),
                 InstalledAppResultLoader.class.getName());
-        mAdapter.addResultsToMap(getDummyDbResults(),
+        mAdapter.addSearchResults(getDummyDbResults(),
                 DatabaseResultLoader.class.getName());
-        int count = mAdapter.mergeResults();
+        int count = mAdapter.displaySearchResults();
 
         List<SearchResult> results = mAdapter.getSearchResults();
         assertThat(results.get(0).title).isEqualTo("alpha");
diff --git a/tests/robotests/src/com/android/settings/search2/SavedQueryRecorderTest.java b/tests/robotests/src/com/android/settings/search2/SavedQueryRecorderAndRemoverTest.java
similarity index 77%
rename from tests/robotests/src/com/android/settings/search2/SavedQueryRecorderTest.java
rename to tests/robotests/src/com/android/settings/search2/SavedQueryRecorderAndRemoverTest.java
index 5374aae..ae78279 100644
--- a/tests/robotests/src/com/android/settings/search2/SavedQueryRecorderTest.java
+++ b/tests/robotests/src/com/android/settings/search2/SavedQueryRecorderAndRemoverTest.java
@@ -36,10 +36,11 @@
 
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class SavedQueryRecorderTest {
+public class SavedQueryRecorderAndRemoverTest {
 
     private Context mContext;
     private SavedQueryRecorder mRecorder;
+    private SavedQueryRemover mRemover;
 
     @Before
     public void setUp() {
@@ -52,16 +53,25 @@
     }
 
     @Test
-    public void canSaveQueryToDb() {
+    public void canSaveAndRemoveQuery() {
         final String query = "test";
         mRecorder = new SavedQueryRecorder(mContext, query);
+        mRemover = new SavedQueryRemover(mContext, query);
 
+        // Record a new query and load all queries from DB
         mRecorder.loadInBackground();
-
         final SavedQueryLoader loader = new SavedQueryLoader(mContext);
         List<? extends SearchResult> results = loader.loadInBackground();
 
+        // Should contain the newly recorded query
         assertThat(results.size()).isEqualTo(1);
         assertThat(results.get(0).title).isEqualTo(query);
+
+        // Remove the query and load all queries from DB
+        mRemover.loadInBackground();
+        results = loader.loadInBackground();
+
+        // Saved query list should be empty because it's removed.
+        assertThat(results).isEmpty();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/search2/SavedQueryViewHolderTest.java b/tests/robotests/src/com/android/settings/search2/SavedQueryViewHolderTest.java
new file mode 100644
index 0000000..5777609
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/search2/SavedQueryViewHolderTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SavedQueryViewHolderTest {
+
+    @Mock
+    private SearchFragment mSearchFragment;
+    private Context mContext;
+    private SavedQueryViewHolder mHolder;
+    private View mView;
+    private View mTitleView;
+    private View mRemoveButton;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mView = LayoutInflater.from(mContext)
+                .inflate(R.layout.search_saved_query_item, null);
+        mTitleView = mView.findViewById(android.R.id.title);
+        mRemoveButton = mView.findViewById(android.R.id.icon);
+        mHolder = new SavedQueryViewHolder(mView);
+    }
+
+    @Test
+    public void onBind_shouldBindClickCallback() {
+        final SearchResult result = mock(SearchResult.class);
+        mHolder.onBind(mSearchFragment, result);
+
+        mTitleView.performClick();
+        mRemoveButton.performClick();
+
+        verify(mSearchFragment).onSavedQueryClicked(any(CharSequence.class));
+        verify(mSearchFragment).onRemoveSavedQueryClicked(any(CharSequence.class));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java b/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java
index 6a61f52..3e22d56 100644
--- a/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java
@@ -17,12 +17,11 @@
 package com.android.settings.search2;
 
 import android.app.LoaderManager;
-
 import android.content.Context;
 import android.content.Loader;
 import android.os.Bundle;
-
 import android.view.View;
+
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.SettingsRobolectricTestRunner;
@@ -39,10 +38,12 @@
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.util.ActivityController;
+import org.robolectric.util.ReflectionHelpers;
 
 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;
@@ -186,20 +187,23 @@
         ActivityController<SearchActivity> activityController =
                 Robolectric.buildActivity(SearchActivity.class);
         activityController.setup();
-        SearchFragment fragment = (SearchFragment) activityController.get().getFragmentManager()
-                .findFragmentById(R.id.main_content);
 
-        fragment.onQueryTextChange("");
-        activityController.get().onBackPressed();
-        activityController.pause().stop().destroy();
+        SearchFragment fragment = spy((SearchFragment) activityController.get().getFragmentManager()
+                .findFragmentById(R.id.main_content));
+
+        final SearchResultsAdapter adapter = mock(SearchResultsAdapter.class);
+        ReflectionHelpers.setField(fragment, "mSearchAdapter", adapter);
 
         verify(mFeatureFactory.searchFeatureProvider, never())
                 .getDatabaseSearchLoader(any(Context.class), anyString());
         verify(mFeatureFactory.searchFeatureProvider, never())
                 .getInstalledAppSearchLoader(any(Context.class), anyString());
-        // Saved query loaded 2 times: fragment start, and query change to empty.
-        verify(mFeatureFactory.searchFeatureProvider, times(2))
+        verify(mFeatureFactory.searchFeatureProvider)
                 .getSavedQueryLoader(any(Context.class));
+
+        fragment.onLoadFinished(mSavedQueryLoader, null /* data */);
+
+        verify(adapter).displaySavedQuery(anyList());
     }
 
     @Test
@@ -225,7 +229,6 @@
 
     @Test
     public void syncLoaders_MergeWhenAllLoadersDone() {
-
         when(mFeatureFactory.searchFeatureProvider
                 .getDatabaseSearchLoader(any(Context.class), anyString()))
                 .thenReturn(new MockDBLoader(RuntimeEnvironment.application));
@@ -236,6 +239,7 @@
         ActivityController<SearchActivity> activityController =
                 Robolectric.buildActivity(SearchActivity.class);
         activityController.setup();
+
         SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager()
                 .findFragmentById(R.id.main_content));
 
@@ -272,7 +276,6 @@
 
     @Test
     public void onLoadFinished_ShowsFeedback() {
-
         when(mFeatureFactory.searchFeatureProvider
                 .getDatabaseSearchLoader(any(Context.class), anyString()))
                 .thenReturn(new MockDBLoader(RuntimeEnvironment.application));
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java b/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java
index 113c7aa..e87e9c5 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java
@@ -66,6 +66,8 @@
             id = R.drawable.ic_settings_wireless;
         } else if (id == R.drawable.app_filter_spinner_background) {
             id = R.drawable.ic_expand_more_inverse;
+        } else if (id == R.drawable.selectable_card_grey) {
+            id = R.drawable.ic_expand_more_inverse;
         }
         return super.loadDrawable(value, id, theme);
     }