Merge "Updating call to set icon on task description"
diff --git a/Android.bp b/Android.bp
index cc273fb..4112d04 100644
--- a/Android.bp
+++ b/Android.bp
@@ -54,6 +54,8 @@
         "settings-logtags",
         "statslog-settings",
         "zxing-core-1.7",
+        "android.hardware.dumpstate-V1.0-java",
+        "android.hardware.dumpstate-V1.1-java",
     ],
 
     libs: [
diff --git a/res/layout-land/confirm_lock_password.xml b/res/layout-land/confirm_lock_password.xml
index 3d2589c..cad1bfc 100644
--- a/res/layout-land/confirm_lock_password.xml
+++ b/res/layout-land/confirm_lock_password.xml
@@ -62,7 +62,8 @@
                 android:layout_height="wrap_content"
                 android:layout_marginStart="?attr/sudMarginSides"
                 android:layout_marginEnd="?attr/sudMarginSides"
-                android:layout_gravity="center" />
+                android:layout_gravity="center"
+                android:visibility="gone" />
         </LinearLayout>
 
         <Space
diff --git a/res/layout-land/confirm_lock_pattern.xml b/res/layout-land/confirm_lock_pattern.xml
index 55e1ef2..861c00a 100644
--- a/res/layout-land/confirm_lock_pattern.xml
+++ b/res/layout-land/confirm_lock_pattern.xml
@@ -59,7 +59,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginStart="?attr/sudMarginSides"
-                    android:layout_marginEnd="?attr/sudMarginSides" />x
+                    android:layout_marginEnd="?attr/sudMarginSides" />
 
                 <Button
                     android:id="@+id/cancelButton"
@@ -77,7 +77,8 @@
                     android:layout_height="wrap_content"
                     android:layout_marginStart="?attr/sudMarginSides"
                     android:layout_marginEnd="?attr/sudMarginSides"
-                    android:layout_gravity="center" />
+                    android:layout_gravity="center"
+                    android:visibility="gone" />
 
                 <Space
                     android:layout_width="match_parent"
diff --git a/res/layout/adb_qrcode_scanner_fragment.xml b/res/layout/adb_qrcode_scanner_fragment.xml
new file mode 100644
index 0000000..975256d
--- /dev/null
+++ b/res/layout/adb_qrcode_scanner_fragment.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.google.android.setupdesign.GlifLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:theme="@style/GlifV3Theme.Light"
+    android:icon="@drawable/ic_scan_32dp">
+
+    <LinearLayout
+        style="@style/SudContentFrame"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:gravity="center_horizontal">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical"
+            android:gravity="center_horizontal"
+            android:id="@+id/camera_layout">
+
+            <TextView
+                android:id="@android:id/summary"
+                style="@style/TextAppearance.SudGlifBody"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="?attr/sudMarginSides"
+                android:layout_marginEnd="?attr/sudMarginSides"
+                android:textAlignment="center"
+                android:accessibilityLiveRegion="polite"/>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:gravity="center"
+                android:orientation="vertical">
+
+                <FrameLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:clipChildren="true">
+                    <TextureView
+                        android:id="@+id/preview_view"
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/qrcode_preview_size"/>
+                    <com.android.settings.wifi.qrcode.QrDecorateView
+                        android:id="@+id/decorate_view"
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/qrcode_preview_size"/>
+                </FrameLayout>
+
+                <TextView
+                    android:id="@+id/error_message"
+                    style="@style/TextAppearance.ErrorText"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="16dp"
+                    android:layout_marginStart="?attr/sudMarginSides"
+                    android:layout_marginEnd="?attr/sudMarginSides"
+                    android:textAlignment="center"
+                    android:visibility="invisible"/>
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <!--
+             The spinner indicating that the device is waiting for pairing
+             after getting valid QR code
+        -->
+        <LinearLayout
+            android:id="@+id/verifying_layout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:visibility="gone">
+
+            <ProgressBar
+                android:id="@+id/verifying_progress"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                style="@style/adb_wireless_item_progress_text"
+                android:text="@string/adb_wireless_verifying_qrcode_text"/>
+
+        </LinearLayout>
+
+    </LinearLayout>
+</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout/adb_wireless_dialog.xml b/res/layout/adb_wireless_dialog.xml
new file mode 100644
index 0000000..31f94c9
--- /dev/null
+++ b/res/layout/adb_wireless_dialog.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/dialog_scrollview"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:fadeScrollbars="false"
+        android:scrollIndicators="top|bottom">
+
+    <LinearLayout
+            android:id="@+id/l_adbwirelessdialog"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingBottom="8dip">
+
+        <LinearLayout android:id="@+id/l_pairing_six_digit"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="@style/adb_wireless_section"
+                android:visibility="gone">
+
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    style="@style/adb_wireless_item" >
+                <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        style="@style/adb_wireless_item_label"
+                        android:text="@string/adb_pairing_device_dialog_pairing_code_label"
+                        android:textDirection="locale" />
+
+                <TextView
+                    android:id="@+id/pairing_code"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    style="@style/adb_wireless_item_content" />
+
+                <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        style="@style/adb_wireless_item_label"
+                        android:text="@string/adb_wireless_ip_addr_preference_title"
+                        android:textDirection="locale"
+                        android:paddingTop="8dip"/>
+
+                <TextView
+                        android:id="@+id/ip_addr"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        style="@style/adb_wireless_item_label"
+                        android:text="@string/summary_placeholder"
+                        android:textDirection="locale" />
+            </LinearLayout>
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/l_pairing_failed"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="@style/adb_wireless_section"
+                android:visibility="gone">
+
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    style="@style/adb_wireless_item" >
+                <TextView
+                        android:id="@+id/pairing_failed_label"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        style="@style/adb_wireless_item_label"
+                        android:textDirection="locale" />
+            </LinearLayout>
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/l_qrcode_pairing_failed"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="@style/adb_wireless_section"
+                android:visibility="gone">
+
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    style="@style/adb_wireless_item" >
+                <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        style="@style/adb_wireless_item_label"
+                        android:textDirection="locale"
+                        android:text="@string/adb_qrcode_pairing_device_failed_msg"/>
+            </LinearLayout>
+        </LinearLayout>
+
+    </LinearLayout>
+</ScrollView>
+
diff --git a/res/layout/confirm_lock_password_base.xml b/res/layout/confirm_lock_password_base.xml
index 9dff190..a0935bf 100644
--- a/res/layout/confirm_lock_password_base.xml
+++ b/res/layout/confirm_lock_password_base.xml
@@ -61,7 +61,8 @@
                 android:layout_height="wrap_content"
                 android:layout_marginStart="?attr/sudMarginSides"
                 android:layout_marginEnd="?attr/sudMarginSides"
-                android:layout_gravity="center" />
+                android:layout_gravity="center"
+                android:visibility="gone" />
         </LinearLayout>
 
         <Space
diff --git a/res/layout/confirm_lock_pattern_base.xml b/res/layout/confirm_lock_pattern_base.xml
index 7bb4d01..9a37eaa 100644
--- a/res/layout/confirm_lock_pattern_base.xml
+++ b/res/layout/confirm_lock_pattern_base.xml
@@ -72,7 +72,8 @@
                 android:layout_height="wrap_content"
                 android:layout_marginStart="?attr/sudMarginSides"
                 android:layout_marginEnd="?attr/sudMarginSides"
-                android:layout_gravity="center" />
+                android:layout_gravity="center"
+                android:visibility="gone" />
 
         </LinearLayout>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 30eb00c..aa37f06 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10990,8 +10990,8 @@
     <string name="graphics_driver_app_preference_default">Default</string>
     <!-- The game driver value for Game Driver app preference [CHAR LIMIT=50] -->
     <string name="graphics_driver_app_preference_game_driver">Game Driver</string>
-    <!-- The prerelase driver value for Prerelease Driver app preference [CHAR LIMIT=50] -->
-    <string name="graphics_driver_app_preference_prerelease_driver">Prerelease Driver</string>
+    <!-- The prerelase driver value for Developer Driver app preference [CHAR LIMIT=50] -->
+    <string name="graphics_driver_app_preference_prerelease_driver">Developer Driver</string>
     <!-- The system driver value for system graphics driver app preference [CHAR LIMIT=50] -->
     <string name="graphics_driver_app_preference_system">System Graphics Driver</string>
     <!-- All the graphics driver preference values for all apps globally [CHAR LIMIT=50] -->
@@ -11002,6 +11002,7 @@
     <!-- All the values of graphics driver for app preference [CHAR LIMIT=50] -->
     <string-array name="graphics_driver_app_preference_values">
         <item>@string/graphics_driver_app_preference_default</item>
+        <item>@string/graphics_driver_app_preference_prerelease_driver</item>
         <item>@string/graphics_driver_app_preference_game_driver</item>
         <item>@string/graphics_driver_app_preference_system</item>
     </string-array>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index c42fab2..85b25e4 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -153,6 +153,44 @@
         <item name="android:orientation">vertical</item>
     </style>
 
+    <style name="adb_wireless_item">
+        <item name="android:layout_marginTop">8dp</item>
+        <item name="android:layout_marginStart">8dp</item>
+        <item name="android:layout_marginEnd">8dp</item>
+        <item name="android:paddingStart">8dp</item>
+        <item name="android:paddingEnd">8dp</item>
+        <item name="android:orientation">vertical</item>
+        <item name="android:gravity">start</item>
+    </style>
+
+    <style name="adb_wireless_item_label">
+        <item name="android:paddingStart">8dp</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:textAlignment">viewStart</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.Material.Body1</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+
+    <style name="adb_wireless_item_content">
+        <item name="android:paddingStart">8dp</item>
+        <item name="android:textSize">24sp</item>
+        <item name="android:textAlignment">viewStart</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.Material.Body1</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+    <style name="adb_wireless_item_progress_text">
+        <item name="android:paddingTop">16dp</item>
+        <item name="android:textSize">18sp</item>
+        <item name="android:textAlignment">viewStart</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.Material.Body1</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+    <style name="adb_wireless_section">
+        <item name="android:orientation">vertical</item>
+    </style>
+
     <style name="ConfirmDeviceCredentialsAnimationStyle"
            parent="@*android:style/Animation.Material.Activity">
         <item name="android:activityOpenEnterAnimation">@anim/confirm_credential_open_enter</item>
diff --git a/res/xml/adb_device_details_fragment.xml b/res/xml/adb_device_details_fragment.xml
new file mode 100644
index 0000000..2e149ed
--- /dev/null
+++ b/res/xml/adb_device_details_fragment.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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-auto"
+    android:title="@string/device_details_title"
+    settings:initialExpandedChildrenCount="3">
+
+    <com.android.settingslib.widget.LayoutPreference
+        android:key="adb_device_header"
+        android:layout="@layout/settings_entity_header"
+        android:selectable="false" />
+
+    <!-- Buttons -->
+    <com.android.settingslib.widget.ActionButtonsPreference
+        android:key="buttons"
+        android:selectable="false" />
+
+    <!-- Device Fingerprint Details -->
+    <PreferenceCategory
+            android:key="fingerprint_category"
+            android:layout="@layout/preference_category_no_label">
+    </PreferenceCategory>
+</PreferenceScreen>
+
diff --git a/res/xml/adb_wireless_settings.xml b/res/xml/adb_wireless_settings.xml
new file mode 100644
index 0000000..7f60c69
--- /dev/null
+++ b/res/xml/adb_wireless_settings.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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-auto"
+        android:title="@string/adb_wireless_settings">
+
+    <PreferenceCategory
+        android:layout="@layout/preference_category_no_label">
+        <!-- ADB device name -->
+        <Preference
+            android:key="adb_device_name_pref"
+            android:title="@string/my_device_info_device_name_preference_title"
+            android:summary="@string/summary_placeholder"
+            android:selectable="false"
+            settings:controller="com.android.settings.development.AdbDeviceNamePreferenceController"
+            settings:enableCopying="true"/>
+
+        <!-- IP address & port -->
+        <Preference
+            android:key="adb_ip_addr_pref"
+            android:title="@string/adb_wireless_ip_addr_preference_title"
+            android:summary="@string/summary_placeholder"
+            android:selectable="false"/>
+    </PreferenceCategory>
+
+    <!-- Pairing methods category -->
+    <PreferenceCategory
+        android:key="adb_pairing_methods_category"
+        android:layout="@layout/preference_category_no_label">
+        <!-- qrcode scanner -->
+        <Preference
+            android:key="adb_pair_method_qrcode_pref"
+            android:icon="@drawable/ic_scan_24dp"
+            android:title="@string/adb_pair_method_qrcode_title"
+            android:summary="@string/adb_pair_method_qrcode_summary"/>
+        <Preference
+            android:key="adb_pair_method_code_pref"
+            android:title="@string/adb_pair_method_code_title"
+            android:summary="@string/adb_pair_method_code_summary"/>
+    </PreferenceCategory>
+
+    <!-- Paired devices list -->
+    <PreferenceCategory
+        android:key="adb_paired_devices_category"
+        android:title="@string/adb_paired_devices_title"/>
+
+    <!-- Off message: Shown only in the off state -->
+    <PreferenceCategory
+        android:key="adb_wireless_footer_category"
+        android:layout="@layout/preference_category_no_label"
+        settings:allowDividerAbove="false"/>
+
+</PreferenceScreen>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 940cb59..834fb48 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -141,6 +141,13 @@
         <Preference android:key="clear_adb_keys"
                     android:title="@string/clear_adb_keys" />
 
+        <com.android.settings.widget.MasterSwitchPreference
+            android:fragment="com.android.settings.development.WirelessDebuggingFragment"
+            android:key="toggle_adb_wireless"
+            android:title="@string/enable_adb_wireless"
+            android:summary="@string/enable_adb_wireless_summary"
+            settings:keywords="@string/keywords_adb_wireless" />
+
         <SwitchPreference
             android:key="enable_terminal"
             android:title="@string/enable_terminal_title"
@@ -152,6 +159,11 @@
             android:summary="@string/bugreport_in_power_summary" />
 
         <SwitchPreference
+            android:key="enable_verbose_vendor_logging"
+            android:title="@string/enable_verbose_vendor_logging"
+            android:summary="@string/enable_verbose_vendor_logging_summary" />
+
+        <SwitchPreference
             android:key="automatic_system_server_heap_dumps"
             android:title="@string/automatic_system_heap_dump_title"
             android:summary="@string/automatic_system_heap_dump_summary" />
@@ -264,6 +276,11 @@
             android:summary="@string/mobile_data_always_on_summary" />
 
         <SwitchPreference
+            android:key="enhanced_connectivity"
+            android:title="@string/enhanced_connectivity"
+            android:summary="@string/enhanced_connectivity_summary" />
+
+        <SwitchPreference
             android:key="tethering_hardware_offload"
             android:title="@string/tethering_hardware_offload"
             android:summary="@string/tethering_hardware_offload_summary" />
diff --git a/src/com/android/settings/TestingSettingsBroadcastReceiver.java b/src/com/android/settings/TestingSettingsBroadcastReceiver.java
index aa28a18..0e1296b 100644
--- a/src/com/android/settings/TestingSettingsBroadcastReceiver.java
+++ b/src/com/android/settings/TestingSettingsBroadcastReceiver.java
@@ -1,10 +1,9 @@
 package com.android.settings;
 
-import static com.android.internal.telephony.TelephonyIntents.SECRET_CODE_ACTION;
-
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.telephony.TelephonyManager;
 
 import com.android.settings.Settings.TestingSettingsActivity;
 
@@ -16,7 +15,7 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (intent.getAction().equals(SECRET_CODE_ACTION)) {
+        if (intent.getAction().equals(TelephonyManager.ACTION_SECRET_CODE)) {
             Intent i = new Intent(Intent.ACTION_MAIN);
             i.setClass(context, TestingSettingsActivity.class);
             i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/src/com/android/settings/development/AdbDeviceDetailsActionController.java b/src/com/android/settings/development/AdbDeviceDetailsActionController.java
new file mode 100644
index 0000000..da4430d
--- /dev/null
+++ b/src/com/android/settings/development/AdbDeviceDetailsActionController.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.debug.PairDevice;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.fragment.app.Fragment;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.ActionButtonsPreference;
+
+/**
+ * Controller for logic pertaining to displaying adb device information for the
+ * {@link AdbDeviceDetailsFragment}.
+ */
+public class AdbDeviceDetailsActionController extends AbstractPreferenceController {
+    private static final String TAG = "AdbDeviceDetailsAction";
+
+    @VisibleForTesting
+    static final String KEY_BUTTONS_PREF = "buttons";
+
+    private PairDevice mPairedDevice;
+    private final Fragment mFragment;
+
+    private ActionButtonsPreference mButtonsPref;
+
+    public AdbDeviceDetailsActionController(
+            PairDevice pairedDevice,
+            Context context,
+            Fragment fragment) {
+        super(context);
+
+        mPairedDevice = pairedDevice;
+        mFragment = fragment;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_BUTTONS_PREF;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        mButtonsPref = ((ActionButtonsPreference) screen.findPreference(getPreferenceKey()))
+                .setButton1Visible(false)
+                .setButton2Icon(R.drawable.ic_settings_delete)
+                .setButton2Text(R.string.adb_device_forget)
+                .setButton2OnClickListener(view -> forgetDevice());
+    }
+
+    /**
+     * Forgets the device.
+     */
+    private void forgetDevice() {
+        Intent intent = new Intent();
+        intent.putExtra(
+                WirelessDebuggingFragment.PAIRED_DEVICE_REQUEST_TYPE,
+                WirelessDebuggingFragment.FORGET_ACTION);
+        intent.putExtra(
+                WirelessDebuggingFragment.PAIRED_DEVICE_EXTRA,
+                mPairedDevice);
+        mFragment.getActivity().setResult(Activity.RESULT_OK, intent);
+        mFragment.getActivity().finish();
+    }
+}
+
diff --git a/src/com/android/settings/development/AdbDeviceDetailsFingerprintController.java b/src/com/android/settings/development/AdbDeviceDetailsFingerprintController.java
new file mode 100644
index 0000000..b9c2d43
--- /dev/null
+++ b/src/com/android/settings/development/AdbDeviceDetailsFingerprintController.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.Context;
+import android.debug.PairDevice;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.fragment.app.Fragment;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.FooterPreference;
+
+/**
+ * Controller for logic pertaining to displaying adb device information for the
+ * {@link AdbDeviceDetailsFragment}.
+ */
+public class AdbDeviceDetailsFingerprintController extends AbstractPreferenceController {
+
+    private static final String TAG = "AdbDeviceDetailsFinger";
+
+    @VisibleForTesting
+    static final String KEY_FINGERPRINT_CATEGORY = "fingerprint_category";
+
+    private PairDevice mPairedDevice;
+    private final Fragment mFragment;
+
+    private PreferenceCategory mFingerprintCategory;
+    private FooterPreference mFingerprintPref;
+
+    public AdbDeviceDetailsFingerprintController(
+            PairDevice pairedDevice,
+            Context context,
+            Fragment fragment) {
+        super(context);
+
+        mPairedDevice = pairedDevice;
+        mFragment = fragment;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_FINGERPRINT_CATEGORY;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        mFingerprintCategory = (PreferenceCategory) screen.findPreference(getPreferenceKey());
+        mFingerprintPref = new FooterPreference(mFingerprintCategory.getContext());
+        final CharSequence titleFormat = mContext.getText(
+                R.string.adb_device_fingerprint_title_format);
+        mFingerprintPref.setTitle(String.format(
+                titleFormat.toString(), mPairedDevice.getGuid()));
+        mFingerprintCategory.addPreference(mFingerprintPref);
+    }
+}
+
diff --git a/src/com/android/settings/development/AdbDeviceDetailsFragment.java b/src/com/android/settings/development/AdbDeviceDetailsFragment.java
new file mode 100644
index 0000000..9861345
--- /dev/null
+++ b/src/com/android/settings/development/AdbDeviceDetailsFragment.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.debug.PairDevice;
+import android.os.Bundle;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Fragment shown when clicking on a paired device in the Wireless
+ * Debugging fragment.
+ */
+public class AdbDeviceDetailsFragment extends DashboardFragment {
+    private static final String TAG = "AdbDeviceDetailsFrag";
+    private PairDevice mPairedDevice;
+
+    public AdbDeviceDetailsFragment() {
+        super();
+    }
+
+    @Override
+    public void onAttach(Context context) {
+        // Get the paired device stored in the extras
+        Bundle bundle = getArguments();
+        if (bundle.containsKey(AdbPairedDevicePreference.PAIRED_DEVICE_EXTRA)) {
+            mPairedDevice = (PairDevice) bundle.getParcelable(
+                    AdbPairedDevicePreference.PAIRED_DEVICE_EXTRA);
+        }
+        super.onAttach(context);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.ADB_WIRELESS_DEVICE_DETAILS;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.adb_device_details_fragment;
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        final List<AbstractPreferenceController> controllers = new ArrayList<>();
+        controllers.add(new AdbDeviceDetailsHeaderController(mPairedDevice, context, this));
+        controllers.add(new AdbDeviceDetailsActionController(mPairedDevice, context, this));
+        controllers.add(new AdbDeviceDetailsFingerprintController(mPairedDevice, context, this));
+
+        return controllers;
+    }
+}
diff --git a/src/com/android/settings/development/AdbDeviceDetailsHeaderController.java b/src/com/android/settings/development/AdbDeviceDetailsHeaderController.java
new file mode 100644
index 0000000..a4e79ea
--- /dev/null
+++ b/src/com/android/settings/development/AdbDeviceDetailsHeaderController.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.Context;
+import android.debug.PairDevice;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.fragment.app.Fragment;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.widget.LayoutPreference;
+
+/**
+ * Controller for logic pertaining to displaying adb device information for the
+ * {@link AdbDeviceDetailsFragment}.
+ */
+public class AdbDeviceDetailsHeaderController extends AbstractPreferenceController
+        implements PreferenceControllerMixin, LifecycleObserver {
+
+    private static final String TAG = "AdbDeviceDetailsHeader";
+
+    @VisibleForTesting
+    static final String KEY_HEADER = "adb_device_header";
+
+    private PairDevice mPairedDevice;
+    private final Fragment mFragment;
+    private EntityHeaderController mEntityHeaderController;
+
+    public AdbDeviceDetailsHeaderController(
+            PairDevice pairedDevice,
+            Context context,
+            Fragment fragment) {
+        super(context);
+
+        mPairedDevice = pairedDevice;
+        mFragment = fragment;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_HEADER;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        setupEntityHeader(screen);
+    }
+
+    private void setupEntityHeader(PreferenceScreen screen) {
+        LayoutPreference headerPref = (LayoutPreference) screen.findPreference(KEY_HEADER);
+        mEntityHeaderController =
+                EntityHeaderController.newInstance(
+                        mFragment.getActivity(), mFragment,
+                        headerPref.findViewById(R.id.entity_header));
+
+        mEntityHeaderController
+                .setIcon(mContext.getDrawable(com.android.internal.R.drawable.ic_bt_laptop))
+                .setLabel(mPairedDevice.getDeviceName())
+                .done(mFragment.getActivity(), true);
+    }
+}
+
diff --git a/src/com/android/settings/development/AdbDeviceNamePreferenceController.java b/src/com/android/settings/development/AdbDeviceNamePreferenceController.java
new file mode 100644
index 0000000..7706c3c
--- /dev/null
+++ b/src/com/android/settings/development/AdbDeviceNamePreferenceController.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import static android.content.Context.CLIPBOARD_SERVICE;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.os.Build;
+import android.provider.Settings;
+import android.widget.Toast;
+
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Controller for the device name preference in the Wireless debugging
+ * fragment.
+ */
+public class AdbDeviceNamePreferenceController extends BasePreferenceController {
+    private static final String TAG = "AdbDeviceNamePrefCtrl";
+
+    private String mDeviceName;
+
+    public AdbDeviceNamePreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        // Keep device name in sync with Settings > About phone > Device name
+        mDeviceName = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.DEVICE_NAME);
+        if (mDeviceName == null) {
+            mDeviceName = Build.MODEL;
+        }
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return mDeviceName;
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public void copy() {
+        final ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(
+                CLIPBOARD_SERVICE);
+        clipboard.setPrimaryClip(ClipData.newPlainText("text", mDeviceName));
+
+        final String toast = mContext.getString(R.string.copyable_slice_toast,
+                mDeviceName);
+        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
+    }
+}
diff --git a/src/com/android/settings/development/AdbIpAddressPreferenceController.java b/src/com/android/settings/development/AdbIpAddressPreferenceController.java
new file mode 100644
index 0000000..dbc329e
--- /dev/null
+++ b/src/com/android/settings/development/AdbIpAddressPreferenceController.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.Context;
+import android.debug.IAdbManager;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.wifi.WifiManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.deviceinfo.AbstractConnectivityPreferenceController;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.Iterator;
+
+/**
+ * Controller for the ip address preference in the Wireless debugging
+ * fragment.
+ */
+public class AdbIpAddressPreferenceController extends AbstractConnectivityPreferenceController {
+    private static final String TAG = "AdbIpAddrPrefCtrl";
+
+    private static final String[] CONNECTIVITY_INTENTS = {
+            ConnectivityManager.CONNECTIVITY_ACTION,
+            WifiManager.ACTION_LINK_CONFIGURATION_CHANGED,
+            WifiManager.NETWORK_STATE_CHANGED_ACTION,
+    };
+
+    private static final String PREF_KEY = "adb_ip_addr_pref";
+    private Preference mAdbIpAddrPref;
+    private int mPort;
+    private final ConnectivityManager mCM;
+    private IAdbManager mAdbManager;
+
+    public AdbIpAddressPreferenceController(Context context, Lifecycle lifecycle) {
+        super(context, lifecycle);
+        mCM = context.getSystemService(ConnectivityManager.class);
+        mAdbManager = IAdbManager.Stub.asInterface(ServiceManager.getService(
+                Context.ADB_SERVICE));
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return PREF_KEY;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mAdbIpAddrPref = screen.findPreference(PREF_KEY);
+        updateConnectivity();
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        updateConnectivity();
+    }
+
+    @Override
+    protected String[] getConnectivityIntents() {
+        return CONNECTIVITY_INTENTS;
+    }
+
+    protected int getPort() {
+        try {
+            return mAdbManager.getAdbWirelessPort();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to get the adbwifi port");
+        }
+        return 0;
+    }
+
+    public String getIpv4Address() {
+        return getDefaultIpAddresses(mCM);
+    }
+
+    @Override
+    protected void updateConnectivity() {
+        String ipAddress = getDefaultIpAddresses(mCM);
+        if (ipAddress != null) {
+            int port = getPort();
+            if (port <= 0) {
+                mAdbIpAddrPref.setSummary(R.string.status_unavailable);
+            } else {
+                ipAddress += ":" + port;
+            }
+            mAdbIpAddrPref.setSummary(ipAddress);
+        } else {
+            mAdbIpAddrPref.setSummary(R.string.status_unavailable);
+        }
+    }
+
+    /**
+     * Returns the default link's IP addresses, if any, taking into account IPv4 and IPv6 style
+     * addresses.
+     * @param cm ConnectivityManager
+     * @return the formatted and newline-separated IP addresses, or null if none.
+     */
+    private static String getDefaultIpAddresses(ConnectivityManager cm) {
+        LinkProperties prop = cm.getActiveLinkProperties();
+        return formatIpAddresses(prop);
+    }
+
+    private static String formatIpAddresses(LinkProperties prop) {
+        if (prop == null) {
+            return null;
+        }
+
+        Iterator<InetAddress> iter = prop.getAllAddresses().iterator();
+        // If there are no entries, return null
+        if (!iter.hasNext()) {
+            return null;
+        }
+
+        // Concatenate all available addresses, newline separated
+        StringBuilder addresses = new StringBuilder();
+        while (iter.hasNext()) {
+            InetAddress addr = iter.next();
+            if (addr instanceof Inet4Address) {
+                // adb only supports ipv4 at the moment
+                addresses.append(addr.getHostAddress());
+                break;
+            }
+        }
+        return addresses.toString();
+    }
+}
diff --git a/src/com/android/settings/development/AdbPairedDevicePreference.java b/src/com/android/settings/development/AdbPairedDevicePreference.java
new file mode 100644
index 0000000..a82a949
--- /dev/null
+++ b/src/com/android/settings/development/AdbPairedDevicePreference.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.Context;
+import android.debug.PairDevice;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+
+/**
+ * An AP preference for the currently connected AP
+ */
+public class AdbPairedDevicePreference extends Preference {
+    private static final String TAG = "AdbPairedDevicePref";
+
+    private PairDevice mPairedDevice;
+
+    // Extract using getSerializable(PAIRED_DEVICE_EXTRA)
+    public static final String PAIRED_DEVICE_EXTRA = "paired_device";
+
+    public AdbPairedDevicePreference(PairDevice pairedDevice, Context context) {
+        super(context);
+
+        mPairedDevice = pairedDevice;
+        setWidgetLayoutResource(getWidgetLayoutResourceId());
+        refresh();
+    }
+
+    protected int getWidgetLayoutResourceId() {
+        return R.layout.preference_widget_gear_optional_background;
+    }
+
+    /**
+     * Refreshes the preference bound to the paired device previously passed in.
+     */
+    public void refresh() {
+        setTitle(this, mPairedDevice);
+    }
+
+    public void setPairedDevice(PairDevice pairedDevice) {
+        mPairedDevice = pairedDevice;
+    }
+
+    public PairDevice getPairedDevice() {
+        return mPairedDevice;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        final View gear = holder.findViewById(R.id.settings_button);
+        final View gearNoBg = holder.findViewById(R.id.settings_button_no_background);
+
+        gear.setVisibility(View.INVISIBLE);
+        gearNoBg.setVisibility(View.VISIBLE);
+    }
+
+    static void setTitle(AdbPairedDevicePreference preference,
+                         PairDevice pairedDevice) {
+        preference.setTitle(pairedDevice.getDeviceName());
+        preference.setSummary(pairedDevice.isConnected()
+                ? preference.getContext().getText(R.string.adb_wireless_device_connected_summary)
+                : "");
+    }
+
+    /**
+     * Writes the paired devices bound to this preference to the bundle.
+     *
+     * @param bundle the bundle to write the paired device to
+     */
+    public void savePairedDeviceToExtras(Bundle bundle) {
+        bundle.putParcelable(PAIRED_DEVICE_EXTRA, mPairedDevice);
+    }
+}
+
diff --git a/src/com/android/settings/development/AdbQrcodeScannerFragment.java b/src/com/android/settings/development/AdbQrcodeScannerFragment.java
new file mode 100644
index 0000000..4f8b113
--- /dev/null
+++ b/src/com/android/settings/development/AdbQrcodeScannerFragment.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.debug.AdbManager;
+import android.debug.IAdbManager;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.Size;
+import android.view.LayoutInflater;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.TextView;
+
+import androidx.annotation.StringRes;
+
+import com.android.settings.R;
+import com.android.settings.wifi.dpp.AdbQrCode;
+import com.android.settings.wifi.dpp.WifiDppQrCodeBaseFragment;
+import com.android.settings.wifi.dpp.WifiNetworkConfig;
+import com.android.settings.wifi.qrcode.QrCamera;
+import com.android.settings.wifi.qrcode.QrDecorateView;
+
+/**
+ * Fragment shown when clicking on the "Pair by QR code" preference in
+ * the Wireless Debugging fragment.
+ */
+public class AdbQrcodeScannerFragment extends WifiDppQrCodeBaseFragment implements
+        SurfaceTextureListener,
+        QrCamera.ScannerCallback {
+    private static final String TAG = "AdbQrcodeScannerFrag";
+
+    /** Message sent to hide error message */
+    private static final int MESSAGE_HIDE_ERROR_MESSAGE = 1;
+
+    /** Message sent to show error message */
+    private static final int MESSAGE_SHOW_ERROR_MESSAGE = 2;
+
+    private static final long SHOW_ERROR_MESSAGE_INTERVAL = 10000;
+    private static final long SHOW_SUCCESS_SQUARE_INTERVAL = 1000;
+
+    private QrCamera mCamera;
+    private TextureView mTextureView;
+    private QrDecorateView mDecorateView;
+    private View mQrCameraView;
+    private View mVerifyingView;
+    private TextView mErrorMessage;
+
+    /** QR code data scanned by camera */
+    private AdbQrCode mAdbQrCode;
+    private WifiNetworkConfig mAdbConfig;
+
+    private IAdbManager mAdbManager;
+
+    private IntentFilter mIntentFilter;
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION.equals(action)) {
+                Integer res = intent.getIntExtra(
+                        AdbManager.WIRELESS_STATUS_EXTRA,
+                        AdbManager.WIRELESS_STATUS_FAIL);
+                if (res.equals(AdbManager.WIRELESS_STATUS_SUCCESS)) {
+                    Intent i = new Intent();
+                    i.putExtra(
+                            WirelessDebuggingFragment.PAIRING_DEVICE_REQUEST_TYPE,
+                            WirelessDebuggingFragment.SUCCESS_ACTION);
+                    getActivity().setResult(Activity.RESULT_OK, i);
+                    getActivity().finish();
+                } else if (res.equals(AdbManager.WIRELESS_STATUS_FAIL)) {
+                    Intent i = new Intent();
+                    i.putExtra(
+                            WirelessDebuggingFragment.PAIRING_DEVICE_REQUEST_TYPE,
+                            WirelessDebuggingFragment.FAIL_ACTION);
+                    getActivity().setResult(Activity.RESULT_OK, i);
+                    getActivity().finish();
+                } else if (res.equals(AdbManager.WIRELESS_STATUS_CONNECTED)) {
+                    int port = intent.getIntExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, 0);
+                    Log.i(TAG, "Got Qr pairing code port=" + port);
+                }
+            }
+        }
+    };
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_HIDE_ERROR_MESSAGE:
+                    mErrorMessage.setVisibility(View.INVISIBLE);
+                    break;
+
+                case MESSAGE_SHOW_ERROR_MESSAGE:
+                    final String errorMessage = (String) msg.obj;
+
+                    mErrorMessage.setVisibility(View.VISIBLE);
+                    mErrorMessage.setText(errorMessage);
+                    mErrorMessage.sendAccessibilityEvent(
+                            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+
+                    // Cancel any pending messages to hide error view and requeue the message so
+                    // user has time to see error
+                    removeMessages(MESSAGE_HIDE_ERROR_MESSAGE);
+                    sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE,
+                            SHOW_ERROR_MESSAGE_INTERVAL);
+                    break;
+
+                default:
+                    return;
+            }
+        }
+    };
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mIntentFilter = new IntentFilter(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION);
+    }
+
+    @Override
+    public final View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.adb_qrcode_scanner_fragment, container, false);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        mTextureView = (TextureView) view.findViewById(R.id.preview_view);
+        mTextureView.setSurfaceTextureListener(this);
+
+        mDecorateView = view.findViewById(R.id.decorate_view);
+        setProgressBarShown(false);
+
+        setHeaderIconImageResource(R.drawable.ic_scan_24dp);
+
+        mQrCameraView = view.findViewById(R.id.camera_layout);
+        mVerifyingView = view.findViewById(R.id.verifying_layout);
+
+        setHeaderTitle(R.string.wifi_dpp_scan_qr_code);
+        mSummary.setText(R.string.adb_wireless_qrcode_pairing_description);
+
+        mErrorMessage = view.findViewById(R.id.error_message);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        mAdbManager = IAdbManager.Stub.asInterface(ServiceManager.getService(Context.ADB_SERVICE));
+        getActivity().registerReceiver(mReceiver, mIntentFilter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        getActivity().unregisterReceiver(mReceiver);
+        try {
+            mAdbManager.disablePairing();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to cancel pairing");
+        }
+        getActivity().finish();
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+        // Do nothing
+    }
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return 0;
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+        initCamera(surface);
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+        // Do nothing
+    }
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        destroyCamera();
+        return true;
+    }
+
+    @Override
+    public Size getViewSize() {
+        return new Size(mTextureView.getWidth(), mTextureView.getHeight());
+    }
+
+    @Override
+    public void setTransform(Matrix transform) {
+        mTextureView.setTransform(transform);
+    }
+
+    @Override
+    public Rect getFramePosition(Size previewSize, int cameraOrientation) {
+        return new Rect(0, 0, previewSize.getHeight(), previewSize.getHeight());
+    }
+
+    @Override
+    public boolean isValid(String qrCode) {
+        try {
+            // WIFI:T:ADB;S:myname;P:mypass;;
+            mAdbQrCode = new AdbQrCode(qrCode);
+        } catch (IllegalArgumentException e) {
+            showErrorMessage(R.string.wifi_dpp_qr_code_is_not_valid_format);
+            return false;
+        }
+
+        mAdbConfig = mAdbQrCode.getAdbNetworkConfig();
+
+        return true;
+    }
+
+    @Override
+    public void handleSuccessfulResult(String qrCode) {
+        destroyCamera();
+        mDecorateView.setFocused(true);
+        mQrCameraView.setVisibility(View.GONE);
+        mVerifyingView.setVisibility(View.VISIBLE);
+        try {
+            mAdbManager.enablePairingByQrCode(mAdbConfig.getSsid(),
+                    mAdbConfig.getPreSharedKey());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to enable QR code pairing");
+            getActivity().finish();
+        }
+    }
+
+    @Override
+    public void handleCameraFailure() {
+        destroyCamera();
+    }
+
+    private void initCamera(SurfaceTexture surface) {
+        // Check if the camera has alread been created.
+        if (mCamera == null) {
+            mCamera = new QrCamera(getContext(), this);
+            mCamera.start(surface);
+        }
+    }
+
+    /**
+     * To resume camera decoding task after handshake fail or Wi-Fi connection fail.
+     */
+    private void restartCamera() {
+        if (mCamera == null) {
+            Log.d(TAG, "mCamera is not available for restarting camera");
+            return;
+        }
+
+        if (mCamera.isDecodeTaskAlive()) {
+            mCamera.stop();
+        }
+
+        final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
+        if (surfaceTexture == null) {
+            throw new IllegalStateException("SurfaceTexture is not ready for restarting camera");
+        }
+
+        mCamera.start(surfaceTexture);
+    }
+
+    private void destroyCamera() {
+        if (mCamera != null) {
+            mCamera.stop();
+            mCamera = null;
+        }
+    }
+
+    private void showErrorMessage(@StringRes int messageResId) {
+        final Message message = mHandler.obtainMessage(MESSAGE_SHOW_ERROR_MESSAGE,
+                getString(messageResId));
+        message.sendToTarget();
+    }
+
+    @Override
+    protected boolean isFooterAvailable() {
+        return false;
+    }
+}
diff --git a/src/com/android/settings/development/AdbWirelessDialog.java b/src/com/android/settings/development/AdbWirelessDialog.java
new file mode 100644
index 0000000..48884b9
--- /dev/null
+++ b/src/com/android/settings/development/AdbWirelessDialog.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+
+/**
+ * Class to show a variety of dialogs for the Wireless debugging
+ * fragment.
+ */
+public class AdbWirelessDialog extends AlertDialog implements
+        AdbWirelessDialogUiBase,
+        DialogInterface.OnClickListener {
+
+    /**
+     * Interface for subscribers to implement in order to listen
+     * to AdbWirelessDialog events.
+     */
+    public interface AdbWirelessDialogListener {
+        /**
+         * Called when the dialog was closed by clicking a negative button.
+         */
+        default void onCancel() {
+        }
+
+        /**
+         * Called when the dialog was closed by clicking a positive button.
+         *
+         * @param dialog the dialog that was closed.
+         */
+        default void onSubmit(AdbWirelessDialog dialog) {
+        }
+
+        /**
+         * Called when the dialog was dismissed.
+         */
+        default void onDismiss() {
+        }
+    }
+
+    private static final String TAG = "AdbWirelessDialog";
+
+    private static final int BUTTON_CANCEL = DialogInterface.BUTTON_NEGATIVE;
+    private static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE;
+
+    private final AdbWirelessDialogListener mListener;
+    private final int mMode;
+
+    private View mView;
+    private AdbWirelessDialogController mController;
+
+    /**
+     * Creates a AdbWirelessDialog with no additional style. It displays as a dialog above the
+     * current view.
+     */
+    public static AdbWirelessDialog createModal(
+            Context context,
+            AdbWirelessDialogListener listener,
+            int mode) {
+        return new AdbWirelessDialog(context, listener, mode);
+    }
+
+    AdbWirelessDialog(Context context, AdbWirelessDialogListener listener, int mode) {
+        super(context);
+        mListener = listener;
+        mMode = mode;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        mView = getLayoutInflater().inflate(R.layout.adb_wireless_dialog, null);
+        setView(mView);
+        mController = new AdbWirelessDialogController(this, mView, mMode);
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        dismiss();
+        if (mListener != null) {
+            mListener.onDismiss();
+        }
+    }
+
+    @Override
+    public void onClick(DialogInterface dialogInterface, int id) {
+        if (mListener != null) {
+            switch (id) {
+                case BUTTON_CANCEL:
+                    mListener.onCancel();
+                    break;
+            }
+        }
+    }
+
+    @Override
+    public AdbWirelessDialogController getController() {
+        return mController;
+    }
+
+    @Override
+    public void dispatchSubmit() {
+        if (mListener != null) {
+            mListener.onSubmit(this);
+        }
+        dismiss();
+    }
+
+    @Override
+    public int getMode() {
+        return mMode;
+    }
+
+    @Override
+    public Button getSubmitButton() {
+        return getButton(BUTTON_SUBMIT);
+    }
+
+    @Override
+    public Button getCancelButton() {
+        return getButton(BUTTON_NEGATIVE);
+    }
+
+    @Override
+    public void setSubmitButton(CharSequence text) {
+        setButton(BUTTON_SUBMIT, text, this);
+    }
+
+    @Override
+    public void setCancelButton(CharSequence text) {
+        setButton(BUTTON_NEGATIVE, text, this);
+    }
+}
diff --git a/src/com/android/settings/development/AdbWirelessDialogController.java b/src/com/android/settings/development/AdbWirelessDialogController.java
new file mode 100644
index 0000000..136c7b3
--- /dev/null
+++ b/src/com/android/settings/development/AdbWirelessDialogController.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+/**
+ * The class for allowing UIs like {@link AdbWirelessDialog} and {@link AdbWirelessDialogUiBase} to
+ * share the logic for controlling buttons, text fields, etc.
+ */
+public class AdbWirelessDialogController {
+    private static final String TAG = "AdbWirelessDialogCtrl";
+
+    private final AdbWirelessDialogUiBase mUi;
+    private final View mView;
+
+    private int mMode;
+
+    // The dialog for showing the six-digit code
+    private TextView mPairingCodeTitle;
+    private TextView mSixDigitCode;
+    private TextView mIpAddr;
+
+    // The dialog for showing pairing failed message
+    private TextView mFailedMsg;
+
+    private Context mContext;
+
+    public AdbWirelessDialogController(AdbWirelessDialogUiBase parent, View view,
+            int mode) {
+        mUi = parent;
+        mView = view;
+        mMode = mode;
+
+        mContext = mUi.getContext();
+        final Resources res = mContext.getResources();
+
+        mSixDigitCode = mView.findViewById(R.id.pairing_code);
+        mIpAddr = mView.findViewById(R.id.ip_addr);
+
+        switch (mMode) {
+            case AdbWirelessDialogUiBase.MODE_PAIRING:
+                String title = res.getString(R.string.adb_pairing_device_dialog_title);
+                mUi.setTitle(title);
+                mView.findViewById(R.id.l_pairing_six_digit).setVisibility(View.VISIBLE);
+                mUi.setCancelButton(res.getString(R.string.cancel));
+                mUi.setCanceledOnTouchOutside(false);
+                break;
+            case AdbWirelessDialogUiBase.MODE_PAIRING_FAILED:
+                String msg = res.getString(R.string.adb_pairing_device_dialog_failed_msg);
+                mUi.setTitle(R.string.adb_pairing_device_dialog_failed_title);
+                mView.findViewById(R.id.l_pairing_failed).setVisibility(View.VISIBLE);
+                mFailedMsg = (TextView) mView.findViewById(R.id.pairing_failed_label);
+                mFailedMsg.setText(msg);
+                mUi.setSubmitButton(res.getString(R.string.okay));
+                break;
+            case AdbWirelessDialogUiBase.MODE_QRCODE_FAILED:
+                mUi.setTitle(R.string.adb_pairing_device_dialog_failed_title);
+                mView.findViewById(R.id.l_qrcode_pairing_failed).setVisibility(View.VISIBLE);
+                mUi.setSubmitButton(res.getString(R.string.okay));
+                break;
+        }
+
+        // After done view show and hide, request focus from parent view
+        mView.findViewById(R.id.l_adbwirelessdialog).requestFocus();
+    }
+
+    /**
+     * Set the pairing code UI text field to code.
+     *
+     * @param code the pairing code string
+     */
+    public void setPairingCode(String code) {
+        mSixDigitCode.setText(code);
+    }
+
+    /**
+     * Set the Ip address UI text field to ipAddr.
+     *
+     * @param ipAddr the ip address string
+     */
+    public void setIpAddr(String ipAddr) {
+        mIpAddr.setText(ipAddr);
+    }
+}
diff --git a/src/com/android/settings/development/AdbWirelessDialogUiBase.java b/src/com/android/settings/development/AdbWirelessDialogUiBase.java
new file mode 100644
index 0000000..b2fc01c
--- /dev/null
+++ b/src/com/android/settings/development/AdbWirelessDialogUiBase.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.widget.Button;
+
+/**
+ * Foundation interface glues between Activities and UIs like {@link AdbWirelessDialog}.
+ */
+public interface AdbWirelessDialogUiBase {
+    /**
+     * Dialog shown when pairing a device via six-digit code.
+     */
+    int MODE_PAIRING = 0;
+    /**
+     *  Dialog shown when connecting to a paired device failed.
+     */
+    int MODE_CONNECTION_FAILED = 1;
+    /**
+     * Dialog shown when pairing failed.
+     */
+    int MODE_PAIRING_FAILED = 2;
+
+    /**
+     * Dialog shown when QR code pairing failed.
+     */
+    int MODE_QRCODE_FAILED = 3;
+
+    /**
+     * Gets the context for the dialog.
+     *
+     * @return the context for the dialog
+     */
+    Context getContext();
+
+    /**
+     * Gets the controller for the dialog.
+     *
+     * @return the controller for the dialog.
+     */
+    AdbWirelessDialogController getController();
+
+    /**
+     * Gets the layout for the dialog.
+     *
+     * @return the {@link LayoutInflater} for the dialog
+     */
+    LayoutInflater getLayoutInflater();
+
+    /**
+     * Gets the dialog mode/ID.
+     *
+     * @return the mode of the dialog
+     */
+    int getMode();
+
+    /**
+     * Sends a submit command to the dialog.
+     */
+    void dispatchSubmit();
+
+    /**
+     * Enables if user can cancel a dialog by clicking outside of the dialog.
+     *
+     * @param cancel The flag indicating if can cancel by clicking outside
+     */
+    void setCanceledOnTouchOutside(boolean cancel);
+
+    /**
+     * Sets the title of the dialog.
+     *
+     * @param id the string id
+     */
+    void setTitle(int id);
+
+    /**
+     * Sets the title of the dialog.
+     *
+     * @param title the title string
+     */
+    void setTitle(CharSequence title);
+
+    /**
+     * Sets the text for the submit button.
+     *
+     * @param text the submit text
+     */
+    void setSubmitButton(CharSequence text);
+
+    /**
+     * Sets the text for the cancel button.
+     *
+     * @param text the cancel text
+     */
+    void setCancelButton(CharSequence text);
+
+    /**
+     * Gets the button widget for the submit button.
+     *
+     * @return the submit {@link Button} widget
+     */
+    Button getSubmitButton();
+
+    /**
+     * Gets the button widget for the cancel button.
+     *
+     * @return the cancel {@link Button} widget
+     */
+    Button getCancelButton();
+}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 1c08131..f3f2a3a 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -443,6 +443,7 @@
         controllers.add(new SelectDSUPreferenceController(context));
         controllers.add(new AdbPreferenceController(context, fragment));
         controllers.add(new ClearAdbKeysPreferenceController(context, fragment));
+        controllers.add(new WirelessDebuggingPreferenceController(context, lifecycle));
         controllers.add(new LocalTerminalPreferenceController(context));
         controllers.add(new BugReportInPowerPreferenceController(context));
         controllers.add(new AutomaticSystemServerHeapDumpPreferenceController(context));
@@ -451,6 +452,7 @@
         controllers.add(new SelectDebugAppPreferenceController(context, fragment));
         controllers.add(new WaitForDebuggerPreferenceController(context));
         controllers.add(new EnableGpuDebugLayersPreferenceController(context));
+        controllers.add(new EnableVerboseVendorLoggingPreferenceController(context));
         controllers.add(new VerifyAppsOverUsbPreferenceController(context));
         controllers.add(new ArtVerifierPreferenceController(context));
         controllers.add(new LogdSizePreferenceController(context));
@@ -468,6 +470,7 @@
         controllers.add(new BluetoothMapVersionPreferenceController(context));
         controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment));
         controllers.add(new BluetoothMaxConnectedAudioDevicesPreferenceController(context));
+        controllers.add(new EnhancedConnectivityPreferenceController(context));
         controllers.add(new ShowTapsPreferenceController(context));
         controllers.add(new PointerLocationPreferenceController(context));
         controllers.add(new ShowSurfaceUpdatesPreferenceController(context));
diff --git a/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceController.java b/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceController.java
new file mode 100644
index 0000000..e1db74d
--- /dev/null
+++ b/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceController.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.dumpstate.V1_0.IDumpstateDevice;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+import java.util.NoSuchElementException;
+
+public class EnableVerboseVendorLoggingPreferenceController
+        extends DeveloperOptionsPreferenceController
+        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+    private static final String TAG = "EnableVerboseVendorLoggingPreferenceController";
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private static final String ENABLE_VERBOSE_VENDOR_LOGGING_KEY = "enable_verbose_vendor_logging";
+    private static final int DUMPSTATE_HAL_VERSION_UNKNOWN = -1;
+    private static final int DUMPSTATE_HAL_VERSION_1_0 = 0;
+    private static final int DUMPSTATE_HAL_VERSION_1_1 = 1;
+
+    private int mDumpstateHalVersion;
+
+    public EnableVerboseVendorLoggingPreferenceController(Context context) {
+        super(context);
+        mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_UNKNOWN;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return ENABLE_VERBOSE_VENDOR_LOGGING_KEY;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        // Only show preference when IDumpstateDevice v1.1 is avalaible
+        // This is temperary strategy that may change later.
+        return isIDumpstateDeviceV1_1ServiceAvailable();
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean isEnabled = (Boolean) newValue;
+        setVerboseLoggingEnabled(isEnabled);
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        final boolean enabled = getVerboseLoggingEnabled();
+        ((SwitchPreference) mPreference).setChecked(enabled);
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        setVerboseLoggingEnabled(false);
+        ((SwitchPreference) mPreference).setChecked(false);
+    }
+
+    @VisibleForTesting
+    boolean isIDumpstateDeviceV1_1ServiceAvailable() {
+        IDumpstateDevice service = getDumpstateDeviceService();
+        if (service == null) {
+            if (DBG) Log.d(TAG, "IDumpstateDevice service is not available.");
+        }
+        return service != null && mDumpstateHalVersion >= DUMPSTATE_HAL_VERSION_1_1;
+    }
+
+    @VisibleForTesting
+    void setVerboseLoggingEnabled(boolean enable) {
+        IDumpstateDevice service = getDumpstateDeviceService();
+
+        if (service == null || mDumpstateHalVersion < DUMPSTATE_HAL_VERSION_1_1) {
+            if (DBG) Log.d(TAG, "setVerboseLoggingEnabled not supported.");
+            return;
+        }
+
+        try {
+            android.hardware.dumpstate.V1_1.IDumpstateDevice service11 =
+                    (android.hardware.dumpstate.V1_1.IDumpstateDevice) service;
+            if (service11 != null) {
+                service11.setVerboseLoggingEnabled(enable);
+            }
+        } catch (RemoteException | RuntimeException e) {
+            if (DBG) Log.e(TAG, "setVerboseLoggingEnabled fail: " + e);
+        }
+    }
+
+    @VisibleForTesting
+    boolean getVerboseLoggingEnabled() {
+        IDumpstateDevice service = getDumpstateDeviceService();
+
+        if (service == null || mDumpstateHalVersion < DUMPSTATE_HAL_VERSION_1_1) {
+            if (DBG) Log.d(TAG, "getVerboseLoggingEnabled not supported.");
+            return false;
+        }
+
+        try {
+            android.hardware.dumpstate.V1_1.IDumpstateDevice service11 =
+                    (android.hardware.dumpstate.V1_1.IDumpstateDevice) service;
+            if (service11 != null) {
+                return service11.getVerboseLoggingEnabled();
+            }
+        } catch (RemoteException | RuntimeException e) {
+            if (DBG) Log.e(TAG, "getVerboseLoggingEnabled fail: " + e);
+        }
+        return false;
+    }
+
+    /** Return a {@IDumpstateDevice} instance or null if service is not available. */
+    @VisibleForTesting
+    @Nullable IDumpstateDevice getDumpstateDeviceService() {
+        IDumpstateDevice service = null;
+        try {
+            service = android.hardware.dumpstate.V1_1.IDumpstateDevice
+                    .getService(true /* retry */);
+            mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_1_1;
+        } catch (NoSuchElementException | RemoteException e) {
+        }
+
+        if (service == null) {
+            try {
+                service = android.hardware.dumpstate.V1_0.IDumpstateDevice
+                        .getService(true /* retry */);
+                mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_1_0;
+            } catch (NoSuchElementException | RemoteException e) {
+            }
+        }
+
+        if (service == null) {
+            mDumpstateHalVersion = DUMPSTATE_HAL_VERSION_UNKNOWN;
+        }
+        return service;
+    }
+}
diff --git a/src/com/android/settings/development/EnhancedConnectivityPreferenceController.java b/src/com/android/settings/development/EnhancedConnectivityPreferenceController.java
new file mode 100644
index 0000000..2dbd7d1
--- /dev/null
+++ b/src/com/android/settings/development/EnhancedConnectivityPreferenceController.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+/**
+ * Preference controller for Enhanced Connectivity feature
+ */
+public class EnhancedConnectivityPreferenceController extends
+        DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
+        PreferenceControllerMixin {
+
+    private static final String ENHANCED_CONNECTIVITY_KEY = "enhanced_connectivity";
+
+    @VisibleForTesting
+    static final int ENHANCED_CONNECTIVITY_ON = 1;
+    // default is enhanced connectivity disabled.
+    @VisibleForTesting
+    static final int ENHANCED_CONNECTIVITY_OFF = 0;
+
+    public EnhancedConnectivityPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object o) {
+        final boolean isEnabled = (Boolean) o;
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ENHANCED_CONNECTIVITY_ENABLED,
+                isEnabled
+                        ? ENHANCED_CONNECTIVITY_ON
+                        : ENHANCED_CONNECTIVITY_OFF);
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return ENHANCED_CONNECTIVITY_KEY;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        final int enhancedConnectivityEnabled = Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.ENHANCED_CONNECTIVITY_ENABLED,
+                ENHANCED_CONNECTIVITY_OFF);
+        ((SwitchPreference) mPreference).setChecked(
+                enhancedConnectivityEnabled == ENHANCED_CONNECTIVITY_ON);
+    }
+
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ENHANCED_CONNECTIVITY_ENABLED,
+                ENHANCED_CONNECTIVITY_OFF);
+        ((SwitchPreference) mPreference).setChecked(false);
+    }
+}
diff --git a/src/com/android/settings/development/WirelessDebuggingEnabler.java b/src/com/android/settings/development/WirelessDebuggingEnabler.java
new file mode 100644
index 0000000..51b81f6
--- /dev/null
+++ b/src/com/android/settings/development/WirelessDebuggingEnabler.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.settings.widget.SwitchWidgetController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+
+/**
+ * Class to control the switch bar in the wireless debugging fragment.
+ */
+public class WirelessDebuggingEnabler implements SwitchWidgetController.OnSwitchChangeListener,
+        LifecycleObserver, OnResume, OnPause {
+    private static final String TAG = "WirelessDebuggingEnabler";
+
+    private final SwitchWidgetController mSwitchWidget;
+    private Context mContext;
+    private boolean mListeningToOnSwitchChange = false;
+    private OnEnabledListener mListener;
+    private final ContentResolver mContentResolver;
+    private final ContentObserver mSettingsObserver;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    public WirelessDebuggingEnabler(Context context, SwitchWidgetController switchWidget,
+            OnEnabledListener listener, Lifecycle lifecycle) {
+        mContext = context;
+        mSwitchWidget = switchWidget;
+        mSwitchWidget.setListener(this);
+        mSwitchWidget.setupView();
+
+        mListener = listener;
+        if (lifecycle != null) {
+            lifecycle.addObserver(this);
+        }
+
+        mContentResolver = context.getContentResolver();
+        mSettingsObserver = new ContentObserver(mHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                Log.i(TAG, "ADB_WIFI_ENABLED=" + isAdbWifiEnabled());
+                onWirelessDebuggingEnabled(isAdbWifiEnabled());
+            }
+        };
+    }
+
+    private boolean isAdbWifiEnabled() {
+        return Settings.Global.getInt(mContentResolver, Settings.Global.ADB_WIFI_ENABLED,
+                AdbPreferenceController.ADB_SETTING_OFF)
+                != AdbPreferenceController.ADB_SETTING_OFF;
+    }
+
+    /**
+     * Tears down the switch controller for the wireless debugging switch.
+     */
+    public void teardownSwitchController() {
+        if (mListeningToOnSwitchChange) {
+            mSwitchWidget.stopListening();
+            mListeningToOnSwitchChange = false;
+        }
+        mSwitchWidget.teardownView();
+    }
+
+    @Override
+    public void onResume() {
+        if (!mListeningToOnSwitchChange) {
+            mSwitchWidget.startListening();
+            mListeningToOnSwitchChange = true;
+        }
+        onWirelessDebuggingEnabled(isAdbWifiEnabled());
+        mContentResolver.registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED), false,
+                mSettingsObserver);
+    }
+
+    @Override
+    public void onPause() {
+        if (mListeningToOnSwitchChange) {
+            mSwitchWidget.stopListening();
+            mListeningToOnSwitchChange = false;
+        }
+        mContentResolver.unregisterContentObserver(mSettingsObserver);
+    }
+
+    private void onWirelessDebuggingEnabled(boolean enabled) {
+        mSwitchWidget.setChecked(enabled);
+        if (mListener != null) {
+            mListener.onEnabled(enabled);
+        }
+    }
+
+    protected void writeAdbWifiSetting(boolean enabled) {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ADB_WIFI_ENABLED, enabled ? AdbPreferenceController.ADB_SETTING_ON
+                : AdbPreferenceController.ADB_SETTING_OFF);
+    }
+
+    @Override
+    public boolean onSwitchToggled(boolean isChecked) {
+        writeAdbWifiSetting(isChecked);
+        return true;
+    }
+
+    /**
+     * Interface for subscribers to implement in order to listen for
+     * wireless debugging state changes.
+     */
+    public interface OnEnabledListener {
+        /**
+         * Called when wireless debugging state changes.
+         *
+         * @param enabled the state of wireless debugging
+         */
+        void onEnabled(boolean enabled);
+    }
+}
diff --git a/src/com/android/settings/development/WirelessDebuggingFragment.java b/src/com/android/settings/development/WirelessDebuggingFragment.java
new file mode 100644
index 0000000..2edadcc
--- /dev/null
+++ b/src/com/android/settings/development/WirelessDebuggingFragment.java
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2020 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.development;
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.settings.SettingsEnums;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.debug.AdbManager;
+import android.debug.IAdbManager;
+import android.debug.PairDevice;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.widget.SwitchBarController;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.development.DevelopmentSettingsEnabler;
+import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.widget.FooterPreference;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Fragment shown when clicking in the "Wireless Debugging" preference in
+ * the developer options.
+ */
+@SearchIndexable
+public class WirelessDebuggingFragment extends DashboardFragment
+        implements WirelessDebuggingEnabler.OnEnabledListener {
+
+    private static final String TAG = "WirelessDebuggingFrag";
+
+    // Activity result from clicking on a paired device.
+    private static final int PAIRED_DEVICE_REQUEST = 0;
+    public static final String PAIRED_DEVICE_REQUEST_TYPE = "request_type";
+    public static final int FORGET_ACTION = 0;
+
+    // Activity result from pairing a device.
+    private static final int PAIRING_DEVICE_REQUEST = 1;
+    public static final String PAIRING_DEVICE_REQUEST_TYPE = "request_type_pairing";
+    public static final int SUCCESS_ACTION = 0;
+    public static final int FAIL_ACTION = 1;
+
+    public static final String PAIRED_DEVICE_EXTRA = "paired_device";
+    public static final String DEVICE_NAME_EXTRA = "device_name";
+    public static final String IP_ADDR_EXTRA = "ip_addr";
+
+    private WirelessDebuggingEnabler mWifiDebuggingEnabler;
+
+    private static AdbIpAddressPreferenceController sAdbIpAddressPreferenceController;
+    // UI components
+    private static final String PREF_KEY_ADB_DEVICE_NAME = "adb_device_name_pref";
+    private static final String PREF_KEY_ADB_IP_ADDR = "adb_ip_addr_pref";
+    private static final String PREF_KEY_PAIRING_METHODS_CATEGORY = "adb_pairing_methods_category";
+    private static final String PREF_KEY_ADB_QRCODE_PAIRING = "adb_pair_method_qrcode_pref";
+    private static final String PREF_KEY_ADB_CODE_PAIRING = "adb_pair_method_code_pref";
+    private static final String PREF_KEY_PAIRED_DEVICES_CATEGORY = "adb_paired_devices_category";
+    private static final String PREF_KEY_FOOTER_CATEGORY = "adb_wireless_footer_category";
+
+    private Preference mDeviceNamePreference;
+    private Preference mIpAddrPreference;
+
+    private PreferenceCategory mPairingMethodsCategory;
+    private Preference mQrcodePairingPreference;
+    private Preference mCodePairingPreference;
+
+    private PreferenceCategory mPairedDevicesCategory;
+
+    private PreferenceCategory mFooterCategory;
+    private FooterPreference mOffMessagePreference;
+
+    // Map of paired devices, with the device GUID is the key
+    private Map<String, AdbPairedDevicePreference> mPairedDevicePreferences;
+
+    private IAdbManager mAdbManager;
+    private int mConnectionPort;
+
+    class PairingCodeDialogListener implements AdbWirelessDialog.AdbWirelessDialogListener {
+        @Override
+        public void onDismiss() {
+            Log.i(TAG, "onDismiss");
+            mPairingCodeDialog = null;
+            try {
+                mAdbManager.disablePairing();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to cancel pairing");
+            }
+        }
+    }
+    final PairingCodeDialogListener mPairingCodeDialogListener = new PairingCodeDialogListener();
+    AdbWirelessDialog mPairingCodeDialog;
+
+    private IntentFilter mIntentFilter;
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION.equals(action)) {
+                Map<String, PairDevice> newPairedDevicesList =
+                        (HashMap<String, PairDevice>) intent.getSerializableExtra(
+                            AdbManager.WIRELESS_DEVICES_EXTRA);
+                updatePairedDevicePreferences(newPairedDevicesList);
+            } else if (AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION.equals(action)) {
+                int status = intent.getIntExtra(AdbManager.WIRELESS_STATUS_EXTRA,
+                        AdbManager.WIRELESS_STATUS_DISCONNECTED);
+                if (status == AdbManager.WIRELESS_STATUS_CONNECTED) {
+                    int port = intent.getIntExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, 0);
+                    Log.i(TAG, "Got adbwifi port=" + port);
+                } else {
+                    Log.i(TAG, "adbwifi server disconnected");
+                }
+            } else if (AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION.equals(action)) {
+                Integer res = intent.getIntExtra(
+                        AdbManager.WIRELESS_STATUS_EXTRA,
+                        AdbManager.WIRELESS_STATUS_FAIL);
+
+                if (res.equals(AdbManager.WIRELESS_STATUS_PAIRING_CODE)) {
+                    String pairingCode = intent.getStringExtra(
+                                AdbManager.WIRELESS_PAIRING_CODE_EXTRA);
+                    if (mPairingCodeDialog != null) {
+                        mPairingCodeDialog.getController().setPairingCode(pairingCode);
+                    }
+                } else if (res.equals(AdbManager.WIRELESS_STATUS_SUCCESS)) {
+                    removeDialog(AdbWirelessDialogUiBase.MODE_PAIRING);
+                    mPairingCodeDialog = null;
+                } else if (res.equals(AdbManager.WIRELESS_STATUS_FAIL)) {
+                    removeDialog(AdbWirelessDialogUiBase.MODE_PAIRING);
+                    mPairingCodeDialog = null;
+                    showDialog(AdbWirelessDialogUiBase.MODE_PAIRING_FAILED);
+                } else if (res.equals(AdbManager.WIRELESS_STATUS_CONNECTED)) {
+                    int port = intent.getIntExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, 0);
+                    Log.i(TAG, "Got pairing code port=" + port);
+                    String ipAddr = sAdbIpAddressPreferenceController.getIpv4Address() + ":" + port;
+                    if (mPairingCodeDialog != null) {
+                        mPairingCodeDialog.getController().setIpAddr(ipAddr);
+                    }
+                }
+            }
+        }
+    };
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        final SettingsActivity activity = (SettingsActivity) getActivity();
+        mWifiDebuggingEnabler =  new WirelessDebuggingEnabler(activity,
+                new SwitchBarController(activity.getSwitchBar()), this,
+                getSettingsLifecycle());
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        addPreferences();
+        mIntentFilter = new IntentFilter(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION);
+        mIntentFilter.addAction(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION);
+        mIntentFilter.addAction(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION);
+    }
+
+    private void addPreferences() {
+        mDeviceNamePreference =
+            (Preference) findPreference(PREF_KEY_ADB_DEVICE_NAME);
+        mIpAddrPreference =
+            (Preference) findPreference(PREF_KEY_ADB_IP_ADDR);
+        mPairingMethodsCategory =
+                (PreferenceCategory) findPreference(PREF_KEY_PAIRING_METHODS_CATEGORY);
+        mCodePairingPreference =
+                (Preference) findPreference(PREF_KEY_ADB_CODE_PAIRING);
+        mCodePairingPreference.setOnPreferenceClickListener(preference -> {
+            showDialog(AdbWirelessDialogUiBase.MODE_PAIRING);
+            return true;
+        });
+        mQrcodePairingPreference =
+                (Preference) findPreference(PREF_KEY_ADB_QRCODE_PAIRING);
+        mQrcodePairingPreference.setOnPreferenceClickListener(preference -> {
+            launchQrcodeScannerFragment();
+            return true;
+        });
+
+        mPairedDevicesCategory =
+                (PreferenceCategory) findPreference(PREF_KEY_PAIRED_DEVICES_CATEGORY);
+        mFooterCategory =
+                (PreferenceCategory) findPreference(PREF_KEY_FOOTER_CATEGORY);
+
+        mOffMessagePreference =
+                new FooterPreference(mFooterCategory.getContext());
+        final CharSequence title = getText(R.string.adb_wireless_list_empty_off);
+        mOffMessagePreference.setTitle(title);
+        mFooterCategory.addPreference(mOffMessagePreference);
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+
+        mWifiDebuggingEnabler.teardownSwitchController();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        getActivity().registerReceiver(mReceiver, mIntentFilter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        removeDialog(AdbWirelessDialogUiBase.MODE_PAIRING);
+        getActivity().unregisterReceiver(mReceiver);
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+        if (requestCode == PAIRED_DEVICE_REQUEST) {
+            handlePairedDeviceRequest(resultCode, data);
+        } else if (requestCode == PAIRING_DEVICE_REQUEST) {
+            handlePairingDeviceRequest(resultCode, data);
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_ADB_WIRELESS;
+    }
+
+    @Override
+    public int getDialogMetricsCategory(int dialogId) {
+        return SettingsEnums.ADB_WIRELESS_DEVICE_PAIRING_DIALOG;
+    }
+
+    @Override
+    public Dialog onCreateDialog(int dialogId) {
+        Dialog d = AdbWirelessDialog.createModal(getActivity(),
+                dialogId == AdbWirelessDialogUiBase.MODE_PAIRING
+                    ? mPairingCodeDialogListener : null, dialogId);
+        if (dialogId == AdbWirelessDialogUiBase.MODE_PAIRING) {
+            mPairingCodeDialog = (AdbWirelessDialog) d;
+            try {
+                mAdbManager.enablePairingByPairingCode();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to enable pairing");
+                mPairingCodeDialog = null;
+                d = AdbWirelessDialog.createModal(getActivity(), null,
+                        AdbWirelessDialogUiBase.MODE_PAIRING_FAILED);
+            }
+        }
+        if (d != null) {
+            return d;
+        }
+        return super.onCreateDialog(dialogId);
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.adb_wireless_settings;
+    }
+
+    @Override
+    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+        return buildPreferenceControllers(context, getActivity(), this /* fragment */,
+                getSettingsLifecycle());
+    }
+
+    private static List<AbstractPreferenceController> buildPreferenceControllers(
+            Context context, Activity activity, WirelessDebuggingFragment fragment,
+            Lifecycle lifecycle) {
+        final List<AbstractPreferenceController> controllers = new ArrayList<>();
+        sAdbIpAddressPreferenceController =
+                new AdbIpAddressPreferenceController(context, lifecycle);
+        controllers.add(sAdbIpAddressPreferenceController);
+
+        return controllers;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    public void onEnabled(boolean enabled) {
+        if (enabled) {
+            showDebuggingPreferences();
+            mAdbManager = IAdbManager.Stub.asInterface(ServiceManager.getService(
+                    Context.ADB_SERVICE));
+            try {
+                Map<String, PairDevice> newList = mAdbManager.getPairedDevices();
+                updatePairedDevicePreferences(newList);
+                mConnectionPort = mAdbManager.getAdbWirelessPort();
+                if (mConnectionPort > 0) {
+                    Log.i(TAG, "onEnabled(): connect_port=" + mConnectionPort);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to request the paired list for Adb wireless");
+            }
+            sAdbIpAddressPreferenceController.updateState(mIpAddrPreference);
+        } else {
+            showOffMessage();
+        }
+    }
+
+    private void showOffMessage() {
+        mDeviceNamePreference.setVisible(false);
+        mIpAddrPreference.setVisible(false);
+        mPairingMethodsCategory.setVisible(false);
+        mPairedDevicesCategory.setVisible(false);
+        mFooterCategory.setVisible(true);
+    }
+
+    private void showDebuggingPreferences() {
+        mDeviceNamePreference.setVisible(true);
+        mIpAddrPreference.setVisible(true);
+        mPairingMethodsCategory.setVisible(true);
+        mPairedDevicesCategory.setVisible(true);
+        mFooterCategory.setVisible(false);
+    }
+
+    private void updatePairedDevicePreferences(Map<String, PairDevice> newList) {
+        // TODO(joshuaduong): Move the non-UI stuff into another thread
+        // as the processing could take some time.
+        if (newList == null) {
+            mPairedDevicesCategory.removeAll();
+            return;
+        }
+        if (mPairedDevicePreferences == null) {
+            mPairedDevicePreferences = new HashMap<String, AdbPairedDevicePreference>();
+        }
+        if (mPairedDevicePreferences.isEmpty()) {
+            for (Map.Entry<String, PairDevice> entry : newList.entrySet()) {
+                AdbPairedDevicePreference p =
+                        new AdbPairedDevicePreference(entry.getValue(),
+                            mPairedDevicesCategory.getContext());
+                mPairedDevicePreferences.put(
+                        entry.getKey(),
+                        p);
+                p.setOnPreferenceClickListener(preference -> {
+                    AdbPairedDevicePreference pref =
+                            (AdbPairedDevicePreference) preference;
+                    launchPairedDeviceDetailsFragment(pref);
+                    return true;
+                });
+                mPairedDevicesCategory.addPreference(p);
+            }
+        } else {
+            // Remove any devices no longer on the newList
+            mPairedDevicePreferences.entrySet().removeIf(entry -> {
+                if (newList.get(entry.getKey()) == null) {
+                    mPairedDevicesCategory.removePreference(entry.getValue());
+                    return true;
+                } else {
+                    // It is in the newList. Just update the PairDevice value
+                    AdbPairedDevicePreference p =
+                            entry.getValue();
+                    p.setPairedDevice(newList.get(entry.getKey()));
+                    p.refresh();
+                    return false;
+                }
+            });
+            // Add new devices if any.
+            for (Map.Entry<String, PairDevice> entry :
+                    newList.entrySet()) {
+                if (mPairedDevicePreferences.get(entry.getKey()) == null) {
+                    AdbPairedDevicePreference p =
+                            new AdbPairedDevicePreference(entry.getValue(),
+                                mPairedDevicesCategory.getContext());
+                    mPairedDevicePreferences.put(
+                            entry.getKey(),
+                            p);
+                    p.setOnPreferenceClickListener(preference -> {
+                        AdbPairedDevicePreference pref =
+                                (AdbPairedDevicePreference) preference;
+                        launchPairedDeviceDetailsFragment(pref);
+                        return true;
+                    });
+                    mPairedDevicesCategory.addPreference(p);
+                }
+            }
+        }
+    }
+
+    private void launchPairedDeviceDetailsFragment(AdbPairedDevicePreference p) {
+        // For sending to the device details fragment.
+        p.savePairedDeviceToExtras(p.getExtras());
+        new SubSettingLauncher(getContext())
+                .setTitleRes(R.string.adb_wireless_device_details_title)
+                .setDestination(AdbDeviceDetailsFragment.class.getName())
+                .setArguments(p.getExtras())
+                .setSourceMetricsCategory(getMetricsCategory())
+                .setResultListener(this, PAIRED_DEVICE_REQUEST)
+                .launch();
+    }
+
+    void handlePairedDeviceRequest(int result, Intent data) {
+        if (result != Activity.RESULT_OK) {
+            return;
+        }
+
+        Log.i(TAG, "Processing paired device request");
+        int requestType = data.getIntExtra(PAIRED_DEVICE_REQUEST_TYPE, -1);
+
+        PairDevice p;
+
+        switch (requestType) {
+            case FORGET_ACTION:
+                try {
+                    p = (PairDevice) data.getParcelableExtra(PAIRED_DEVICE_EXTRA);
+                    mAdbManager.unpairDevice(p.getGuid());
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Unable to forget the device");
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    void handlePairingDeviceRequest(int result, Intent data) {
+        if (result != Activity.RESULT_OK) {
+            return;
+        }
+
+        int requestType = data.getIntExtra(PAIRING_DEVICE_REQUEST_TYPE, -1);
+        switch (requestType) {
+            case FAIL_ACTION:
+                showDialog(AdbWirelessDialogUiBase.MODE_PAIRING_FAILED);
+                break;
+            default:
+                break;
+        }
+    }
+
+    private String getDeviceName() {
+        // Keep device name in sync with Settings > About phone > Device name
+        String deviceName = Settings.Global.getString(getContext().getContentResolver(),
+                Settings.Global.DEVICE_NAME);
+        if (deviceName == null) {
+            deviceName = Build.MODEL;
+        }
+        return deviceName;
+    }
+
+    private void launchQrcodeScannerFragment() {
+        new SubSettingLauncher(getContext())
+                .setDestination(AdbQrcodeScannerFragment.class.getName())
+                .setSourceMetricsCategory(getMetricsCategory())
+                .setResultListener(this, PAIRING_DEVICE_REQUEST)
+                .launch();
+    }
+
+    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider(R.xml.development_tile_settings) {
+
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context);
+                }
+            };
+}
diff --git a/src/com/android/settings/development/WirelessDebuggingPreferenceController.java b/src/com/android/settings/development/WirelessDebuggingPreferenceController.java
new file mode 100644
index 0000000..81575d2
--- /dev/null
+++ b/src/com/android/settings/development/WirelessDebuggingPreferenceController.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.debug.IAdbManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.widget.MasterSwitchPreference;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+/**
+ * This controls the master switch controller in the developer options page for
+ * "Wireless debugging".
+ */
+public class WirelessDebuggingPreferenceController extends DeveloperOptionsPreferenceController
+        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin,
+        LifecycleObserver, OnResume, OnPause {
+    private static final String TAG = "WirelessDebugPrefCtrl";
+    private final IAdbManager mAdbManager;
+    private final ContentResolver mContentResolver;
+    private final ContentObserver mSettingsObserver;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    public static final String KEY_TOGGLE_ADB_WIRELESS = "toggle_adb_wireless";
+
+    public WirelessDebuggingPreferenceController(Context context, Lifecycle lifecycle) {
+        super(context);
+
+        if (lifecycle != null) {
+            lifecycle.addObserver(this);
+        }
+        mAdbManager = IAdbManager.Stub.asInterface(ServiceManager.getService(Context.ADB_SERVICE));
+        mSettingsObserver = new ContentObserver(mHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                updateState(mPreference);
+            }
+        };
+        mContentResolver = context.getContentResolver();
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        try {
+            return mAdbManager.isAdbWifiSupported();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to check if adb wifi is supported.", e);
+        }
+
+        return false;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_TOGGLE_ADB_WIRELESS;
+    }
+
+    /**
+     * Called when developer options is enabled and the preference is available
+     */
+    @Override
+    protected void onDeveloperOptionsSwitchEnabled() {
+        super.onDeveloperOptionsSwitchEnabled();
+        mPreference.setEnabled(true);
+    }
+
+    /**
+     * Called when developer options is disabled and the preference is available
+     */
+    @Override
+    protected void onDeveloperOptionsSwitchDisabled() {
+        super.onDeveloperOptionsSwitchDisabled();
+        mPreference.setEnabled(false);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ADB_WIFI_ENABLED,
+                AdbPreferenceController.ADB_SETTING_OFF);
+    }
+
+    @Override
+    public void onResume() {
+        mContentResolver.registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED), false,
+                mSettingsObserver);
+    }
+
+    @Override
+    public void onPause() {
+        mContentResolver.unregisterContentObserver(mSettingsObserver);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        boolean enabled = Settings.Global.getInt(mContentResolver,
+                Settings.Global.ADB_WIFI_ENABLED, AdbPreferenceController.ADB_SETTING_OFF)
+                    != AdbPreferenceController.ADB_SETTING_OFF;
+        ((MasterSwitchPreference) preference).setChecked(enabled);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean enabled = (Boolean) newValue;
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ADB_WIFI_ENABLED,
+                enabled ? AdbPreferenceController.ADB_SETTING_ON
+                : AdbPreferenceController.ADB_SETTING_OFF);
+        return true;
+    }
+}
diff --git a/src/com/android/settings/development/graphicsdriver/GraphicsDriverAppPreferenceController.java b/src/com/android/settings/development/graphicsdriver/GraphicsDriverAppPreferenceController.java
index c1376a8..2013b45 100644
--- a/src/com/android/settings/development/graphicsdriver/GraphicsDriverAppPreferenceController.java
+++ b/src/com/android/settings/development/graphicsdriver/GraphicsDriverAppPreferenceController.java
@@ -26,7 +26,9 @@
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.SystemProperties;
 import android.provider.Settings;
+import android.text.TextUtils;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.ListPreference;
@@ -58,15 +60,19 @@
         GraphicsDriverContentObserver.OnGraphicsDriverContentChangedListener, LifecycleObserver,
         OnStart, OnStop {
 
+    private static final String PROPERTY_GFX_DRIVER_GAME = "ro.gfx.driver.0";
+    private static final String PROPERTY_GFX_DRIVER_PRERELEASE = "ro.gfx.driver.1";
+
     private final Context mContext;
     private final ContentResolver mContentResolver;
-    private final CharSequence[] mEntryList;
     private final String mPreferenceTitle;
     private final String mPreferenceDefault;
     private final String mPreferenceGameDriver;
     private final String mPreferencePrereleaseDriver;
     private final String mPreferenceSystem;
     @VisibleForTesting
+    CharSequence[] mEntryList;
+    @VisibleForTesting
     GraphicsDriverContentObserver mGraphicsDriverContentObserver;
 
     private final List<AppInfo> mAppInfos;
@@ -85,7 +91,6 @@
                 new GraphicsDriverContentObserver(new Handler(Looper.getMainLooper()), this);
 
         final Resources resources = context.getResources();
-        mEntryList = resources.getStringArray(R.array.graphics_driver_app_preference_values);
         mPreferenceTitle = resources.getString(R.string.graphics_driver_app_preference_title);
         mPreferenceDefault = resources.getString(R.string.graphics_driver_app_preference_default);
         mPreferenceGameDriver =
@@ -93,6 +98,7 @@
         mPreferencePrereleaseDriver =
                 resources.getString(R.string.graphics_driver_app_preference_prerelease_driver);
         mPreferenceSystem = resources.getString(R.string.graphics_driver_app_preference_system);
+        mEntryList = constructEntryList();
 
         // TODO: Move this task to background if there's potential ANR/Jank.
         // Update the UI when all the app infos are ready.
@@ -189,6 +195,28 @@
         updateState(mPreferenceGroup);
     }
 
+    /**
+     * Constructs and returns a list of graphics driver choices.
+     */
+    public CharSequence[] constructEntryList() {
+        final String prereleaseDriverPackageName =
+                SystemProperties.get(PROPERTY_GFX_DRIVER_PRERELEASE);
+        final String gameDriverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER_GAME);
+
+        List<CharSequence> entryList = new ArrayList<>();
+        entryList.add(mPreferenceDefault);
+        if (!TextUtils.isEmpty(prereleaseDriverPackageName)) {
+            entryList.add(mPreferencePrereleaseDriver);
+        }
+        if (!TextUtils.isEmpty(gameDriverPackageName)) {
+            entryList.add(mPreferenceGameDriver);
+        }
+        entryList.add(mPreferenceSystem);
+        CharSequence[] filteredEntryList = new CharSequence[entryList.size()];
+        filteredEntryList = entryList.toArray(filteredEntryList);
+        return filteredEntryList;
+    }
+
     // AppInfo class to achieve loading the application label only once
     class AppInfo {
         AppInfo(PackageManager packageManager, ApplicationInfo applicationInfo) {
diff --git a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java
index 7f85f7d..8faae30 100644
--- a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java
+++ b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java
@@ -17,8 +17,12 @@
 
 import android.Manifest;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.provider.Settings;
+import android.service.attention.AttentionService;
+import android.text.TextUtils;
 
 import com.android.settings.R;
 import com.android.settings.core.TogglePreferenceController;
@@ -62,10 +66,24 @@
     public static int isControllerAvailable(Context context) {
         return context.getResources().getBoolean(
                 com.android.internal.R.bool.config_adaptive_sleep_available)
+                && isAttentionServiceAvailable(context)
                 ? AVAILABLE_UNSEARCHABLE
                 : UNSUPPORTED_ON_DEVICE;
     }
 
+    private static boolean isAttentionServiceAvailable(Context context) {
+        final PackageManager packageManager = context.getPackageManager();
+        final String resolvePackage = packageManager.getAttentionServicePackageName();
+        if (TextUtils.isEmpty(resolvePackage)) {
+            return false;
+        }
+        final Intent intent = new Intent(AttentionService.SERVICE_INTERFACE).setPackage(
+                resolvePackage);
+        final ResolveInfo resolveInfo = packageManager.resolveService(intent,
+                PackageManager.MATCH_SYSTEM_ONLY);
+        return resolveInfo != null && resolveInfo.serviceInfo != null;
+    }
+
     static boolean hasSufficientPermission(PackageManager packageManager) {
         final String attentionPackage = packageManager.getAttentionServicePackageName();
         return attentionPackage != null && packageManager.checkPermission(
diff --git a/src/com/android/settings/homepage/contextualcards/CardContentProvider.java b/src/com/android/settings/homepage/contextualcards/CardContentProvider.java
index a9a832d..9627eb0 100644
--- a/src/com/android/settings/homepage/contextualcards/CardContentProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/CardContentProvider.java
@@ -48,7 +48,7 @@
     public static final Uri DELETE_CARD_URI = new Uri.Builder()
             .scheme(ContentResolver.SCHEME_CONTENT)
             .authority(CardContentProvider.CARD_AUTHORITY)
-            .appendPath(CardDatabaseHelper.CardColumns.CARD_DISMISSED)
+            .appendPath(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP)
             .build();
 
     private static final String TAG = "CardContentProvider";
diff --git a/src/com/android/settings/homepage/contextualcards/CardDatabaseHelper.java b/src/com/android/settings/homepage/contextualcards/CardDatabaseHelper.java
index 8c471b0..5af0ca6 100644
--- a/src/com/android/settings/homepage/contextualcards/CardDatabaseHelper.java
+++ b/src/com/android/settings/homepage/contextualcards/CardDatabaseHelper.java
@@ -16,9 +16,7 @@
 
 package com.android.settings.homepage.contextualcards;
 
-import android.content.ContentValues;
 import android.content.Context;
-import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.util.Log;
@@ -31,7 +29,7 @@
 public class CardDatabaseHelper extends SQLiteOpenHelper {
     private static final String TAG = "CardDatabaseHelper";
     private static final String DATABASE_NAME = "homepage_cards.db";
-    private static final int DATABASE_VERSION = 6;
+    private static final int DATABASE_VERSION = 7;
 
     public static final String CARD_TABLE = "cards";
 
@@ -72,31 +70,32 @@
         String APP_VERSION = "app_version";
 
         /**
-         * Decide the card is dismissed or not.
+         * Timestamp of card being dismissed.
          */
-        String CARD_DISMISSED = "card_dismissed";
+        String DISMISSED_TIMESTAMP = "dismissed_timestamp";
     }
 
     private static final String CREATE_CARD_TABLE =
-            "CREATE TABLE " + CARD_TABLE +
-                    "(" +
-                    CardColumns.NAME +
-                    " TEXT NOT NULL PRIMARY KEY, " +
-                    CardColumns.TYPE +
-                    " INTEGER NOT NULL, " +
-                    CardColumns.SCORE +
-                    " DOUBLE NOT NULL, " +
-                    CardColumns.SLICE_URI +
-                    " TEXT, " +
-                    CardColumns.CATEGORY +
-                    " INTEGER DEFAULT 0, " +
-                    CardColumns.PACKAGE_NAME +
-                    " TEXT NOT NULL, " +
-                    CardColumns.APP_VERSION +
-                    " INTEGER NOT NULL, " +
-                    CardColumns.CARD_DISMISSED +
-                    " INTEGER DEFAULT 0 " +
-                    ");";
+            "CREATE TABLE "
+                    + CARD_TABLE
+                    + "("
+                    + CardColumns.NAME
+                    + " TEXT NOT NULL PRIMARY KEY, "
+                    + CardColumns.TYPE
+                    + " INTEGER NOT NULL, "
+                    + CardColumns.SCORE
+                    + " DOUBLE NOT NULL, "
+                    + CardColumns.SLICE_URI
+                    + " TEXT, "
+                    + CardColumns.CATEGORY
+                    + " INTEGER DEFAULT 0, "
+                    + CardColumns.PACKAGE_NAME
+                    + " TEXT NOT NULL, "
+                    + CardColumns.APP_VERSION
+                    + " INTEGER NOT NULL, "
+                    + CardColumns.DISMISSED_TIMESTAMP
+                    + " INTEGER"
+                    + ");";
 
     public CardDatabaseHelper(Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -125,32 +124,4 @@
         }
         return sCardDatabaseHelper;
     }
-
-    Cursor getContextualCards() {
-        final SQLiteDatabase db = getReadableDatabase();
-        final String selection = CardColumns.CARD_DISMISSED + "=0";
-        return db.query(CARD_TABLE, null /* columns */, selection,
-                null /* selectionArgs */, null /* groupBy */, null /* having */,
-                CardColumns.SCORE + " DESC" /* orderBy */);
-    }
-
-    /**
-     * Mark a specific ContextualCard with dismissal flag in the database to indicate that the
-     * card has been dismissed.
-     *
-     * @param context  Context
-     * @param cardName The card name of the ContextualCard which is dismissed by user.
-     * @return The number of rows updated
-     */
-    public int markContextualCardAsDismissed(Context context, String cardName) {
-        final SQLiteDatabase database = getWritableDatabase();
-        final ContentValues values = new ContentValues();
-        values.put(CardColumns.CARD_DISMISSED, 1);
-        final String selection = CardColumns.NAME + "=?";
-        final String[] selectionArgs = {cardName};
-        final int rowsUpdated = database.update(CARD_TABLE, values, selection, selectionArgs);
-        database.close();
-        context.getContentResolver().notifyChange(CardContentProvider.DELETE_CARD_URI, null);
-        return rowsUpdated;
-    }
 }
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
index bdf863e..60bffde 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
@@ -16,10 +16,25 @@
 
 package com.android.settings.homepage.contextualcards;
 
+import android.content.Context;
+import android.database.Cursor;
+
 import androidx.slice.Slice;
 
 /** Feature provider for the contextual card feature. */
 public interface ContextualCardFeatureProvider {
+    /** Get contextual cards from the card provider */
+    Cursor getContextualCards();
+
+    /**
+     * Mark a specific {@link ContextualCard} as dismissed with dismissal signal in the database
+     * to indicate that the card has been dismissed.
+     *
+     * @param context  Context
+     * @param cardName The card name of the ContextualCard which is dismissed by user.
+     * @return The number of rows updated
+     */
+    int markCardAsDismissed(Context context, String cardName);
 
     /** Log package when user clicks contextual notification channel card. */
     void logNotificationPackage(Slice slice);
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
index 4af2838..f4bb84c 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
@@ -18,10 +18,19 @@
 
 import static android.content.Context.MODE_PRIVATE;
 
+import static com.android.settings.homepage.contextualcards.CardDatabaseHelper.CARD_TABLE;
+
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Build;
+import android.text.format.DateUtils;
 import android.util.ArraySet;
+import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.slice.Slice;
 import androidx.slice.SliceMetadata;
 import androidx.slice.core.SliceAction;
@@ -30,10 +39,13 @@
 import com.android.settings.applications.AppInfoBase;
 import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice;
 import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settingslib.utils.ThreadUtils;
 
 import java.util.Set;
 
 public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureProvider {
+    private static final String TAG = "ContextualCardFeatureProvider";
+
     private final Context mContext;
 
     public ContextualCardFeatureProviderImpl(Context context) {
@@ -41,6 +53,33 @@
     }
 
     @Override
+    public Cursor getContextualCards() {
+        final SQLiteDatabase db = CardDatabaseHelper.getInstance(mContext).getReadableDatabase();
+        //TODO(b/149542061): Make the dismissal duration configurable.
+        final long threshold = System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS;
+        final String selection = CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP + " < ? OR "
+                + CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP + " IS NULL";
+        final String[] selectionArgs = {String.valueOf(threshold)};
+        final Cursor cursor = db.query(CARD_TABLE, null /* columns */, selection,
+                selectionArgs /* selectionArgs */, null /* groupBy */, null /* having */,
+                CardDatabaseHelper.CardColumns.SCORE + " DESC" /* orderBy */);
+        ThreadUtils.postOnBackgroundThread(() -> resetDismissedTime(threshold));
+        return cursor;
+    }
+
+    @Override
+    public int markCardAsDismissed(Context context, String cardName) {
+        final SQLiteDatabase db = CardDatabaseHelper.getInstance(mContext).getWritableDatabase();
+        final ContentValues values = new ContentValues();
+        values.put(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP, System.currentTimeMillis());
+        final String selection = CardDatabaseHelper.CardColumns.NAME + "=?";
+        final String[] selectionArgs = {cardName};
+        final int rowsUpdated = db.update(CARD_TABLE, values, selection, selectionArgs);
+        context.getContentResolver().notifyChange(CardContentProvider.DELETE_CARD_URI, null);
+        return rowsUpdated;
+    }
+
+    @Override
     public void logNotificationPackage(Slice slice) {
         if (slice == null || !slice.getUri().equals(
                 CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI)) {
@@ -62,4 +101,20 @@
         prefs.edit().putStringSet(ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES,
                 newInteractedPackages).apply();
     }
+
+    @VisibleForTesting
+    int resetDismissedTime(long threshold) {
+        final SQLiteDatabase database =
+                CardDatabaseHelper.getInstance(mContext).getWritableDatabase();
+        final ContentValues values = new ContentValues();
+        values.putNull(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP);
+        final String selection = CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP + " < ? AND "
+                + CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP + " IS NOT NULL";
+        final String[] selectionArgs = {String.valueOf(threshold)};
+        final int rowsUpdated = database.update(CARD_TABLE, values, selection, selectionArgs);
+        if (Build.IS_DEBUGGABLE) {
+            Log.d(TAG, "Reset " + rowsUpdated + " records of dismissed time.");
+        }
+        return rowsUpdated;
+    }
 }
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 1c83a10..886a12d 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -178,7 +178,9 @@
 
     @VisibleForTesting
     Cursor getContextualCardsFromProvider() {
-        return CardDatabaseHelper.getInstance(mContext).getContextualCards();
+        final ContextualCardFeatureProvider cardFeatureProvider =
+                FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
+        return cardFeatureProvider.getContextualCards();
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
index 9eb7fae..ced3f8d 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
@@ -25,9 +25,9 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.R;
-import com.android.settings.homepage.contextualcards.CardDatabaseHelper;
 import com.android.settings.homepage.contextualcards.ContextualCard;
 import com.android.settings.homepage.contextualcards.ContextualCardController;
+import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
 import com.android.settings.homepage.contextualcards.ContextualCardFeedbackDialog;
 import com.android.settings.homepage.contextualcards.ContextualCardUpdateListener;
 import com.android.settings.homepage.contextualcards.logging.ContextualCardLogUtils;
@@ -68,8 +68,9 @@
     @Override
     public void onDismissed(ContextualCard card) {
         ThreadUtils.postOnBackgroundThread(() -> {
-            final CardDatabaseHelper dbHelper = CardDatabaseHelper.getInstance(mContext);
-            dbHelper.markContextualCardAsDismissed(mContext, card.getName());
+            final ContextualCardFeatureProvider cardFeatureProvider =
+                    FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
+            cardFeatureProvider.markCardAsDismissed(mContext, card.getName());
         });
         showFeedbackDialog(card);
 
diff --git a/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceController.java b/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceController.java
index b6a78a1..44187e4 100644
--- a/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceController.java
+++ b/src/com/android/settings/network/telephony/DeleteSimProfilePreferenceController.java
@@ -21,6 +21,7 @@
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
 import android.telephony.euicc.EuiccManager;
+import android.text.TextUtils;
 
 import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
@@ -60,19 +61,23 @@
 
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
-        boolean confirmDeletion =
-                Settings.Global.getInt(
-                                mContext.getContentResolver(),
-                                ConfirmSimDeletionPreferenceController.KEY_CONFIRM_SIM_DELETION,
-                                mConfirmationDefaultOn ? 1 : 0)
-                        == 1;
-        if (confirmDeletion) {
-            WifiDppUtils.showLockScreen(mContext, () -> deleteSim());
-        } else {
-            deleteSim();
+        if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            boolean confirmDeletion =
+                    Settings.Global.getInt(
+                            mContext.getContentResolver(),
+                            ConfirmSimDeletionPreferenceController.KEY_CONFIRM_SIM_DELETION,
+                            mConfirmationDefaultOn ? 1 : 0)
+                            == 1;
+            if (confirmDeletion) {
+                WifiDppUtils.showLockScreen(mContext, () -> deleteSim());
+            } else {
+                deleteSim();
+            }
+
+            return true;
         }
 
-        return true;
+        return false;
     }
 
     private void deleteSim() {
diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java
index 9b78ae9..9f8a07f 100644
--- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java
+++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java
@@ -51,6 +51,7 @@
 import com.android.settings.notification.NotificationBackend;
 import com.android.settings.widget.SwitchBar;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 
 public class NotificationHistoryActivity extends Activity {
@@ -252,7 +253,7 @@
                 rv.setNestedScrollingEnabled(false);
 
                 ((NotificationSbnAdapter) rv.getAdapter()).onRebuildComplete(
-                        Arrays.asList(snoozed));
+                        new ArrayList<>(Arrays.asList(snoozed)));
             }
 
             try {
@@ -268,7 +269,7 @@
                 rv.setNestedScrollingEnabled(false);
 
                 ((NotificationSbnAdapter) rv.getAdapter()).onRebuildComplete(
-                        Arrays.asList(dismissed));
+                        new ArrayList<>(Arrays.asList(dismissed)));
                 mDismissView.setVisibility(View.VISIBLE);
             } catch (Exception e) {
                 Slog.e(TAG, "Cannot load recently dismissed", e);
diff --git a/src/com/android/settings/notification/history/NotificationSbnAdapter.java b/src/com/android/settings/notification/history/NotificationSbnAdapter.java
index a35b5d4..f1dcf47 100644
--- a/src/com/android/settings/notification/history/NotificationSbnAdapter.java
+++ b/src/com/android/settings/notification/history/NotificationSbnAdapter.java
@@ -17,6 +17,8 @@
 package com.android.settings.notification.history;
 
 import static android.content.pm.PackageManager.*;
+import static android.os.UserHandle.USER_ALL;
+import static android.os.UserHandle.USER_CURRENT;
 
 import android.app.Notification;
 import android.content.Context;
@@ -77,12 +79,13 @@
             holder.setTitle(getTitleString(sbn.getNotification()));
             holder.setSummary(getTextString(mContext, sbn.getNotification()));
             holder.setPostedTime(sbn.getPostTime());
-            if (!mUserBadgeCache.containsKey(sbn.getUserId())) {
+            int userId = normalizeUserId(sbn);
+            if (!mUserBadgeCache.containsKey(userId)) {
                 Drawable profile = mContext.getPackageManager().getUserBadgeForDensity(
-                        UserHandle.of(sbn.getUserId()), -1);
-                mUserBadgeCache.put(sbn.getUserId(), profile);
+                        UserHandle.of(userId), -1);
+                mUserBadgeCache.put(userId, profile);
             }
-            holder.setProfileBadge(mUserBadgeCache.get(sbn.getUserId()));
+            holder.setProfileBadge(mUserBadgeCache.get(userId));
         } else {
             Slog.w(TAG, "null entry in list at position " + position);
         }
@@ -153,7 +156,7 @@
 
     private Drawable loadIcon(StatusBarNotification sbn) {
         Drawable draw = sbn.getNotification().getSmallIcon().loadDrawableAsUser(
-                sbn.getPackageContext(mContext), sbn.getUserId());
+                sbn.getPackageContext(mContext), normalizeUserId(sbn));
         if (draw == null) {
             return null;
         }
@@ -161,4 +164,12 @@
         draw.setColorFilter(sbn.getNotification().color, PorterDuff.Mode.SRC_ATOP);
         return draw;
     }
+
+    private int normalizeUserId(StatusBarNotification sbn) {
+        int userId = sbn.getUserId();
+        if (userId == USER_ALL) {
+            userId = USER_CURRENT;
+        }
+        return userId;
+    }
 }
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
index 4422204..262a550 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
@@ -37,6 +37,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
@@ -57,7 +58,7 @@
  * Base fragment to be shared for PIN/Pattern/Password confirmation fragments.
  */
 public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFragment {
-
+    public static final String TAG = ConfirmDeviceCredentialBaseFragment.class.getSimpleName();
     public static final String TITLE_TEXT = SETTINGS_PACKAGE_NAME + ".ConfirmCredentials.title";
     public static final String HEADER_TEXT = SETTINGS_PACKAGE_NAME + ".ConfirmCredentials.header";
     public static final String DETAILS_TEXT = SETTINGS_PACKAGE_NAME + ".ConfirmCredentials.details";
@@ -78,7 +79,8 @@
 
     protected boolean mReturnCredentials = false;
     protected Button mCancelButton;
-    protected Button mForgotButton;
+    /** Button allowing managed profile password reset, null when is not shown. */
+    @Nullable protected Button mForgotButton;
     protected int mEffectiveUserId;
     protected int mUserId;
     protected UserManager mUserManager;
@@ -133,10 +135,18 @@
             }
             getActivity().finish();
         });
-        mForgotButton = view.findViewById(R.id.forgotButton);
+        setupForgotButtonIfManagedProfile(view);
+    }
+
+    private void setupForgotButtonIfManagedProfile(View view) {
         if (mUserManager.isManagedProfile(mUserId)
                 && mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))
                 && mDevicePolicyManager.canProfileOwnerResetPasswordWhenLocked(mUserId)) {
+            mForgotButton = view.findViewById(R.id.forgotButton);
+            if (mForgotButton == null) {
+                Log.wtf(TAG, "Forgot button not found in managed profile credential dialog");
+                return;
+            }
             mForgotButton.setVisibility(View.VISIBLE);
             mForgotButton.setOnClickListener(v -> {
                 final Intent intent = new Intent();
@@ -145,8 +155,6 @@
                 getActivity().startActivity(intent);
                 getActivity().finish();
             });
-        } else {
-            mForgotButton.setVisibility(View.GONE);
         }
     }
 
diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java
index d77fd3a..ce8813f 100644
--- a/src/com/android/settings/password/ConfirmLockPassword.java
+++ b/src/com/android/settings/password/ConfirmLockPassword.java
@@ -267,7 +267,9 @@
             mHeaderTextView.setAlpha(0f);
             mDetailsTextView.setAlpha(0f);
             mCancelButton.setAlpha(0f);
-            mForgotButton.setAlpha(0f);
+            if (mForgotButton != null) {
+                mForgotButton.setAlpha(0f);
+            }
             mPasswordEntry.setAlpha(0f);
             mErrorTextView.setAlpha(0f);
         }
@@ -279,7 +281,7 @@
             if (mCancelButton.getVisibility() == View.VISIBLE) {
                 result.add(mCancelButton);
             }
-            if (mForgotButton.getVisibility() == View.VISIBLE) {
+            if (mForgotButton != null) {
                 result.add(mForgotButton);
             }
             result.add(mPasswordEntry);
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index fd164b8..b2afb22 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -240,7 +240,9 @@
             super.prepareEnterAnimation();
             mHeaderTextView.setAlpha(0f);
             mCancelButton.setAlpha(0f);
-            mForgotButton.setAlpha(0f);
+            if (mForgotButton != null) {
+                mForgotButton.setAlpha(0f);
+            }
             mLockPatternView.setAlpha(0f);
             mDetailsTextView.setAlpha(0f);
         }
@@ -268,7 +270,7 @@
             if (mCancelButton.getVisibility() == View.VISIBLE) {
                 result.add(new ArrayList<>(Collections.singletonList(mCancelButton)));
             }
-            if (mForgotButton.getVisibility() == View.VISIBLE) {
+            if (mForgotButton != null) {
                 result.add(new ArrayList<>(Collections.singletonList(mForgotButton)));
             }
             LockPatternView.CellState[][] cellStates = mLockPatternView.getCellStates();
diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java
index 8e3d9bb..8280a3d 100644
--- a/src/com/android/settings/vpn2/AppManagementFragment.java
+++ b/src/com/android/settings/vpn2/AppManagementFragment.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.app.Dialog;
+import android.app.admin.DevicePolicyManager;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -48,6 +49,8 @@
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedPreference;
 import com.android.settingslib.RestrictedSwitchPreference;
 
@@ -67,6 +70,7 @@
     private static final String KEY_FORGET_VPN = "forget_vpn";
 
     private PackageManager mPackageManager;
+    private DevicePolicyManager mDevicePolicyManager;
     private ConnectivityManager mConnectivityManager;
     private IConnectivityManager mConnectivityService;
 
@@ -119,6 +123,7 @@
         addPreferencesFromResource(R.xml.vpn_app_management);
 
         mPackageManager = getContext().getPackageManager();
+        mDevicePolicyManager = getContext().getSystemService(DevicePolicyManager.class);
         mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
         mConnectivityService = IConnectivityManager.Stub
                 .asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
@@ -250,6 +255,15 @@
             mPreferenceForget.checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN,
                     mUserId);
 
+            if (mPackageName.equals(mDevicePolicyManager.getAlwaysOnVpnPackage())) {
+                EnforcedAdmin admin = RestrictedLockUtils.getProfileOrDeviceOwner(
+                        getContext(), UserHandle.of(mUserId));
+                mPreferenceAlwaysOn.setDisabledByAdmin(admin);
+                mPreferenceForget.setDisabledByAdmin(admin);
+                if (mDevicePolicyManager.isAlwaysOnVpnLockdownEnabled()) {
+                    mPreferenceLockdown.setDisabledByAdmin(admin);
+                }
+            }
             if (mConnectivityManager.isAlwaysOnVpnPackageSupportedForUser(mUserId, mPackageName)) {
                 // setSummary doesn't override the admin message when user restriction is applied
                 mPreferenceAlwaysOn.setSummary(R.string.vpn_always_on_summary);
diff --git a/src/com/android/settings/wifi/dpp/AdbQrCode.java b/src/com/android/settings/wifi/dpp/AdbQrCode.java
new file mode 100644
index 0000000..fb63e0a
--- /dev/null
+++ b/src/com/android/settings/wifi/dpp/AdbQrCode.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 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.dpp;
+
+import android.text.TextUtils;
+
+/**
+ * Extension of WifiQrCode to support ADB QR code format.
+ * It will be based on the ZXing format:
+ *
+ * WIFI:T:ADB;S:myname;P:mypassword;;
+ */
+public class AdbQrCode extends WifiQrCode {
+    static final String SECURITY_ADB = "ADB";
+
+    private WifiNetworkConfig mAdbConfig;
+
+    public AdbQrCode(String qrCode) throws IllegalArgumentException {
+        super(qrCode);
+
+        // Only accept the zxing format.
+        if (!WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(getScheme())) {
+            throw new IllegalArgumentException("DPP format not supported for ADB QR code");
+        }
+
+        mAdbConfig = getWifiNetworkConfig();
+        if (!SECURITY_ADB.equals(mAdbConfig.getSecurity())) {
+            throw new IllegalArgumentException("Invalid security type");
+        }
+
+        if (TextUtils.isEmpty(mAdbConfig.getSsid())) {
+            throw new IllegalArgumentException("Empty service name");
+        }
+
+        if (TextUtils.isEmpty(mAdbConfig.getPreSharedKey())) {
+            throw new IllegalArgumentException("Empty password");
+        }
+    }
+
+    public WifiNetworkConfig getAdbNetworkConfig() {
+        return mAdbConfig;
+    }
+}
diff --git a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
index 89ead9d..111126f 100644
--- a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
+++ b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
@@ -52,7 +52,7 @@
     @VisibleForTesting
     static long sActiveUiSession = -1000;
     @VisibleForTesting
-    static boolean sToggleNeeded = true;
+    static boolean sApRowCollapsed;
 
     public ContextualWifiSlice(Context context) {
         super(context);
@@ -69,26 +69,26 @@
                 .getSlicesFeatureProvider().getUiSessionToken();
         if (currentUiSession != sActiveUiSession) {
             sActiveUiSession = currentUiSession;
-            sToggleNeeded = !hasWorkingNetwork();
+            sApRowCollapsed = hasWorkingNetwork();
         } else if (!mWifiManager.isWifiEnabled()) {
-            sToggleNeeded = true;
+            sApRowCollapsed = false;
         }
         return super.getSlice();
     }
 
     static int getApRowCount() {
-        return sToggleNeeded ? DEFAULT_EXPANDED_ROW_COUNT : COLLAPSED_ROW_COUNT;
+        return sApRowCollapsed ? COLLAPSED_ROW_COUNT : DEFAULT_EXPANDED_ROW_COUNT;
     }
 
     @Override
-    protected boolean isToggleNeeded() {
-        return sToggleNeeded;
+    protected boolean isApRowCollapsed() {
+        return sApRowCollapsed;
     }
 
     @Override
     protected ListBuilder.RowBuilder getHeaderRow(AccessPoint accessPoint) {
         final ListBuilder.RowBuilder builder = super.getHeaderRow(accessPoint);
-        if (!sToggleNeeded) {
+        if (sApRowCollapsed) {
             builder.setTitleItem(getLevelIcon(accessPoint), ListBuilder.ICON_IMAGE)
                     .setSubtitle(getSubtitle(accessPoint));
         }
diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java
index 8e2d7a6..fe1da73 100644
--- a/src/com/android/settings/wifi/slice/WifiSlice.java
+++ b/src/com/android/settings/wifi/slice/WifiSlice.java
@@ -107,7 +107,7 @@
         final boolean isFirstApActive = apCount > 0 && apList.get(0).isActive();
         handleNetworkCallback(worker, isFirstApActive);
 
-        if (!isToggleNeeded()) {
+        if (isApRowCollapsed()) {
             if (isFirstApActive) {
                 // refresh header subtext
                 listBuilder = getListBuilder(true /* isWifiEnabled */, apList.get(0));
@@ -142,8 +142,8 @@
         }
     }
 
-    protected boolean isToggleNeeded() {
-        return true;
+    protected boolean isApRowCollapsed() {
+        return false;
     }
 
     protected ListBuilder.RowBuilder getHeaderRow(AccessPoint accessPoint) {
@@ -160,15 +160,14 @@
     }
 
     private ListBuilder getListBuilder(boolean isWifiEnabled, AccessPoint accessPoint) {
+        final PendingIntent toggleAction = getBroadcastIntent(mContext);
+        final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction,
+                null /* actionTitle */, isWifiEnabled);
         final ListBuilder builder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
                 .setAccentColor(COLOR_NOT_TINTED)
                 .setKeywords(getKeywords())
-                .addRow(getHeaderRow(accessPoint));
-        if (isToggleNeeded()) {
-            final PendingIntent toggleAction = getBroadcastIntent(mContext);
-            builder.addAction(SliceAction.createToggle(toggleAction, null /* actionTitle */,
-                    isWifiEnabled));
-        }
+                .addRow(getHeaderRow(accessPoint))
+                .addAction(toggleSliceAction);
         return builder;
     }
 
diff --git a/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java
new file mode 100644
index 0000000..6145939
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/EnableVerboseVendorLoggingPreferenceControllerTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.dumpstate.V1_1.IDumpstateDevice;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.lang.reflect.Field;
+
+@RunWith(RobolectricTestRunner.class)
+public final class EnableVerboseVendorLoggingPreferenceControllerTest {
+    @Mock
+    private SwitchPreference mPreference;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+    @Mock
+    IDumpstateDevice mIDumpstateDevice;
+
+    private Context mContext;
+    private EnableVerboseVendorLoggingPreferenceController mController;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mController = spy(new EnableVerboseVendorLoggingPreferenceController(mContext));
+        doReturn(mIDumpstateDevice).when(mController).getDumpstateDeviceService();
+
+        // mock with Dumpstate HAL v1.1
+        Field f = EnableVerboseVendorLoggingPreferenceController.class
+                .getDeclaredField("mDumpstateHalVersion");
+        f.setAccessible(true);
+        f.setInt(mController, 1 /* DUMPSTATE_HAL_VERSION_1_1 */);
+
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+                .thenReturn(mPreference);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void onPreferenceChange_settingEnable_enableVendorLoggingShouldBeOn() throws Exception {
+        doReturn(true).when(mIDumpstateDevice).getVerboseLoggingEnabled();
+
+        mController.onPreferenceChange(mPreference, true /* new value */);
+
+        final boolean enabled = mController.getVerboseLoggingEnabled();
+        assertTrue(enabled);
+    }
+
+    @Test
+    public void onPreferenceChange_settingDisable_enableVendorLoggingShouldBeOff()
+            throws Exception {
+        doReturn(false).when(mIDumpstateDevice).getVerboseLoggingEnabled();
+
+        mController.onPreferenceChange(mPreference,  false /* new value */);
+
+        final boolean enabled = mController.getVerboseLoggingEnabled();
+        assertFalse(enabled);
+    }
+
+    @Test
+    public void updateState_settingDisabled_preferenceShouldNotBeChecked() throws Exception {
+        doReturn(false).when(mIDumpstateDevice).getVerboseLoggingEnabled();
+
+        mController.setVerboseLoggingEnabled(false);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(false);
+    }
+
+    @Test
+    public void updateState_settingEnabled_preferenceShouldBeChecked() throws Exception {
+        doReturn(true).when(mIDumpstateDevice).getVerboseLoggingEnabled();
+
+        mController.setVerboseLoggingEnabled(true);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(true);
+    }
+
+    @Test
+    public void onDeveloperOptionDisabled_shouldDisablePreference() throws Exception {
+        doReturn(false).when(mIDumpstateDevice).getVerboseLoggingEnabled();
+
+        mController.onDeveloperOptionsSwitchDisabled();
+
+        final boolean enabled = mController.getVerboseLoggingEnabled();
+        assertFalse(enabled);
+        verify(mPreference).setChecked(false);
+        verify(mPreference).setEnabled(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/EnhancedConnectivityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/EnhancedConnectivityPreferenceControllerTest.java
new file mode 100644
index 0000000..6fd6f55
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/EnhancedConnectivityPreferenceControllerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class EnhancedConnectivityPreferenceControllerTest {
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private SwitchPreference mPreference;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+
+    private EnhancedConnectivityPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new EnhancedConnectivityPreferenceController(mContext);
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+                .thenReturn(mPreference);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void onPreferenceChanged_enhanceConnectivity_shouldBeOn() {
+        mController.onPreferenceChange(mPreference, true /* new value */);
+
+        assertThat(isSettingEnabled()).isTrue();
+    }
+
+    @Test
+    public void onPreferenceChanged_enhanceConnectivity_shouldBeOff() {
+        mController.onPreferenceChange(mPreference, false /* new value */);
+
+        assertThat(isSettingEnabled()).isFalse();
+    }
+
+    @Test
+    public void updateState_preferenceShouldBeChecked() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ENHANCED_CONNECTIVITY_ENABLED, 1 /* enabled */);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(true);
+    }
+
+    @Test
+    public void updateState_preferenceShouldNotBeChecked() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ENHANCED_CONNECTIVITY_ENABLED, 0 /* disabled */);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(false);
+    }
+
+    @Test
+    public void onDeveloperOptionsDisabled_shouldDisablePreference() {
+        mController.onDeveloperOptionsDisabled();
+
+        verify(mPreference).setEnabled(false);
+        verify(mPreference).setChecked(false);
+
+        assertThat(isSettingEnabled()).isFalse();
+    }
+
+    private boolean isSettingEnabled() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.ENHANCED_CONNECTIVITY_ENABLED,
+                EnhancedConnectivityPreferenceController.ENHANCED_CONNECTIVITY_OFF
+                /* default off */)
+                == EnhancedConnectivityPreferenceController.ENHANCED_CONNECTIVITY_ON;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/WirelessDebuggingEnablerTest.java b/tests/robotests/src/com/android/settings/development/WirelessDebuggingEnablerTest.java
new file mode 100644
index 0000000..7f4f530
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/WirelessDebuggingEnablerTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.provider.Settings.Global;
+
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settings.widget.SwitchBar;
+import com.android.settings.widget.SwitchBarController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowUtils.class)
+public class WirelessDebuggingEnablerTest {
+
+    @Mock
+    private SettingsActivity mActivity;
+    @Mock
+    private SwitchBar mSwitchBar;
+    @Mock
+    private WirelessDebuggingEnabler.OnEnabledListener mListener;
+
+    private WirelessDebuggingEnabler mWirelessDebuggingEnabler;
+    private Context mContext;
+    private LifecycleOwner mLifecycleOwner;
+    private Lifecycle mLifecycle;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
+        mWirelessDebuggingEnabler = spy(new WirelessDebuggingEnabler(
+                mContext, new SwitchBarController(mSwitchBar), mListener, mLifecycle));
+    }
+
+    @Test
+    public void onCreation_shouldShowSwitchBar() {
+        verify(mSwitchBar).show();
+    }
+
+    @Test
+    public void teardownSwitchController_shouldHideSwitchBar() {
+        mWirelessDebuggingEnabler.teardownSwitchController();
+
+        verify(mSwitchBar).hide();
+    }
+
+    @Test
+    public void adbWifiEnabled_switchBarShouldBeChecked() {
+        // Set to disabled first otherwise we won't get the onChange() event
+        Global.putInt(mContext.getContentResolver(),
+                Global.ADB_WIFI_ENABLED, 0 /* setting disabled */);
+        mWirelessDebuggingEnabler.onResume();
+
+        verify(mSwitchBar).setChecked(false);
+        verify(mListener).onEnabled(false);
+
+        Global.putInt(mContext.getContentResolver(),
+                Global.ADB_WIFI_ENABLED, 1 /* setting enabled */);
+        final ContentObserver observer =
+                ReflectionHelpers.getField(mWirelessDebuggingEnabler, "mSettingsObserver");
+        observer.onChange(true, Global.getUriFor(Global.ADB_WIFI_ENABLED));
+
+        verify(mSwitchBar).setChecked(true);
+        // Should also get a callback
+        verify(mListener).onEnabled(true);
+    }
+
+    @Test
+    public void adbWifiEnabled_switchBarShouldNotBeChecked() {
+        Global.putInt(mContext.getContentResolver(),
+                Global.ADB_WIFI_ENABLED, 1 /* setting enabled */);
+        mWirelessDebuggingEnabler.onResume();
+
+        verify(mSwitchBar).setChecked(true);
+        verify(mListener).onEnabled(true);
+
+        Global.putInt(mContext.getContentResolver(),
+                Global.ADB_WIFI_ENABLED, 0 /* setting disabled */);
+        final ContentObserver observer =
+                ReflectionHelpers.getField(mWirelessDebuggingEnabler, "mSettingsObserver");
+        observer.onChange(true, Global.getUriFor(Global.ADB_WIFI_ENABLED));
+
+        verify(mSwitchBar).setChecked(false);
+        // Should also get a callback
+        verify(mListener).onEnabled(false);
+    }
+
+    @Test
+    public void onSwitchToggled_true_shouldSetAdbWifiEnabledTrue() {
+        Global.putInt(mContext.getContentResolver(),
+                Global.ADB_WIFI_ENABLED, 0 /* setting disabled */);
+        mWirelessDebuggingEnabler.onResume();
+
+        verify(mSwitchBar).setChecked(false);
+        verify(mListener).onEnabled(false);
+
+        mWirelessDebuggingEnabler.onSwitchToggled(true);
+
+        verify(mSwitchBar).setChecked(true);
+        verify(mListener).onEnabled(true);
+        assertThat(Global.getInt(mContext.getContentResolver(),
+                Global.ADB_WIFI_ENABLED, -1)).isEqualTo(1);
+        // Should also get a callback
+    }
+
+    @Test
+    public void onSwitchToggled_false_shouldSetAdbWifiEnabledFalse() {
+        Global.putInt(mContext.getContentResolver(),
+                Global.ADB_WIFI_ENABLED, 1 /* setting disabled */);
+        mWirelessDebuggingEnabler.onResume();
+
+        verify(mSwitchBar).setChecked(true);
+        verify(mListener).onEnabled(true);
+
+        mWirelessDebuggingEnabler.onSwitchToggled(false);
+
+        verify(mSwitchBar).setChecked(false);
+        verify(mListener).onEnabled(false);
+        assertThat(Global.getInt(mContext.getContentResolver(),
+            Global.ADB_WIFI_ENABLED, -1)).isEqualTo(0);
+        // Should also get a callback
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/WirelessDebuggingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/WirelessDebuggingPreferenceControllerTest.java
new file mode 100644
index 0000000..f755ec4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/WirelessDebuggingPreferenceControllerTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2020 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.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.debug.IAdbManager;
+import android.os.RemoteException;
+import android.provider.Settings.Global;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settings.widget.MasterSwitchPreference;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowUtils.class)
+public class WirelessDebuggingPreferenceControllerTest {
+
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private MasterSwitchPreference mPreference;
+    @Mock
+    private IAdbManager mAdbManager;
+    @Mock
+    private DevelopmentSettingsDashboardFragment mFragment;
+
+    private WirelessDebuggingPreferenceController mController;
+    private LifecycleOwner mLifecycleOwner;
+    private Lifecycle mLifecycle;
+    private Context mContext;
+    private ContentResolver mContentResolver;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mContentResolver = mContext.getContentResolver();
+        mLifecycleOwner = () -> mLifecycle;
+        mLifecycle = new Lifecycle(mLifecycleOwner);
+        mController = spy(new WirelessDebuggingPreferenceController(mContext, mLifecycle));
+        ReflectionHelpers.setField(mController, "mAdbManager", mAdbManager);
+        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    @Test
+    public void isAvailable_isAdbWifiSupported_yes_shouldBeTrue() throws RemoteException {
+        when(mAdbManager.isAdbWifiSupported()).thenReturn(true);
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void isAvailable_isAdbWifiSupported_shouldBeFalse() throws RemoteException {
+        when(mAdbManager.isAdbWifiSupported()).thenReturn(false);
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void updateState_adbWifiEnabled_preferenceShouldBeChecked() {
+        Global.putInt(mContentResolver,
+                Global.ADB_WIFI_ENABLED, 1 /* setting enabled */);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(true);
+    }
+
+    @Test
+    public void updateState_adbWifiDisabled_preferenceShouldNotBeChecked() {
+        Global.putInt(mContentResolver,
+                Global.ADB_WIFI_ENABLED, 0 /* setting disabled */);
+        mController.updateState(mPreference);
+
+        verify(mPreference).setChecked(false);
+    }
+
+    @Test
+    public void onPreferenceChange_turnOn_adbWifiEnabledTrue() {
+        mController.onPreferenceChange(null, true);
+
+        assertThat(Global.getInt(mContentResolver, Global.ADB_WIFI_ENABLED, -1)).isEqualTo(1);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverAppPreferenceControllerTest.java
index 522dc8a..372daf0 100644
--- a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverAppPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverAppPreferenceControllerTest.java
@@ -56,8 +56,9 @@
 public class GraphicsDriverAppPreferenceControllerTest {
 
     private static final int DEFAULT = 0;
-    private static final int GAME_DRIVER = 1;
-    private static final int SYSTEM = 2;
+    private static final int PRERELEASE_DRIVER = 1;
+    private static final int GAME_DRIVER = 2;
+    private static final int SYSTEM = 3;
     private static final String TEST_APP_NAME = "testApp";
     private static final String TEST_PKG_NAME = "testPkg";
 
@@ -116,7 +117,7 @@
     }
 
     @Test
-    public void getAvailability_gameDriverOff_conditionallyUnavailable() {
+    public void getAvailability_graphicsDriverOff_conditionallyUnavailable() {
         loadDefaultConfig();
         Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
 
@@ -163,7 +164,7 @@
     }
 
     @Test
-    public void updateState_gameDriverOff_notVisible() {
+    public void updateState_graphicsDriverOff_notVisible() {
         Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
         loadDefaultConfig();
 
@@ -213,6 +214,8 @@
         assertThat(preference.getDialogTitle()).isEqualTo(mDialogTitle);
         assertThat(preference.getEntries()).isEqualTo(mValueList);
         assertThat(preference.getEntryValues()).isEqualTo(mValueList);
+        assertThat(preference.getEntry()).isEqualTo(mValueList[PRERELEASE_DRIVER]);
+        assertThat(preference.getValue()).isEqualTo(mValueList[PRERELEASE_DRIVER]);
         assertThat(preference.getSummary()).isEqualTo(mPreferencePrereleaseDriver);
     }
 
@@ -249,6 +252,23 @@
     }
 
     @Test
+    public void onPreferenceChange_selectPRERELEASE_DRIVER_shouldUpdateAttrAndSettingsGlobal() {
+        loadDefaultConfig();
+        final ListPreference preference =
+                mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME);
+        mController.onPreferenceChange(preference, mValueList[PRERELEASE_DRIVER]);
+
+        assertThat(preference.getEntry()).isEqualTo(mValueList[PRERELEASE_DRIVER]);
+        assertThat(preference.getValue()).isEqualTo(mValueList[PRERELEASE_DRIVER]);
+        assertThat(preference.getSummary()).isEqualTo(mValueList[PRERELEASE_DRIVER]);
+        assertThat(Settings.Global.getString(mResolver,
+                Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS))
+                .isEqualTo(TEST_PKG_NAME);
+        assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS))
+                .isEqualTo("");
+    }
+
+    @Test
     public void onPreferenceChange_selectGAME_DRIVER_shouldUpdateAttributesAndSettingsGlobal() {
         loadDefaultConfig();
         final ListPreference preference =
@@ -306,6 +326,8 @@
         Settings.Global.putString(mResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS, optOut);
 
         mController = new GraphicsDriverAppPreferenceController(mContext, "testKey");
+        mController.mEntryList = mContext.getResources().getStringArray(
+                R.array.graphics_driver_app_preference_values);
         mGroup = spy(new PreferenceCategory(mContext));
         final PreferenceManager preferenceManager = new PreferenceManager(mContext);
         when(mGroup.getContext()).thenReturn(mContext);
diff --git a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java
index 295eac5..964fce3 100644
--- a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java
@@ -16,17 +16,22 @@
 
 package com.android.settings.display;
 
-import static android.provider.Settings.System.ADAPTIVE_SLEEP;
+import static android.provider.Settings.Secure.ADAPTIVE_SLEEP;
+
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.provider.Settings;
 
@@ -76,6 +81,14 @@
     }
 
     @Test
+    public void isControllerAvailable_ServiceUnavailable_returnUnsupported() {
+        doReturn(null).when(mPackageManager).resolveService(isA(Intent.class), anyInt());
+
+        assertThat(AdaptiveSleepPreferenceController.isControllerAvailable(mContext)).isEqualTo(
+                UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
     public void onPreferenceChange_turnOn_returnOn() {
         mController.onPreferenceChange(null, true);
 
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java
index 7c76999..c908225 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java
@@ -18,13 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 
-import com.android.settings.intelligence.ContextualCardProto;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -32,9 +29,6 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-import java.util.ArrayList;
-import java.util.List;
-
 @RunWith(RobolectricTestRunner.class)
 public class CardDatabaseHelperTest {
 
@@ -46,7 +40,7 @@
     public void setUp() {
         mContext = RuntimeEnvironment.application;
         mCardDatabaseHelper = CardDatabaseHelper.getInstance(mContext);
-        mDatabase = mCardDatabaseHelper.getWritableDatabase();
+        mDatabase = mCardDatabaseHelper.getReadableDatabase();
     }
 
     @After
@@ -69,44 +63,10 @@
                 CardDatabaseHelper.CardColumns.CATEGORY,
                 CardDatabaseHelper.CardColumns.PACKAGE_NAME,
                 CardDatabaseHelper.CardColumns.APP_VERSION,
-                CardDatabaseHelper.CardColumns.CARD_DISMISSED,
+                CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP,
         };
 
         assertThat(columnNames).isEqualTo(expectedNames);
         cursor.close();
     }
-
-    @Test
-    public void getContextualCards_shouldSortByScore() {
-        insertFakeCard(mDatabase, "card1", 1, "uri1");
-        insertFakeCard(mDatabase, "card2", 0, "uri2");
-        insertFakeCard(mDatabase, "card3", 10, "uri3");
-        // Should sort as 3,1,2
-        try (final Cursor cursor = CardDatabaseHelper.getInstance(mContext).getContextualCards()) {
-            assertThat(cursor.getCount()).isEqualTo(3);
-            final List<ContextualCard> cards = new ArrayList<>();
-            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
-                cards.add(new ContextualCard(cursor));
-            }
-            assertThat(cards.get(0).getName()).isEqualTo("card3");
-            assertThat(cards.get(1).getName()).isEqualTo("card1");
-            assertThat(cards.get(2).getName()).isEqualTo("card2");
-        }
-    }
-
-    private static void insertFakeCard(SQLiteDatabase db, String name, double score, String uri) {
-        final ContentValues value = new ContentValues();
-        value.put(CardDatabaseHelper.CardColumns.NAME, name);
-        value.put(CardDatabaseHelper.CardColumns.SCORE, score);
-        value.put(CardDatabaseHelper.CardColumns.SLICE_URI, uri);
-
-        value.put(CardDatabaseHelper.CardColumns.TYPE, ContextualCard.CardType.SLICE);
-        value.put(CardDatabaseHelper.CardColumns.CATEGORY,
-                ContextualCardProto.ContextualCard.Category.DEFAULT.getNumber());
-        value.put(CardDatabaseHelper.CardColumns.PACKAGE_NAME,
-                RuntimeEnvironment.application.getPackageName());
-        value.put(CardDatabaseHelper.CardColumns.APP_VERSION, 1);
-
-        db.insert(CardDatabaseHelper.CARD_TABLE, null, value);
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
index e380636..029dde8 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
@@ -28,10 +28,14 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 
+import android.annotation.Nullable;
 import android.app.PendingIntent;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.ArraySet;
@@ -46,6 +50,7 @@
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.applications.AppInfoBase;
+import com.android.settings.intelligence.ContextualCardProto;
 
 import org.junit.After;
 import org.junit.Before;
@@ -54,6 +59,8 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 @RunWith(RobolectricTestRunner.class)
@@ -62,6 +69,8 @@
     private Context mContext;
     private ContextualCardFeatureProviderImpl mImpl;
     private SharedPreferences mSharedPreferences;
+    private CardDatabaseHelper mCardDatabaseHelper;
+    private SQLiteDatabase mDatabase;
 
     @Before
     public void setUp() {
@@ -70,14 +79,56 @@
         mSharedPreferences = mContext.getSharedPreferences(PREFS, MODE_PRIVATE);
         // Set-up specs for SliceMetadata.
         SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+        mCardDatabaseHelper = CardDatabaseHelper.getInstance(mContext);
+        mDatabase = mCardDatabaseHelper.getWritableDatabase();
     }
 
     @After
     public void tearDown() {
+        CardDatabaseHelper.getInstance(mContext).close();
+        CardDatabaseHelper.sCardDatabaseHelper = null;
         removeInteractedPackageFromSharedPreference();
     }
 
     @Test
+    public void getContextualCards_shouldSortByScore() {
+        insertFakeCard(mDatabase, "card1", 1, "uri1", 1000L);
+        insertFakeCard(mDatabase, "card2", 0, "uri2", 1000L);
+        insertFakeCard(mDatabase, "card3", 10, "uri3", 1000L);
+        // Should sort as 3,1,2
+        try (Cursor cursor = mImpl.getContextualCards()) {
+            assertThat(cursor.getCount()).isEqualTo(3);
+            final List<ContextualCard> cards = new ArrayList<>();
+            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+                cards.add(new ContextualCard(cursor));
+            }
+            assertThat(cards.get(0).getName()).isEqualTo("card3");
+            assertThat(cards.get(1).getName()).isEqualTo("card1");
+            assertThat(cards.get(2).getName()).isEqualTo("card2");
+        }
+    }
+
+    @Test
+    public void resetDismissedTime_durationExpired_shouldResetToNull() {
+        insertFakeCard(mDatabase, "card1", 1, "uri1", 100L);
+        final long threshold = 1000L;
+
+        final int rowsUpdated = mImpl.resetDismissedTime(threshold);
+
+        assertThat(rowsUpdated).isEqualTo(1);
+    }
+
+    @Test
+    public void resetDismissedTime_durationNotExpired_shouldNotUpdate() {
+        insertFakeCard(mDatabase, "card1", 1, "uri1", 1111L);
+        final long threshold = 1000L;
+
+        final int rowsUpdated = mImpl.resetDismissedTime(threshold);
+
+        assertThat(rowsUpdated).isEqualTo(0);
+    }
+
+    @Test
     public void logNotificationPackage_isContextualNotificationChannel_shouldLogPackage() {
         final String packageName = "com.android.test.app";
         final Slice slice = buildSlice(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI, packageName);
@@ -101,6 +152,28 @@
         assertThat(interactedPackages.contains(packageName)).isFalse();
     }
 
+    private static void insertFakeCard(
+            SQLiteDatabase db, String name, double score, String uri, @Nullable Long time) {
+        final ContentValues value = new ContentValues();
+        value.put(CardDatabaseHelper.CardColumns.NAME, name);
+        value.put(CardDatabaseHelper.CardColumns.SCORE, score);
+        value.put(CardDatabaseHelper.CardColumns.SLICE_URI, uri);
+
+        value.put(CardDatabaseHelper.CardColumns.TYPE, ContextualCard.CardType.SLICE);
+        value.put(CardDatabaseHelper.CardColumns.CATEGORY,
+                ContextualCardProto.ContextualCard.Category.DEFAULT.getNumber());
+        value.put(CardDatabaseHelper.CardColumns.PACKAGE_NAME,
+                RuntimeEnvironment.application.getPackageName());
+        value.put(CardDatabaseHelper.CardColumns.APP_VERSION, 1);
+        if (time == null) {
+            value.putNull(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP);
+        } else {
+            value.put(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP, time);
+        }
+
+        db.insert(CardDatabaseHelper.CARD_TABLE, null, value);
+    }
+
     private Slice buildSlice(Uri sliceUri, String packageName) {
         final Bundle args = new Bundle();
         args.putString(AppInfoBase.ARG_PACKAGE_NAME, packageName);
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java
index 51d2523..91d372e 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java
@@ -38,10 +38,13 @@
 import com.android.settings.homepage.contextualcards.CardContentProvider;
 import com.android.settings.homepage.contextualcards.CardDatabaseHelper;
 import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
+import com.android.settings.homepage.contextualcards.ContextualCardFeatureProviderImpl;
 import com.android.settings.homepage.contextualcards.ContextualCardFeedbackDialog;
 import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
 import com.android.settings.testutils.FakeFeatureFactory;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -78,10 +81,18 @@
         mResolver = mContext.getContentResolver();
         mController = spy(new SliceContextualCardController(mContext));
         mFeatureFactory = FakeFeatureFactory.setupForTest();
+        final ContextualCardFeatureProvider cardFeatureProvider =
+                new ContextualCardFeatureProviderImpl(mContext);
+        mFeatureFactory.mContextualCardFeatureProvider = cardFeatureProvider;
+    }
+
+    @After
+    public void tearDown() {
+        CardDatabaseHelper.getInstance(mContext).close();
     }
 
     @Test
-    public void onDismissed_cardShouldBeMarkedAsDismissed() {
+    public void onDismissed_cardShouldBeMarkedAsDismissedWithTimestamp() {
         final Uri providerUri = CardContentProvider.REFRESH_CARD_URI;
         mResolver.insert(providerUri, generateOneRow());
         doNothing().when(mController).showFeedbackDialog(any(ContextualCard.class));
@@ -89,15 +100,15 @@
         final ContextualCard card = getTestSliceCard();
         mController.onDismissed(card);
 
-        final String[] columns = {CardDatabaseHelper.CardColumns.CARD_DISMISSED};
+        final String[] columns = {CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP};
         final String selection = CardDatabaseHelper.CardColumns.NAME + "=?";
         final String[] selectionArgs = {TEST_CARD_NAME};
         final Cursor cr = mResolver.query(providerUri, columns, selection, selectionArgs, null);
         cr.moveToFirst();
-        final int qryDismissed = cr.getInt(0);
+        final long dismissedTimestamp = cr.getLong(0);
         cr.close();
 
-        assertThat(qryDismissed).isEqualTo(1);
+        assertThat(dismissedTimestamp).isNotEqualTo(0L);
         verify(mFeatureFactory.metricsFeatureProvider).action(any(),
                 eq(SettingsEnums.ACTION_CONTEXTUAL_CARD_DISMISS), any(String.class));
     }
@@ -172,7 +183,7 @@
         values.put(CardDatabaseHelper.CardColumns.CATEGORY, 2);
         values.put(CardDatabaseHelper.CardColumns.PACKAGE_NAME, "com.android.settings");
         values.put(CardDatabaseHelper.CardColumns.APP_VERSION, 10001);
-        values.put(CardDatabaseHelper.CardColumns.CARD_DISMISSED, 0);
+        values.put(CardDatabaseHelper.CardColumns.DISMISSED_TIMESTAMP, 0L);
 
         return values;
     }
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index 220209c..b6c4fb7 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -66,7 +66,6 @@
     public final UserFeatureProvider userFeatureProvider;
     public final AssistGestureFeatureProvider assistGestureFeatureProvider;
     public final AccountFeatureProvider mAccountFeatureProvider;
-    public final ContextualCardFeatureProvider mContextualCardFeatureProvider;
     public final BluetoothFeatureProvider mBluetoothFeatureProvider;
     public final AwareFeatureProvider mAwareFeatureProvider;
     public final FaceFeatureProvider mFaceFeatureProvider;
@@ -74,6 +73,7 @@
     public PanelFeatureProvider panelFeatureProvider;
     public SlicesFeatureProvider slicesFeatureProvider;
     public SearchFeatureProvider searchFeatureProvider;
+    public ContextualCardFeatureProvider mContextualCardFeatureProvider;
 
     /**
      * Call this in {@code @Before} method of the test class to use fake factory.
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
index 6593ec3..54b7c2d 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
@@ -87,8 +87,7 @@
 
         final Slice wifiSlice = mWifiSlice.getSlice();
 
-        assertTitleAndIcon(wifiSlice);
-        assertNoToggle(wifiSlice);
+        assertWifiHeader(wifiSlice);
         assertThat(ContextualWifiSlice.getApRowCount()).isEqualTo(COLLAPSED_ROW_COUNT);
     }
 
@@ -98,61 +97,32 @@
 
         final Slice wifiSlice = mWifiSlice.getSlice();
 
-        assertTitleAndIcon(wifiSlice);
-        assertToggle(wifiSlice);
+        assertWifiHeader(wifiSlice);
         assertThat(ContextualWifiSlice.getApRowCount()).isEqualTo(DEFAULT_EXPANDED_ROW_COUNT);
     }
 
     @Test
     public void getWifiSlice_previousExpanded_hasActiveConnection_shouldExpandSlice() {
         mWifiSlice.sActiveUiSession = mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
-        mWifiSlice.sToggleNeeded = true;
+        mWifiSlice.sApRowCollapsed = false;
         connectToWifi(makeValidatedNetworkCapabilities());
 
         final Slice wifiSlice = mWifiSlice.getSlice();
 
-        assertTitleAndIcon(wifiSlice);
-        assertToggle(wifiSlice);
+        assertWifiHeader(wifiSlice);
         assertThat(ContextualWifiSlice.getApRowCount()).isEqualTo(DEFAULT_EXPANDED_ROW_COUNT);
     }
 
     @Test
-    public void getWifiSlice_previousExpanded_disableWifi_shouldHaveToggle() {
-        mWifiSlice.sActiveUiSession = mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
-        mWifiSlice.sToggleNeeded = true;
-        connectToWifi(makeValidatedNetworkCapabilities());
-
-        mWifiManager.setWifiEnabled(false);
-        final Slice wifiSlice = mWifiSlice.getSlice();
-
-        assertTitleAndIcon(wifiSlice);
-        assertToggle(wifiSlice);
-    }
-
-    @Test
-    public void getWifiSlice_previousCollapsed_disableWifi_shouldHaveToggle() {
-        mWifiSlice.sActiveUiSession = mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
-        mWifiSlice.sToggleNeeded = false;
-        connectToWifi(makeValidatedNetworkCapabilities());
-
-        mWifiManager.setWifiEnabled(false);
-        final Slice wifiSlice = mWifiSlice.getSlice();
-
-        assertTitleAndIcon(wifiSlice);
-        assertToggle(wifiSlice);
-    }
-
-    @Test
     public void getWifiSlice_previousCollapsed_connectionLoss_shouldCollapseSlice() {
         mWifiSlice.sActiveUiSession = mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
-        mWifiSlice.sToggleNeeded = false;
+        mWifiSlice.sApRowCollapsed = true;
         connectToWifi(makeValidatedNetworkCapabilities());
 
         mWifiManager.disconnect();
         final Slice wifiSlice = mWifiSlice.getSlice();
 
-        assertTitleAndIcon(wifiSlice);
-        assertNoToggle(wifiSlice);
+        assertWifiHeader(wifiSlice);
         assertThat(ContextualWifiSlice.getApRowCount()).isEqualTo(COLLAPSED_ROW_COUNT);
     }
 
@@ -181,7 +151,7 @@
         return nc;
     }
 
-    private void assertTitleAndIcon(Slice slice) {
+    private void assertWifiHeader(Slice slice) {
         final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
         assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.wifi_settings));
 
@@ -189,17 +159,8 @@
         final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_settings_wireless);
         assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString());
-    }
 
-    private void assertToggle(Slice slice) {
-        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
         final List<SliceAction> toggles = metadata.getToggles();
         assertThat(toggles).hasSize(1);
     }
-
-    private void assertNoToggle(Slice slice) {
-        final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
-        final List<SliceAction> toggles = metadata.getToggles();
-        assertThat(toggles).isEmpty();
-    }
 }