Merge "Fix [a11y][Qt]Small touch targets in Add network page after running Accessibility scanner"
diff --git a/res/layout/dialog_firmware_version.xml b/res/layout/dialog_firmware_version.xml
deleted file mode 100644
index 1d5f531..0000000
--- a/res/layout/dialog_firmware_version.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2017 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<ScrollView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-    <LinearLayout
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:padding="@dimen/sim_content_padding">
-
-        <TextView
-            style="@style/device_info_dialog_label"
-            android:id="@+id/firmware_version_label"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/firmware_version"/>
-        <TextView
-            style="@style/device_info_dialog_value"
-            android:id="@+id/firmware_version_value"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-
-        <TextView
-            style="@style/device_info_dialog_label"
-            android:id="@+id/security_patch_level_label"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/security_patch"/>
-        <TextView
-            style="@style/device_info_dialog_value"
-            android:id="@+id/security_patch_level_value"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:background="?android:attr/selectableItemBackground"
-            android:textColor="?android:attr/colorAccent"/>
-
-        <TextView
-            style="@style/device_info_dialog_label"
-            android:id="@+id/module_version_label"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/module_version"/>
-        <TextView
-            style="@style/device_info_dialog_value"
-            android:id="@+id/module_version_value"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-
-        <TextView
-            style="@style/device_info_dialog_label"
-            android:id="@+id/baseband_version_label"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/baseband_version"/>
-        <TextView
-            style="@style/device_info_dialog_value"
-            android:id="@+id/baseband_version_value"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-
-        <TextView
-            style="@style/device_info_dialog_label"
-            android:id="@+id/kernel_version_label"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/kernel_version"/>
-        <TextView
-            style="@style/device_info_dialog_value"
-            android:id="@+id/kernel_version_value"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-
-        <TextView
-            style="@style/device_info_dialog_label"
-            android:id="@+id/build_number_label"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/build_number"/>
-        <TextView
-            style="@style/device_info_dialog_value"
-            android:id="@+id/build_number_value"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-
-    </LinearLayout>
-</ScrollView>
diff --git a/res/layout/wifi_network_details_two_buttons_panel.xml b/res/layout/wifi_network_details_two_buttons_panel.xml
index 57f76b5..6c51d11 100644
--- a/res/layout/wifi_network_details_two_buttons_panel.xml
+++ b/res/layout/wifi_network_details_two_buttons_panel.xml
@@ -27,7 +27,6 @@
         android:paddingStart="8dp"
         android:paddingEnd="8dp">
         <Button
-            style="@android:style/@Widget.Material.Button.Colored"
             android:id="@+id/forget_button"
             android:text="@string/forget"
             android:layout_width="0dp"
diff --git a/res/values/config.xml b/res/values/config.xml
index c2899ef..beeac0c 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -171,9 +171,6 @@
     <!-- Email address for the homepage contextual cards feedback -->
     <string name="config_contextual_card_feedback_email" translatable="false"></string>
 
-    <!-- Uri that represents extra bluetooth settings -->
-    <string name="config_bluetooth_device_settings_uri" translatable="false">content://com.google.android.gms.nearby.fastpair/settings_slice?addr=<xliff:g id="mac_address">%1$s</xliff:g></string>
-
     <!-- ComponentName to launch a vendor-specific enrollment activity if available -->
     <string name="config_face_enroll" translatable="false"></string>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f581121..e01ab3b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2927,8 +2927,6 @@
 
     <!-- About phone screen, status item label  [CHAR LIMIT=40] -->
     <string name="firmware_version">Android version</string>
-    <!-- About phone screen, dialog title for showing device software information such as android version, security patch level, etc  [CHAR LIMIT=60] -->
-    <string name="firmware_title">Android</string>
     <!-- About phone screen, status item label  [CHAR LIMIT=60] -->
     <string name="security_patch">Android security patch level</string>
     <!-- About phone screen, status item label  [CHAR LIMIT=40] -->
diff --git a/res/xml/firmware_version.xml b/res/xml/firmware_version.xml
new file mode 100644
index 0000000..2914ef1
--- /dev/null
+++ b/res/xml/firmware_version.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 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:key="firmware_version_screen"
+    android:title="@string/firmware_version"
+    settings:keywords="@string/keywords_android_version">
+
+    <!-- Android version -->
+    <Preference
+        android:key="os_firmware_version"
+        android:title="@string/firmware_version"
+        android:summary="@string/summary_placeholder"
+        settings:enableCopying="true"
+        settings:allowDynamicSummaryInSlice="true"
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.FirmwareVersionDetailPreferenceController"/>
+
+    <!-- Security patch -->
+    <Preference
+        android:key="security_key"
+        android:title="@string/security_patch"
+        settings:enableCopying="true"
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.SecurityPatchLevelPreferenceController"/>
+
+    <!-- Mainline module version -->
+    <Preference
+        android:key="module_version"
+        android:title="@string/module_version"
+        android:summary="@string/summary_placeholder"
+        settings:enableCopying="true"
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.MainlineModuleVersionPreferenceController"/>
+
+    <!-- Baseband -->
+    <Preference
+        android:key="base_band"
+        android:title="@string/baseband_version"
+        android:summary="@string/summary_placeholder"
+        settings:enableCopying="true"
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.BasebandVersionPreferenceController"/>
+
+    <!-- Kernel -->
+    <Preference
+        android:key="kernel_version"
+        android:title="@string/kernel_version"
+        android:summary="@string/summary_placeholder"
+        settings:enableCopying="true"
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.KernelVersionPreferenceController"/>
+
+    <!-- Build -->
+    <Preference
+        android:key="os_build_number"
+        android:title="@string/build_number"
+        android:summary="@string/summary_placeholder"
+        settings:enableCopying="true"
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.SimpleBuildNumberPreferenceController"/>
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml
index 6323a14..918e8ec 100644
--- a/res/xml/my_device_info.xml
+++ b/res/xml/my_device_info.xml
@@ -121,11 +121,10 @@
         android:key="firmware_version"
         android:order="32"
         android:title="@string/firmware_version"
-        settings:keywords="@string/keywords_android_version"
         android:summary="@string/summary_placeholder"
         settings:allowDynamicSummaryInSlice="true"
-        settings:controller=
-            "com.android.settings.deviceinfo.firmwareversion.FirmwareVersionPreferenceController"/>
+        android:fragment="com.android.settings.deviceinfo.firmwareversion.FirmwareVersionSettings"
+        settings:controller="com.android.settings.deviceinfo.firmwareversion.FirmwareVersionPreferenceController"/>
 
     <!--IP address -->
     <Preference
diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
index 34a758b..64c9866 100644
--- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.bluetooth;
 
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -23,6 +24,8 @@
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.MediaStore;
 import android.util.Log;
 import android.view.View;
@@ -59,9 +62,25 @@
     @VisibleForTesting
     final Map<String, Bitmap> mIconCache;
     private CachedBluetoothDevice mCachedDevice;
+    @VisibleForTesting
+    BluetoothAdapter mBluetoothAdapter;
+    @VisibleForTesting
+    Handler mHandler = new Handler(Looper.getMainLooper());
+    @VisibleForTesting
+    final BluetoothAdapter.MetadataListener mMetadataListener =
+            new BluetoothAdapter.MetadataListener() {
+                @Override
+                public void onMetadataChanged(BluetoothDevice device, int key, String value) {
+                    super.onMetadataChanged(device, key, value);
+                    Log.i(TAG, String.format("Metadata updated in Device %s: %d = %s.", device, key,
+                            value));
+                    refresh();
+                }
+            };
 
     public AdvancedBluetoothDetailsHeaderController(Context context, String prefKey) {
         super(context, prefKey);
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
         mIconCache = new HashMap<>();
     }
 
@@ -84,11 +103,14 @@
     @Override
     public void onStart() {
         mCachedDevice.registerCallback(this::onDeviceAttributesChanged);
+        mBluetoothAdapter.registerMetadataListener(mCachedDevice.getDevice(), mMetadataListener,
+                mHandler);
     }
 
     @Override
     public void onStop() {
         mCachedDevice.unregisterCallback(this::onDeviceAttributesChanged);
+        mBluetoothAdapter.unregisterMetadataListener(mCachedDevice.getDevice());
 
         // Destroy icon bitmap associated with this header
         for (Bitmap bitmap : mIconCache.values()) {
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 2fbd061..36cbd5d 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -121,7 +121,7 @@
                 FeatureFlags.SLICE_INJECTION);
 
         use(BlockingSlicePrefController.class).setSliceUri(injectionEnabled
-                ? featureProvider.getBluetoothDeviceSettingsUri(mDeviceAddress)
+                ? featureProvider.getBluetoothDeviceSettingsUri(mCachedDevice.getDevice())
                 : null);
     }
 
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
index 2bca038..582a26c 100644
--- a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.bluetooth;
 
+import android.bluetooth.BluetoothDevice;
 import android.net.Uri;
 
 /**
@@ -25,8 +26,8 @@
 
     /**
      * Get the {@link Uri} that represents extra settings for a specific bluetooth device
-     * @param macAddress Bluetooth mac address
+     * @param bluetoothDevice bluetooth device
      * @return {@link Uri} for extra settings
      */
-    Uri getBluetoothDeviceSettingsUri(String macAddress);
+    Uri getBluetoothDeviceSettingsUri(BluetoothDevice bluetoothDevice);
 }
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
index dcdc2fd7..e486b68 100644
--- a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
@@ -16,11 +16,10 @@
 
 package com.android.settings.bluetooth;
 
+import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.net.Uri;
 
-import com.android.settings.R;
-
 /**
  * Impl of {@link BluetoothFeatureProvider}
  */
@@ -33,9 +32,9 @@
     }
 
     @Override
-    public Uri getBluetoothDeviceSettingsUri(String macAddress) {
-        final String uriString = mContext.getString(R.string.config_bluetooth_device_settings_uri,
-                macAddress);
-        return Uri.parse(uriString);
+    public Uri getBluetoothDeviceSettingsUri(BluetoothDevice bluetoothDevice) {
+        final String uriString = bluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI);
+        return uriString != null ? Uri.parse(uriString) : null;
     }
 }
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 60655fe..5e32e71 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -49,9 +49,9 @@
 import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureDetails;
 import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureSettings;
 import com.android.settings.applications.specialaccess.vrlistener.VrListenerSettings;
-import com.android.settings.backup.UserBackupSettingsActivity;
 import com.android.settings.backup.PrivacySettings;
 import com.android.settings.backup.ToggleBackupSettingFragment;
+import com.android.settings.backup.UserBackupSettingsActivity;
 import com.android.settings.biometrics.face.FaceSettings;
 import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
 import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
@@ -68,6 +68,7 @@
 import com.android.settings.deviceinfo.StorageDashboardFragment;
 import com.android.settings.deviceinfo.StorageSettings;
 import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
+import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionSettings;
 import com.android.settings.display.NightDisplaySettings;
 import com.android.settings.dream.DreamSettings;
 import com.android.settings.enterprise.EnterprisePrivacySettings;
@@ -166,6 +167,7 @@
             DisplaySettings.class.getName(),
             MyDeviceInfoFragment.class.getName(),
             ManageApplications.class.getName(),
+            FirmwareVersionSettings.class.getName(),
             ManageAssist.class.getName(),
             ProcessStatsUi.class.getName(),
             NotificationStation.class.getName(),
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index 0116c42..c20e857 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -77,7 +77,6 @@
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
-        use(FirmwareVersionPreferenceController.class).setHost(this /* parent */);
         use(DeviceModelPreferenceController.class).setHost(this /* parent */);
         use(ImeiInfoPreferenceController.class).setHost(this /* parent */);
         use(DeviceNamePreferenceController.class).setHost(this /* parent */);
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionDialogController.java b/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionDialogController.java
deleted file mode 100644
index 0e36d85..0000000
--- a/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionDialogController.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.deviceinfo.firmwareversion;
-
-import android.content.Context;
-import android.os.SystemProperties;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settings.R;
-import com.android.settings.Utils;
-
-public class BasebandVersionDialogController {
-
-    @VisibleForTesting
-    static final int BASEBAND_VERSION_LABEL_ID = R.id.baseband_version_label;
-    @VisibleForTesting
-    static final int BASEBAND_VERSION_VALUE_ID = R.id.baseband_version_value;
-    @VisibleForTesting
-    static final String BASEBAND_PROPERTY = "gsm.version.baseband";
-
-    private final FirmwareVersionDialogFragment mDialog;
-
-    public BasebandVersionDialogController(FirmwareVersionDialogFragment dialog) {
-        mDialog = dialog;
-    }
-
-    /**
-     * Updates the baseband version field of the dialog.
-     */
-    public void initialize() {
-        final Context context = mDialog.getContext();
-        if (Utils.isWifiOnly(context)) {
-            mDialog.removeSettingFromScreen(BASEBAND_VERSION_LABEL_ID);
-            mDialog.removeSettingFromScreen(BASEBAND_VERSION_VALUE_ID);
-            return;
-        }
-
-        mDialog.setText(BASEBAND_VERSION_VALUE_ID, SystemProperties.get(BASEBAND_PROPERTY,
-                context.getString(R.string.device_info_default)));
-    }
-}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceController.java
new file mode 100644
index 0000000..dd3d560
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceController.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 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.deviceinfo.firmwareversion;
+
+import android.content.Context;
+import android.os.SystemProperties;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.BasePreferenceController;
+
+public class BasebandVersionPreferenceController extends BasePreferenceController {
+
+    @VisibleForTesting
+    static final String BASEBAND_PROPERTY = "gsm.version.baseband";
+
+    public BasebandVersionPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return !Utils.isWifiOnly(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return SystemProperties.get(BASEBAND_PROPERTY,
+                mContext.getString(R.string.device_info_default));
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/BuildNumberDialogController.java b/src/com/android/settings/deviceinfo/firmwareversion/BuildNumberDialogController.java
deleted file mode 100644
index ba4eb7a..0000000
--- a/src/com/android/settings/deviceinfo/firmwareversion/BuildNumberDialogController.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.deviceinfo.firmwareversion;
-
-import android.os.Build;
-import android.text.BidiFormatter;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settings.R;
-
-public class BuildNumberDialogController {
-
-    @VisibleForTesting
-    static final int BUILD_NUMBER_VALUE_ID = R.id.build_number_value;
-
-    private final FirmwareVersionDialogFragment mDialog;
-
-    public BuildNumberDialogController(FirmwareVersionDialogFragment dialog) {
-        mDialog = dialog;
-    }
-
-    /**
-     * Updates the build number to the dialog.
-     */
-    public void initialize() {
-        mDialog.setText(BUILD_NUMBER_VALUE_ID,
-                BidiFormatter.getInstance().unicodeWrap(Build.DISPLAY));
-    }
-}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogController.java b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java
similarity index 71%
rename from src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogController.java
rename to src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java
index 8c29f7b..7a19fdef2 100644
--- a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogController.java
+++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -22,42 +22,61 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.text.TextUtils;
 import android.util.Log;
-import android.view.View;
 
 import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
 
 import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.slices.Copyable;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 
-public class FirmwareVersionDialogController implements View.OnClickListener {
+public class FirmwareVersionDetailPreferenceController extends BasePreferenceController implements
+        Copyable {
 
     private static final String TAG = "firmwareDialogCtrl";
     private static final int DELAY_TIMER_MILLIS = 500;
     private static final int ACTIVITY_TRIGGER_COUNT = 3;
 
-    @VisibleForTesting
-    static final int FIRMWARE_VERSION_VALUE_ID = R.id.firmware_version_value;
-    @VisibleForTesting
-    static final int FIRMWARE_VERSION_LABEL_ID = R.id.firmware_version_label;
-
-    private final FirmwareVersionDialogFragment mDialog;
-    private final Context mContext;
     private final UserManager mUserManager;
     private final long[] mHits = new long[ACTIVITY_TRIGGER_COUNT];
 
     private RestrictedLockUtils.EnforcedAdmin mFunDisallowedAdmin;
     private boolean mFunDisallowedBySystem;
 
-    public FirmwareVersionDialogController(FirmwareVersionDialogFragment dialog) {
-        mDialog = dialog;
-        mContext = dialog.getContext();
+    public FirmwareVersionDetailPreferenceController(Context context, String key) {
+        super(context, key);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        initializeAdminPermissions();
     }
 
     @Override
-    public void onClick(View v) {
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public boolean isSliceable() {
+        return true;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return Build.VERSION.RELEASE;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            return false;
+        }
+        if (Utils.isMonkeyRunning()) {
+            return false;
+        }
         arrayCopy();
         mHits[mHits.length - 1] = SystemClock.uptimeMillis();
         if (mHits[0] >= (SystemClock.uptimeMillis() - DELAY_TIMER_MILLIS)) {
@@ -67,7 +86,7 @@
                             mFunDisallowedAdmin);
                 }
                 Log.d(TAG, "Sorry, no fun for you!");
-                return;
+                return true;
             }
 
             final Intent intent = new Intent(Intent.ACTION_MAIN)
@@ -79,21 +98,7 @@
                 Log.e(TAG, "Unable to start activity " + intent.toString());
             }
         }
-    }
-
-    /**
-     * Populates the Android version field in the dialog and registers click listeners.
-     */
-    public void initialize() {
-        initializeAdminPermissions();
-        registerClickListeners();
-
-        mDialog.setText(FIRMWARE_VERSION_VALUE_ID, Build.VERSION.RELEASE);
-    }
-
-    private void registerClickListeners() {
-        mDialog.registerClickListener(FIRMWARE_VERSION_LABEL_ID, this /* listener */);
-        mDialog.registerClickListener(FIRMWARE_VERSION_VALUE_ID, this /* listener */);
+        return true;
     }
 
     /**
@@ -111,4 +116,10 @@
         mFunDisallowedBySystem = RestrictedLockUtilsInternal.hasBaseUserRestriction(
                 mContext, UserManager.DISALLOW_FUN, UserHandle.myUserId());
     }
+
+    @Override
+    public void copy() {
+        Copyable.setCopyContent(mContext, getSummary(),
+                mContext.getText(R.string.firmware_version));
+    }
 }
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogFragment.java b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogFragment.java
deleted file mode 100644
index 2093c3e..0000000
--- a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogFragment.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.deviceinfo.firmwareversion;
-
-import android.app.Dialog;
-import android.app.settings.SettingsEnums;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-
-import com.android.settings.R;
-import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
-
-public class FirmwareVersionDialogFragment extends InstrumentedDialogFragment {
-
-    private static final String TAG = "firmwareVersionDialog";
-
-    private View mRootView;
-
-    public static void show(Fragment host) {
-        final FragmentManager manager = host.getChildFragmentManager();
-        if (manager.findFragmentByTag(TAG) == null) {
-            final FirmwareVersionDialogFragment dialog = new FirmwareVersionDialogFragment();
-            dialog.show(manager, TAG);
-        }
-    }
-
-    @Override
-    public int getMetricsCategory() {
-        return SettingsEnums.DIALOG_FIRMWARE_VERSION;
-    }
-
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
-                .setTitle(R.string.firmware_title)
-                .setPositiveButton(android.R.string.ok, null /* listener */);
-
-        mRootView = LayoutInflater.from(getActivity()).inflate(
-                R.layout.dialog_firmware_version, null /* parent */);
-
-        initializeControllers();
-
-        return builder.setView(mRootView).create();
-    }
-
-    public void setText(int viewId, CharSequence text) {
-        final TextView view = mRootView.findViewById(viewId);
-        if (view != null) {
-            view.setText(text);
-        }
-    }
-
-    public void removeSettingFromScreen(int viewId) {
-        final View view = mRootView.findViewById(viewId);
-        if (view != null) {
-            view.setVisibility(View.GONE);
-        }
-    }
-
-    public void registerClickListener(int viewId, View.OnClickListener listener) {
-        final View view = mRootView.findViewById(viewId);
-        if (view != null) {
-            view.setOnClickListener(listener);
-        }
-    }
-
-    private void initializeControllers() {
-        new FirmwareVersionDialogController(this).initialize();
-        new SecurityPatchLevelDialogController(this).initialize();
-        new BasebandVersionDialogController(this).initialize();
-        new KernelVersionDialogController(this).initialize();
-        new BuildNumberDialogController(this).initialize();
-        new ModuleVersionDialogController(this).initialize();
-    }
-}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java
index b7b67b7..41d9566 100644
--- a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceController.java
@@ -18,56 +18,22 @@
 
 import android.content.Context;
 import android.os.Build;
-import android.text.TextUtils;
 
-import androidx.fragment.app.Fragment;
-import androidx.preference.Preference;
-
-import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
-import com.android.settings.slices.Copyable;
 
-public class FirmwareVersionPreferenceController extends BasePreferenceController implements
-        Copyable {
-
-    private Fragment mFragment;
+public class FirmwareVersionPreferenceController extends BasePreferenceController {
 
     public FirmwareVersionPreferenceController(Context context, String key) {
         super(context, key);
     }
 
-    public void setHost(Fragment fragment) {
-        mFragment = fragment;
-    }
-
     @Override
     public int getAvailabilityStatus() {
-        return AVAILABLE;
+        return AVAILABLE_UNSEARCHABLE;
     }
 
     @Override
     public CharSequence getSummary() {
         return Build.VERSION.RELEASE;
     }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        if (!TextUtils.equals(preference.getKey(), mPreferenceKey)) {
-            return false;
-        }
-
-        FirmwareVersionDialogFragment.show(mFragment);
-        return true;
-    }
-
-    @Override
-    public boolean isSliceable() {
-        return true;
-    }
-
-    @Override
-    public void copy() {
-        Copyable.setCopyContent(mContext, getSummary(),
-                mContext.getText(R.string.firmware_version));
-    }
 }
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionSettings.java b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionSettings.java
new file mode 100644
index 0000000..90c3b56
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionSettings.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 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.deviceinfo.firmwareversion;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SearchIndexable
+public class FirmwareVersionSettings extends DashboardFragment {
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.firmware_version;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return "FirmwareVersionSettings";
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.DIALOG_FIRMWARE_VERSION;
+    }
+
+    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
+                        boolean enabled) {
+                    final ArrayList<SearchIndexableResource> result = new ArrayList<>();
+
+                    final SearchIndexableResource sir = new SearchIndexableResource(context);
+                    sir.xmlResId = R.xml.firmware_version;
+                    result.add(sir);
+                    return result;
+                }
+
+            };
+}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionDialogController.java b/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionDialogController.java
deleted file mode 100644
index 0d816d5..0000000
--- a/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionDialogController.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.deviceinfo.firmwareversion;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settings.R;
-import com.android.settingslib.DeviceInfoUtils;
-
-public class KernelVersionDialogController {
-
-    @VisibleForTesting
-    static int KERNEL_VERSION_VALUE_ID = R.id.kernel_version_value;
-
-    private final FirmwareVersionDialogFragment mDialog;
-
-    public KernelVersionDialogController(FirmwareVersionDialogFragment dialog) {
-        mDialog = dialog;
-    }
-
-    /**
-     * Updates kernel version to the dialog.
-     */
-    public void initialize() {
-        mDialog.setText(KERNEL_VERSION_VALUE_ID,
-                DeviceInfoUtils.getFormattedKernelVersion(mDialog.getContext()));
-    }
-}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionPreferenceController.java
new file mode 100644
index 0000000..0500c893
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionPreferenceController.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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.deviceinfo.firmwareversion;
+
+import android.content.Context;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.DeviceInfoUtils;
+
+public class KernelVersionPreferenceController extends BasePreferenceController {
+
+    public KernelVersionPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return DeviceInfoUtils.getFormattedKernelVersion(mContext);
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java
new file mode 100644
index 0000000..e2f4fae
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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.deviceinfo.firmwareversion;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.FeatureFlags;
+
+public class MainlineModuleVersionPreferenceController extends BasePreferenceController {
+
+    private static final String TAG = "MainlineModuleControl";
+
+    private final PackageManager mPackageManager;
+
+    private String mModuleVersion;
+
+    public MainlineModuleVersionPreferenceController(Context context, String key) {
+        super(context, key);
+        mPackageManager = mContext.getPackageManager();
+        initModules();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlags.MAINLINE_MODULE)) {
+            return UNSUPPORTED_ON_DEVICE;
+        }
+        return !TextUtils.isEmpty(mModuleVersion) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    private void initModules() {
+        if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlags.MAINLINE_MODULE)) {
+            return;
+        }
+        final String moduleProvider = mContext.getString(
+                com.android.internal.R.string.config_defaultModuleMetadataProvider);
+        if (!TextUtils.isEmpty(moduleProvider)) {
+            try {
+                mModuleVersion =
+                        mPackageManager.getPackageInfo(moduleProvider, 0 /* flags */).versionName;
+                return;
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "Failed to get mainline version.", e);
+                mModuleVersion = null;
+            }
+        }
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return mModuleVersion;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogController.java b/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogController.java
deleted file mode 100644
index 0dc953d..0000000
--- a/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogController.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 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.deviceinfo.firmwareversion;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
-import android.util.Log;
-
-import com.android.settings.R;
-import com.android.settings.core.FeatureFlags;
-
-import androidx.annotation.VisibleForTesting;
-
-public class ModuleVersionDialogController {
-
-    private static final String TAG = "MainlineModuleControl";
-
-    @VisibleForTesting
-    static final int MODULE_VERSION_LABEL_ID = R.id.module_version_label;
-    @VisibleForTesting
-    static final int MODULE_VERSION_VALUE_ID = R.id.module_version_value;
-
-    private final FirmwareVersionDialogFragment mDialog;
-    private final Context mContext;
-    private final PackageManager mPackageManager;
-
-    public ModuleVersionDialogController(FirmwareVersionDialogFragment dialog) {
-        mDialog = dialog;
-        mContext = mDialog.getContext();
-        mPackageManager = mContext.getPackageManager();
-    }
-
-    /**
-     * Updates the mainline module version field of the dialog.
-     */
-    public void initialize() {
-        if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlags.MAINLINE_MODULE)) {
-            mDialog.removeSettingFromScreen(MODULE_VERSION_LABEL_ID);
-            mDialog.removeSettingFromScreen(MODULE_VERSION_VALUE_ID);
-            return;
-        }
-        final String moduleProvider = mContext.getString(
-            com.android.internal.R.string.config_defaultModuleMetadataProvider);
-        if (!TextUtils.isEmpty(moduleProvider)) {
-            try {
-                mDialog.setText(MODULE_VERSION_VALUE_ID,
-                    mPackageManager.getPackageInfo(moduleProvider, 0 /* flags */).versionName);
-                return;
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.e(TAG, "Failed to get mainline version.", e);
-            }
-        }
-        mDialog.removeSettingFromScreen(MODULE_VERSION_LABEL_ID);
-        mDialog.removeSettingFromScreen(MODULE_VERSION_VALUE_ID);
-    }
-}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelDialogController.java b/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelDialogController.java
deleted file mode 100644
index 9037fe7..0000000
--- a/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelDialogController.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.deviceinfo.firmwareversion;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settings.R;
-import com.android.settingslib.DeviceInfoUtils;
-
-public class SecurityPatchLevelDialogController implements View.OnClickListener {
-
-    private static final String TAG = "SecurityPatchCtrl";
-    private static final Uri INTENT_URI_DATA = Uri.parse(
-            "https://source.android.com/security/bulletin/");
-
-    @VisibleForTesting
-    static final int SECURITY_PATCH_VALUE_ID = R.id.security_patch_level_value;
-    @VisibleForTesting
-    static final int SECURITY_PATCH_LABEL_ID = R.id.security_patch_level_label;
-
-    private final FirmwareVersionDialogFragment mDialog;
-    private final Context mContext;
-    private final PackageManager mPackageManager;
-    private final String mCurrentPatch;
-
-    public SecurityPatchLevelDialogController(FirmwareVersionDialogFragment dialog) {
-        mDialog = dialog;
-        mContext = dialog.getContext();
-        mPackageManager = mContext.getPackageManager();
-        mCurrentPatch = DeviceInfoUtils.getSecurityPatch();
-    }
-
-    @Override
-    public void onClick(View v) {
-        final Intent intent = new Intent();
-        intent.setAction(Intent.ACTION_VIEW);
-        intent.setData(INTENT_URI_DATA);
-        if (mPackageManager.queryIntentActivities(intent, 0).isEmpty()) {
-            // Don't send out the intent to stop crash
-            Log.w(TAG, "Stop click action on " + SECURITY_PATCH_VALUE_ID + ": "
-                    + "queryIntentActivities() returns empty");
-            return;
-        }
-
-        mContext.startActivity(intent);
-    }
-
-    /**
-     * Populates the security patch level field in the dialog and registers click listeners.
-     */
-    public void initialize() {
-        if (TextUtils.isEmpty(mCurrentPatch)) {
-            mDialog.removeSettingFromScreen(SECURITY_PATCH_LABEL_ID);
-            mDialog.removeSettingFromScreen(SECURITY_PATCH_VALUE_ID);
-            return;
-        }
-        registerListeners();
-        mDialog.setText(SECURITY_PATCH_VALUE_ID, mCurrentPatch);
-    }
-
-    private void registerListeners() {
-        mDialog.registerClickListener(SECURITY_PATCH_LABEL_ID, this /* listener */);
-        mDialog.registerClickListener(SECURITY_PATCH_VALUE_ID, this /* listener */);
-    }
-}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelPreferenceController.java
new file mode 100644
index 0000000..1df78a8
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelPreferenceController.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 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.deviceinfo.firmwareversion;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.DeviceInfoUtils;
+
+public class SecurityPatchLevelPreferenceController extends BasePreferenceController {
+
+    private static final String TAG = "SecurityPatchCtrl";
+    private static final Uri INTENT_URI_DATA = Uri.parse(
+            "https://source.android.com/security/bulletin/");
+
+    private final PackageManager mPackageManager;
+    private final String mCurrentPatch;
+
+    public SecurityPatchLevelPreferenceController(Context context, String key) {
+        super(context, key);
+        mPackageManager = mContext.getPackageManager();
+        mCurrentPatch = DeviceInfoUtils.getSecurityPatch();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return !TextUtils.isEmpty(mCurrentPatch)
+                ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return mCurrentPatch;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            return false;
+        }
+
+        final Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_VIEW);
+        intent.setData(INTENT_URI_DATA);
+        if (mPackageManager.queryIntentActivities(intent, 0).isEmpty()) {
+            // Don't send out the intent to stop crash
+            Log.w(TAG, "queryIntentActivities() returns empty");
+            return true;
+        }
+
+        mContext.startActivity(intent);
+        return true;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceController.java
new file mode 100644
index 0000000..c7d4459
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/SimpleBuildNumberPreferenceController.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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.deviceinfo.firmwareversion;
+
+import android.content.Context;
+import android.os.Build;
+import android.text.BidiFormatter;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class SimpleBuildNumberPreferenceController extends BasePreferenceController {
+
+    public SimpleBuildNumberPreferenceController(Context context,
+            String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return BidiFormatter.getInstance().unicodeWrap(Build.DISPLAY);
+    }
+}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
index 5b5d474..9b912a8 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
@@ -80,7 +80,7 @@
     public Slice getSlice() {
         final ListBuilder sliceBuilder =
                 new ListBuilder(mContext, BATTERY_FIX_SLICE_URI, ListBuilder.INFINITY)
-                        .setAccentColor(-1);
+                        .setAccentColor(COLOR_NOT_TINTED);
 
         // TipType.SUMMARY is battery good
         if (UNIMPORTANT_BATTERY_TIPS.contains(readBatteryTipAvailabilityCache(mContext))) {
diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
index 0152614..ae8b80a 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
@@ -142,7 +142,8 @@
     @Override
     public Slice getSlice() {
         final ListBuilder listBuilder =
-                new ListBuilder(mContext, getUri(), ListBuilder.INFINITY).setAccentColor(-1);
+                new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
+                        .setAccentColor(COLOR_NOT_TINTED);
         /**
          * Get package which is satisfied with:
          * 1. Recently installed.
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index cae7d33..cf62112 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -238,8 +238,8 @@
                     UserManager.get(getActivity()),
                     getArguments(),
                     getActivity().getIntent().getExtras()).getIdentifier();
-            mController =
-                    new ChooseLockGenericController(getContext(), mUserId, mRequestedMinComplexity);
+            mController = new ChooseLockGenericController(
+                    getContext(), mUserId, mRequestedMinComplexity, mLockPatternUtils);
             if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction)
                     && UserManager.get(getActivity()).isManagedProfile(mUserId)
                     && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
diff --git a/src/com/android/settings/password/ChooseLockGenericController.java b/src/com/android/settings/password/ChooseLockGenericController.java
index 91ca957..62a0063 100644
--- a/src/com/android/settings/password/ChooseLockGenericController.java
+++ b/src/com/android/settings/password/ChooseLockGenericController.java
@@ -27,6 +27,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.widget.LockPatternUtils;
 import com.android.settings.R;
 
 import java.util.ArrayList;
@@ -43,12 +44,14 @@
     @PasswordComplexity private final int mRequestedMinComplexity;
     private ManagedLockPasswordProvider mManagedPasswordProvider;
     private DevicePolicyManager mDpm;
+    private final LockPatternUtils mLockPatternUtils;
 
     public ChooseLockGenericController(Context context, int userId) {
         this(
                 context,
                 userId,
-                PASSWORD_COMPLEXITY_NONE);
+                PASSWORD_COMPLEXITY_NONE,
+                new LockPatternUtils(context));
     }
 
     /**
@@ -56,13 +59,14 @@
      *                               when determining the available screen lock types
      */
     public ChooseLockGenericController(Context context, int userId,
-            @PasswordComplexity int requestedMinComplexity) {
+            @PasswordComplexity int requestedMinComplexity, LockPatternUtils lockPatternUtils) {
         this(
                 context,
                 userId,
                 requestedMinComplexity,
                 context.getSystemService(DevicePolicyManager.class),
-                ManagedLockPasswordProvider.get(context, userId));
+                ManagedLockPasswordProvider.get(context, userId),
+                lockPatternUtils);
     }
 
     @VisibleForTesting
@@ -71,12 +75,14 @@
             int userId,
             @PasswordComplexity int requestedMinComplexity,
             DevicePolicyManager dpm,
-            ManagedLockPasswordProvider managedLockPasswordProvider) {
+            ManagedLockPasswordProvider managedLockPasswordProvider,
+            LockPatternUtils lockPatternUtils) {
         mContext = context;
         mUserId = userId;
         mRequestedMinComplexity = requestedMinComplexity;
         mManagedPasswordProvider = managedLockPasswordProvider;
         mDpm = dpm;
+        mLockPatternUtils = lockPatternUtils;
     }
 
     /**
@@ -105,6 +111,12 @@
                     && !managedProfile; // Swipe doesn't make sense for profiles.
             case MANAGED:
                 return mManagedPasswordProvider.isManagedPasswordChoosable();
+            case PIN:
+            case PATTERN:
+            case PASSWORD:
+                // Hide the secure lock screen options if the device doesn't support the secure lock
+                // screen feature.
+                return mLockPatternUtils.hasSecureLockScreen();
         }
         return true;
     }
diff --git a/src/com/android/settings/slices/CustomSliceable.java b/src/com/android/settings/slices/CustomSliceable.java
index d32e266..b48f22a 100644
--- a/src/com/android/settings/slices/CustomSliceable.java
+++ b/src/com/android/settings/slices/CustomSliceable.java
@@ -55,6 +55,11 @@
 public interface CustomSliceable extends Sliceable {
 
     /**
+     * The color representing not to be tinted for the slice.
+     */
+    int COLOR_NOT_TINTED = -1;
+
+    /**
      * @return an complete instance of the {@link Slice}.
      */
     Slice getSlice();
diff --git a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
index 5761ae5..fa8c267 100644
--- a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
+++ b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
@@ -16,26 +16,17 @@
 
 package com.android.settings.wifi.slice;
 
-import android.annotation.ColorInt;
 import android.content.Context;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.Drawable;
-import android.net.NetworkInfo.State;
 import android.net.Uri;
 import android.net.wifi.WifiSsid;
 import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
-import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 
-import com.android.settings.R;
-import com.android.settings.Utils;
 import com.android.settings.slices.CustomSliceRegistry;
 import com.android.settings.slices.CustomSliceable;
-import com.android.settingslib.wifi.AccessPoint;
 
 /**
  * {@link CustomSliceable} for Wi-Fi, used by contextual homepage.
@@ -65,36 +56,6 @@
         // keep showing this card to keep UI stable, even if wifi connects to a network later.
         mPreviouslyDisplayed = true;
 
-        // Reload theme for switching dark mode on/off
-        mContext.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);
-
         return super.getSlice();
     }
-
-    @Override
-    protected IconCompat getAccessPointLevelIcon(AccessPoint accessPoint) {
-        final Drawable d = mContext.getDrawable(
-                com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
-
-        @ColorInt int color;
-        if (accessPoint.isActive()) {
-            final State state = accessPoint.getNetworkInfo().getState();
-            if (state == State.CONNECTED) {
-                color = Utils.getColorAccentDefaultColor(mContext);
-            } else { // connecting
-                color = Utils.getDisabled(mContext, Utils.getColorAttrDefaultColor(mContext,
-                        android.R.attr.colorControlNormal));
-            }
-        } else {
-            color = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal);
-        }
-
-        d.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
-        return Utils.createIconWithDrawable(d);
-    }
-
-    @Override
-    protected int getSliceAccentColor() {
-        return -1;
-    }
 }
diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java
index b4b94e1..679ab8b 100644
--- a/src/com/android/settings/wifi/slice/WifiSlice.java
+++ b/src/com/android/settings/wifi/slice/WifiSlice.java
@@ -26,12 +26,21 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.NetworkInfo;
 import android.net.Uri;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiSsid;
 import android.os.Bundle;
+import android.text.Spannable;
+import android.text.SpannableString;
 import android.text.TextUtils;
+import android.text.style.ForegroundColorSpan;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.core.graphics.drawable.IconCompat;
@@ -79,13 +88,15 @@
 
     @Override
     public Slice getSlice() {
+        // Reload theme for switching dark mode on/off
+        mContext.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);
+
         final boolean isWifiEnabled = isWifiEnabled();
 
         final IconCompat icon = IconCompat.createWithResource(mContext,
                 R.drawable.ic_settings_wireless);
         final String title = mContext.getString(R.string.wifi_settings);
         final CharSequence summary = getSummary();
-        @ColorInt final int color = getSliceAccentColor();
         final PendingIntent toggleAction = getBroadcastIntent(mContext);
         final PendingIntent primaryAction = getPrimaryAction();
         final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
@@ -94,7 +105,7 @@
                 null /* actionTitle */, isWifiEnabled);
 
         final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
-                .setAccentColor(color)
+                .setAccentColor(COLOR_NOT_TINTED)
                 .addRow(new ListBuilder.RowBuilder()
                         .setTitle(title)
                         .setSubtitle(summary)
@@ -118,8 +129,7 @@
             if (i < apCount) {
                 listBuilder.addRow(getAccessPointRow(results.get(i)));
             } else if (needLoadingRow) {
-                listBuilder.addRow(new ListBuilder.RowBuilder()
-                        .setTitle(mContext.getText(R.string.wifi_empty_list_wifi_on)));
+                listBuilder.addRow(getLoadingRow());
                 needLoadingRow = false;
             } else {
                 listBuilder.addRow(new ListBuilder.RowBuilder()
@@ -130,11 +140,11 @@
     }
 
     private ListBuilder.RowBuilder getAccessPointRow(AccessPoint accessPoint) {
-        final CharSequence title = accessPoint.getConfigName();
+        final CharSequence title = getAccessPointName(accessPoint);
         final IconCompat levelIcon = getAccessPointLevelIcon(accessPoint);
         final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder()
                 .setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
-                .setTitle(title)
+                .setSubtitle(title)
                 .setPrimaryAction(SliceAction.create(
                         getAccessPointAction(accessPoint), levelIcon, ListBuilder.ICON_IMAGE,
                         title));
@@ -146,14 +156,35 @@
         return rowBuilder;
     }
 
-    protected IconCompat getAccessPointLevelIcon(AccessPoint accessPoint) {
-        return IconCompat.createWithResource(mContext,
-                com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
+    private CharSequence getAccessPointName(AccessPoint accessPoint) {
+        final CharSequence name = accessPoint.getConfigName();
+        final Spannable span = new SpannableString(name);
+        @ColorInt final int color = Utils.getColorAttrDefaultColor(mContext,
+                android.R.attr.textColorPrimary);
+        span.setSpan(new ForegroundColorSpan(color), 0, name.length(),
+                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        return span;
     }
 
-    @ColorInt
-    protected int getSliceAccentColor() {
-        return Utils.getColorAccentDefaultColor(mContext);
+    private IconCompat getAccessPointLevelIcon(AccessPoint accessPoint) {
+        final Drawable d = mContext.getDrawable(
+                com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
+
+        @ColorInt int color;
+        if (accessPoint.isActive()) {
+            final NetworkInfo.State state = accessPoint.getNetworkInfo().getState();
+            if (state == NetworkInfo.State.CONNECTED) {
+                color = Utils.getColorAccentDefaultColor(mContext);
+            } else { // connecting
+                color = Utils.getDisabled(mContext, Utils.getColorAttrDefaultColor(mContext,
+                        android.R.attr.colorControlNormal));
+            }
+        } else {
+            color = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal);
+        }
+
+        d.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
+        return Utils.createIconWithDrawable(d);
     }
 
     private IconCompat getEndIcon(AccessPoint accessPoint) {
@@ -190,6 +221,18 @@
                 intent, 0 /* flags */);
     }
 
+    private ListBuilder.RowBuilder getLoadingRow() {
+        final CharSequence title = mContext.getText(R.string.wifi_empty_list_wifi_on);
+
+        // for aligning to the Wi-Fi AP's name
+        final IconCompat emptyIcon = Utils.createIconWithDrawable(
+                new ColorDrawable(Color.TRANSPARENT));
+
+        return new ListBuilder.RowBuilder()
+                .setTitleItem(emptyIcon, ListBuilder.ICON_IMAGE)
+                .setSubtitle(title);
+    }
+
     /**
      * Update the current wifi status to the boolean value keyed by
      * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}.
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
index 53fac3c..139ef41 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -65,6 +66,8 @@
     private ImageView mImageView;
     @Mock
     private CachedBluetoothDevice mCachedDevice;
+    @Mock
+    private BluetoothAdapter mBluetoothAdapter;
     private AdvancedBluetoothDetailsHeaderController mController;
     private LayoutPreference mLayoutPreference;
 
@@ -78,6 +81,7 @@
         mLayoutPreference = new LayoutPreference(mContext,
                 LayoutInflater.from(mContext).inflate(R.layout.advanced_bt_entity_header, null));
         mController.mLayoutPreference = mLayoutPreference;
+        mController.mBluetoothAdapter = mBluetoothAdapter;
         when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
     }
 
@@ -159,6 +163,21 @@
         verify(mImageView).setImageBitmap(mBitmap);
     }
 
+    @Test
+    public void onStart_registerCallback() {
+        mController.onStart();
+
+        verify(mBluetoothAdapter).registerMetadataListener(mBluetoothDevice,
+                mController.mMetadataListener, mController.mHandler);
+    }
+
+    @Test
+    public void onStop_unregisterCallback() {
+        mController.onStop();
+
+        verify(mBluetoothAdapter).unregisterMetadataListener(mBluetoothDevice);
+    }
+
     private void assertBatteryLevel(LinearLayout linearLayout, int batteryLevel) {
         final TextView textView = linearLayout.findViewById(R.id.bt_battery_summary);
         assertThat(textView.getText().toString()).isEqualTo(
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java
index 887f58c..a921215 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java
@@ -17,30 +17,40 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothDevice;
 import android.net.Uri;
 
 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;
 
 @RunWith(RobolectricTestRunner.class)
 public class BluetoothFeatureProviderImplTest {
-    private static final String PARAMETER_KEY = "addr";
-    private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
+    private static final String SETTINGS_URI = "content://test.provider/settings_uri";
     private BluetoothFeatureProvider mBluetoothFeatureProvider;
 
+    @Mock
+    private BluetoothDevice mBluetoothDevice;
+
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
         mBluetoothFeatureProvider = new BluetoothFeatureProviderImpl(
                 RuntimeEnvironment.application);
     }
 
     @Test
     public void getBluetoothDeviceSettingsUri_containCorrectMacAddress() {
-        final Uri uri = mBluetoothFeatureProvider.getBluetoothDeviceSettingsUri(MAC_ADDRESS);
-        assertThat(uri.getQueryParameterNames()).containsExactly(PARAMETER_KEY);
-        assertThat(uri.getQueryParameter(PARAMETER_KEY)).isEqualTo(MAC_ADDRESS);
+        when(mBluetoothDevice.getMetadata(
+                BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI)).thenReturn(SETTINGS_URI);
+        final Uri uri = mBluetoothFeatureProvider.getBluetoothDeviceSettingsUri(mBluetoothDevice);
+        assertThat(uri.toString()).isEqualTo(SETTINGS_URI);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java
similarity index 60%
rename from tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionDialogControllerTest.java
rename to tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java
index 0f56164..5f4848f 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionDialogControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -16,15 +16,12 @@
 
 package com.android.settings.deviceinfo.firmwareversion;
 
-import static com.android.settings.deviceinfo.firmwareversion.BasebandVersionDialogController
-        .BASEBAND_PROPERTY;
-import static com.android.settings.deviceinfo.firmwareversion.BasebandVersionDialogController
-        .BASEBAND_VERSION_LABEL_ID;
-import static com.android.settings.deviceinfo.firmwareversion.BasebandVersionDialogController
-        .BASEBAND_VERSION_VALUE_ID;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+import static com.android.settings.deviceinfo.firmwareversion.BasebandVersionPreferenceController.BASEBAND_PROPERTY;
 
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.robolectric.shadow.api.Shadow.extract;
 
 import android.content.Context;
@@ -36,7 +33,6 @@
 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;
@@ -44,44 +40,35 @@
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = ShadowConnectivityManager.class)
-public class BasebandVersionDialogControllerTest {
-
-    @Mock
-    private FirmwareVersionDialogFragment mDialog;
+public class BasebandVersionPreferenceControllerTest {
 
     private Context mContext;
-    private BasebandVersionDialogController mController;
+    private BasebandVersionPreferenceController mController;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
-        when(mDialog.getContext()).thenReturn(mContext);
-        mController = new BasebandVersionDialogController(mDialog);
+        mController = new BasebandVersionPreferenceController(mContext, "key");
     }
 
     @Test
-    public void initialize_wifiOnly_shouldRemoveSettingFromDialog() {
-        ShadowConnectivityManager connectivityManager =
+    public void getAvailability_wifiOnly_unavailable() {
+        final ShadowConnectivityManager connectivityManager =
                 extract(mContext.getSystemService(ConnectivityManager.class));
         connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
 
-        mController.initialize();
-
-        verify(mDialog).removeSettingFromScreen(BASEBAND_VERSION_LABEL_ID);
-        verify(mDialog).removeSettingFromScreen(BASEBAND_VERSION_VALUE_ID);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
     }
 
     @Test
-    public void initialize_hasMobile_shouldSetDialogTextToBasebandVersion() {
+    public void getAvailability_hasMobile_available() {
         final String text = "test";
         SystemProperties.set(BASEBAND_PROPERTY, text);
         ShadowConnectivityManager connectivityManager =
                 extract(mContext.getSystemService(ConnectivityManager.class));
         connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true);
 
-        mController.initialize();
-
-        verify(mDialog).setText(BASEBAND_VERSION_VALUE_ID, text);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BuildNumberDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BuildNumberDialogControllerTest.java
deleted file mode 100644
index a1e8813..0000000
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BuildNumberDialogControllerTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.deviceinfo.firmwareversion;
-
-import static com.android.settings.deviceinfo.firmwareversion.BuildNumberDialogController
-        .BUILD_NUMBER_VALUE_ID;
-
-import static org.mockito.Mockito.verify;
-
-import android.os.Build;
-import android.text.BidiFormatter;
-
-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 BuildNumberDialogControllerTest {
-
-    @Mock
-    private FirmwareVersionDialogFragment mDialog;
-
-    private BuildNumberDialogController mController;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        mController = new BuildNumberDialogController(mDialog);
-    }
-
-    @Test
-    public void initialize_shouldUpdateBuildNumberToDialog() {
-        mController.initialize();
-
-        verify(mDialog)
-            .setText(BUILD_NUMBER_VALUE_ID, BidiFormatter.getInstance().unicodeWrap(Build.DISPLAY));
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceControllerTest.java
similarity index 64%
rename from tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogControllerTest.java
rename to tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceControllerTest.java
index 0c57941..adfff25 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDetailPreferenceControllerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -16,13 +16,9 @@
 
 package com.android.settings.deviceinfo.firmwareversion;
 
-import static com.android.settings.deviceinfo.firmwareversion.FirmwareVersionDialogController
-        .FIRMWARE_VERSION_LABEL_ID;
-import static com.android.settings.deviceinfo.firmwareversion.FirmwareVersionDialogController
-        .FIRMWARE_VERSION_VALUE_ID;
+import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -32,7 +28,8 @@
 import android.content.Context;
 import android.os.Build;
 import android.os.UserManager;
-import android.view.View;
+
+import androidx.preference.Preference;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -44,36 +41,30 @@
 import org.robolectric.util.ReflectionHelpers;
 
 @RunWith(RobolectricTestRunner.class)
-public class FirmwareVersionDialogControllerTest {
+public class FirmwareVersionDetailPreferenceControllerTest {
 
     @Mock
     private UserManager mUserManager;
-    @Mock
-    private FirmwareVersionDialogFragment mDialog;
-    @Mock
-    private View mView;
 
+    private Preference mPreference;
     private Context mContext;
-    private FirmwareVersionDialogController mController;
+    private FirmwareVersionDetailPreferenceController mController;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
-        when(mDialog.getContext()).thenReturn(mContext);
-        mController = spy(new FirmwareVersionDialogController(mDialog));
+        mController = spy(new TestController(mContext, "key"));
+
         ReflectionHelpers.setField(mController, "mUserManager", mUserManager);
-        doNothing().when(mController).arrayCopy();
-        doNothing().when(mController).initializeAdminPermissions();
+
+        mPreference = new Preference(mContext);
+        mPreference.setKey(mController.getPreferenceKey());
     }
 
     @Test
-    public void initialize_shouldRegisterListenersAndSetBuildVersion() {
-        mController.initialize();
-
-        verify(mDialog).registerClickListener(eq(FIRMWARE_VERSION_VALUE_ID), any());
-        verify(mDialog).registerClickListener(eq(FIRMWARE_VERSION_LABEL_ID), any());
-        verify(mDialog).setText(FIRMWARE_VERSION_VALUE_ID, Build.VERSION.RELEASE);
+    public void getSummary_shouldGetBuildVersion() {
+        assertThat(mController.getSummary()).isEqualTo(Build.VERSION.RELEASE);
     }
 
     @Test
@@ -82,7 +73,7 @@
         hits[0] = Long.MAX_VALUE;
         when(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN)).thenReturn(true);
 
-        mController.onClick(mView);
+        mController.handlePreferenceTreeClick(mPreference);
 
         verify(mContext, never()).startActivity(any());
     }
@@ -93,8 +84,19 @@
         hits[0] = Long.MAX_VALUE;
         when(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN)).thenReturn(false);
 
-        mController.onClick(mView);
+        mController.handlePreferenceTreeClick(mPreference);
 
         verify(mContext).startActivity(any());
     }
+
+    private static class TestController extends FirmwareVersionDetailPreferenceController {
+
+        public TestController(Context context, String key) {
+            super(context, key);
+        }
+
+        @Override
+        void initializeAdminPermissions() {
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceControllerTest.java
index 0c74525..77ae4e2 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionPreferenceControllerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -16,42 +16,29 @@
 
 package com.android.settings.deviceinfo.firmwareversion;
 
-import static android.content.Context.CLIPBOARD_SERVICE;
-
 import static com.google.common.truth.Truth.assertThat;
 
-import android.content.ClipboardManager;
 import android.content.Context;
 import android.os.Build;
 
-import androidx.fragment.app.Fragment;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.core.BasePreferenceController;
 
-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.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.Resetter;
 
 @RunWith(RobolectricTestRunner.class)
 public class FirmwareVersionPreferenceControllerTest {
 
     private static final String KEY = "firmware_version";
 
-    @Mock
-    private Fragment mFragment;
-
     private Preference mPreference;
     private PreferenceScreen mScreen;
     private FirmwareVersionPreferenceController mController;
@@ -62,22 +49,16 @@
         final Context context = RuntimeEnvironment.application;
         final PreferenceManager preferenceManager = new PreferenceManager(context);
         mController = new FirmwareVersionPreferenceController(context, KEY);
-        mController.setHost(mFragment);
         mPreference = new Preference(context);
         mPreference.setKey(KEY);
         mScreen = preferenceManager.createPreferenceScreen(context);
         mScreen.addPreference(mPreference);
     }
 
-    @After
-    public void tearDown() {
-        ShadowFirmwareVersionDialogFragment.reset();
-    }
-
     @Test
     public void firmwareVersion_shouldAlwaysBeShown() {
-        assertThat(mController.getAvailabilityStatus()).isEqualTo(
-                BasePreferenceController.AVAILABLE);
+        assertThat(mController.getAvailabilityStatus())
+                .isEqualTo(BasePreferenceController.AVAILABLE_UNSEARCHABLE);
     }
 
     @Test
@@ -86,55 +67,4 @@
 
         assertThat(mPreference.getSummary()).isEqualTo(Build.VERSION.RELEASE);
     }
-
-    @Test
-    @Config(shadows = ShadowFirmwareVersionDialogFragment.class)
-    public void handlePreferenceTreeClick_samePreferenceKey_shouldStartDialogFragment() {
-        final boolean result = mController.handlePreferenceTreeClick(mPreference);
-
-        assertThat(ShadowFirmwareVersionDialogFragment.isShowing).isTrue();
-        assertThat(result).isTrue();
-    }
-
-    @Test
-    public void handlePreferenceTreeClick_unknownPreferenceKey_shouldDoNothingAndReturnFalse() {
-        mPreference.setKey("foobar");
-
-        final boolean result = mController.handlePreferenceTreeClick(mPreference);
-
-        assertThat(ShadowFirmwareVersionDialogFragment.isShowing).isFalse();
-        assertThat(result).isFalse();
-    }
-
-    @Test
-    public void isSliceable_shouldBeTrue() {
-        assertThat(mController.isSliceable()).isTrue();
-    }
-
-    @Test
-    public void copy_shouldCopyVersionNumberToClipboard() {
-        mController.copy();
-
-        final Context context = RuntimeEnvironment.application;
-        final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(
-                CLIPBOARD_SERVICE);
-        final CharSequence data = clipboard.getPrimaryClip().getItemAt(0).getText();
-        assertThat(data.toString()).isEqualTo(Build.VERSION.RELEASE);
-    }
-
-    @Implements(FirmwareVersionDialogFragment.class)
-    public static class ShadowFirmwareVersionDialogFragment {
-
-        private static boolean isShowing = false;
-
-        @Implementation
-        public static void show(Fragment fragemnt) {
-            isShowing = true;
-        }
-
-        @Resetter
-        public static void reset() {
-            isShowing = false;
-        }
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionDialogControllerTest.java
deleted file mode 100644
index 52af280..0000000
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionDialogControllerTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.deviceinfo.firmwareversion;
-
-import static com.android.settings.deviceinfo.firmwareversion.KernelVersionDialogController
-        .KERNEL_VERSION_VALUE_ID;
-
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-
-import com.android.settingslib.DeviceInfoUtils;
-
-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;
-
-@RunWith(RobolectricTestRunner.class)
-public class KernelVersionDialogControllerTest {
-
-    @Mock
-    private FirmwareVersionDialogFragment mDialog;
-
-    private Context mContext;
-    private KernelVersionDialogController mController;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        when(mDialog.getContext()).thenReturn(mContext);
-        mController = new KernelVersionDialogController(mDialog);
-    }
-
-    @Test
-    public void initialize_shouldUpdateKernelVersionToDialog() {
-        mController.initialize();
-
-        verify(mDialog)
-            .setText(KERNEL_VERSION_VALUE_ID, DeviceInfoUtils.getFormattedKernelVersion(mContext));
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionPreferenceControllerTest.java
new file mode 100644
index 0000000..9ee0bb3
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/KernelVersionPreferenceControllerTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 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.deviceinfo.firmwareversion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import com.android.settingslib.DeviceInfoUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class KernelVersionPreferenceControllerTest {
+
+
+    private Context mContext;
+    private KernelVersionPreferenceController mController;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mController = new KernelVersionPreferenceController(mContext, "key");
+    }
+
+    @Test
+    public void getSummary_shouldGetKernalVersion() {
+        assertThat(mController.getSummary()).isEqualTo(
+                DeviceInfoUtils.getFormattedKernelVersion(mContext));
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
new file mode 100644
index 0000000..2761b2f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2019 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.deviceinfo.firmwareversion;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.FeatureFlags;
+
+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;
+
+@RunWith(RobolectricTestRunner.class)
+public class MainlineModuleVersionPreferenceControllerTest {
+
+    @Mock
+    private PackageManager mPackageManager;
+
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+
+        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.MAINLINE_MODULE, true);
+    }
+
+    @Test
+    public void getAvailabilityStatus_featureDisabled_unavailable() {
+        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.MAINLINE_MODULE, false);
+
+        final MainlineModuleVersionPreferenceController controller =
+                new MainlineModuleVersionPreferenceController(mContext, "key");
+
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_noMainlineModuleProvider_unavailable() {
+        when(mContext.getString(
+                com.android.internal.R.string.config_defaultModuleMetadataProvider)).thenReturn(
+                null);
+
+        final MainlineModuleVersionPreferenceController controller =
+                new MainlineModuleVersionPreferenceController(mContext, "key");
+
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_noMainlineModulePackageInfo_unavailable() throws Exception {
+
+        final String provider = "test.provider";
+        when(mContext.getString(
+                com.android.internal.R.string.config_defaultModuleMetadataProvider))
+                .thenReturn(provider);
+        when(mPackageManager.getPackageInfo(eq(provider), anyInt()))
+                .thenThrow(new PackageManager.NameNotFoundException());
+
+        final MainlineModuleVersionPreferenceController controller =
+                new MainlineModuleVersionPreferenceController(mContext, "key");
+
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_hasMainlineModulePackageInfo_available() throws Exception {
+        final String provider = "test.provider";
+        final String version = "test version 123";
+        final PackageInfo info = new PackageInfo();
+        info.versionName = version;
+        when(mContext.getString(
+                com.android.internal.R.string.config_defaultModuleMetadataProvider))
+                .thenReturn(provider);
+        when(mPackageManager.getPackageInfo(eq(provider), anyInt())).thenReturn(info);
+
+        final MainlineModuleVersionPreferenceController controller =
+                new MainlineModuleVersionPreferenceController(mContext, "key");
+
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogControllerTest.java
deleted file mode 100644
index b84ea99..0000000
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogControllerTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2019 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.deviceinfo.firmwareversion;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.util.FeatureFlagUtils;
-
-import com.android.settings.core.FeatureFlags;
-
-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;
-
-@RunWith(RobolectricTestRunner.class)
-public class ModuleVersionDialogControllerTest {
-
-    @Mock
-    private FirmwareVersionDialogFragment mDialog;
-    @Mock
-    private PackageManager mPackageManager;
-
-    private Context mContext;
-    private ModuleVersionDialogController mController;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(RuntimeEnvironment.application);
-        when(mDialog.getContext()).thenReturn(mContext);
-        when(mContext.getPackageManager()).thenReturn(mPackageManager);
-        mController = new ModuleVersionDialogController(mDialog);
-        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.MAINLINE_MODULE, true);
-    }
-
-    @Test
-    public void initialize_featureDisabled_shouldRemoveSettingFromDialog() {
-        FeatureFlagUtils.setEnabled(mContext, FeatureFlags.MAINLINE_MODULE, false);
-
-        mController.initialize();
-
-        verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_LABEL_ID);
-        verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_VALUE_ID);
-    }
-
-    @Test
-    public void initialize_noMainlineModuleProvider_shouldRemoveSettingFromDialog() {
-        when(mContext.getString(
-            com.android.internal.R.string.config_defaultModuleMetadataProvider)).thenReturn(null);
-
-        mController.initialize();
-
-        verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_LABEL_ID);
-        verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_VALUE_ID);
-    }
-
-    @Test
-    public void initialize_noMainlineModulePackageInfo_shouldRemoveSettingFromDialog()
-            throws PackageManager.NameNotFoundException {
-        final String provider = "test.provider";
-        when(mContext.getString(
-            com.android.internal.R.string.config_defaultModuleMetadataProvider))
-            .thenReturn(provider);
-        when(mPackageManager.getPackageInfo(eq(provider), anyInt()))
-            .thenThrow(new PackageManager.NameNotFoundException());
-
-        mController.initialize();
-
-        verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_LABEL_ID);
-        verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_VALUE_ID);
-    }
-
-    @Test
-    public void initialize_hasMainlineModulePackageInfo_shouldshouldSetDialogTextToMainlineVersion()
-            throws PackageManager.NameNotFoundException {
-        final String provider = "test.provider";
-        final String version = "test version 123";
-        final PackageInfo info = new PackageInfo();
-        info.versionName = version;
-        when(mContext.getString(
-            com.android.internal.R.string.config_defaultModuleMetadataProvider))
-            .thenReturn(provider);
-        when(mPackageManager.getPackageInfo(eq(provider), anyInt())).thenReturn(info);
-
-        mController.initialize();
-
-        verify(mDialog).setText(mController.MODULE_VERSION_VALUE_ID, version);
-    }
-
-}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelPreferenceControllerTest.java
similarity index 62%
rename from tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelDialogControllerTest.java
rename to tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelPreferenceControllerTest.java
index 8c334cc..ccc91e6 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelDialogControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/SecurityPatchLevelPreferenceControllerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -16,14 +16,13 @@
 
 package com.android.settings.deviceinfo.firmwareversion;
 
-import static com.android.settings.deviceinfo.firmwareversion.SecurityPatchLevelDialogController
-        .SECURITY_PATCH_LABEL_ID;
-import static com.android.settings.deviceinfo.firmwareversion.SecurityPatchLevelDialogController
-        .SECURITY_PATCH_VALUE_ID;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+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.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -33,7 +32,8 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Build;
-import android.view.View;
+
+import androidx.preference.Preference;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -47,55 +47,47 @@
 import java.util.Collections;
 
 @RunWith(RobolectricTestRunner.class)
-public class SecurityPatchLevelDialogControllerTest {
+public class SecurityPatchLevelPreferenceControllerTest {
 
     @Mock
     private PackageManager mPackageManager;
-    @Mock
-    private FirmwareVersionDialogFragment mDialog;
-    @Mock
-    private View mView;
 
     private Context mContext;
-    private SecurityPatchLevelDialogController mController;
+    private SecurityPatchLevelPreferenceController mController;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mContext = spy(Robolectric.setupActivity(Activity.class));
-        when(mDialog.getContext()).thenReturn(mContext);
     }
 
     @Test
-    public void initialize_noPatchInfo_shouldRemoveSettingFromDialog() {
+    public void getAvailabilityStatus_noPatchInfo_unavailable() {
         ReflectionHelpers.setStaticField(Build.VERSION.class, "SECURITY_PATCH", "");
-        mController = new SecurityPatchLevelDialogController(mDialog);
+        mController = new SecurityPatchLevelPreferenceController(mContext, "key");
 
-        mController.initialize();
-
-        verify(mDialog).removeSettingFromScreen(SECURITY_PATCH_VALUE_ID);
-        verify(mDialog).removeSettingFromScreen(SECURITY_PATCH_LABEL_ID);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
     }
 
     @Test
-    public void initialize_patchInfoAvailable_shouldRegisterListeners() {
+    public void getAvailabilityStatus_hasPatchInfo_available() {
         ReflectionHelpers.setStaticField(Build.VERSION.class, "SECURITY_PATCH", "foobar");
-        mController = new SecurityPatchLevelDialogController(mDialog);
+        mController = new SecurityPatchLevelPreferenceController(mContext, "key");
 
-        mController.initialize();
-
-        verify(mDialog).registerClickListener(eq(SECURITY_PATCH_LABEL_ID), any());
-        verify(mDialog).registerClickListener(eq(SECURITY_PATCH_VALUE_ID), any());
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 
     @Test
     public void onClick_noActivityIntent_shouldDoNothing() {
         when(mPackageManager.queryIntentActivities(any(), anyInt()))
                 .thenReturn(Collections.emptyList());
-        mController = new SecurityPatchLevelDialogController(mDialog);
+        mController = new SecurityPatchLevelPreferenceController(mContext, "key");
         ReflectionHelpers.setField(mController, "mPackageManager", mPackageManager);
 
-        mController.onClick(mView);
+        final Preference pref = new Preference(mContext);
+        pref.setKey(mController.getPreferenceKey());
+
+        mController.handlePreferenceTreeClick(pref);
 
         verify(mContext, never()).startActivity(any());
     }
@@ -104,10 +96,14 @@
     public void onClick_activityIntentFound_shouldStartActivity() {
         when(mPackageManager.queryIntentActivities(any(), anyInt()))
                 .thenReturn(Collections.singletonList(null));
-        mController = new SecurityPatchLevelDialogController(mDialog);
+
+        mController = new SecurityPatchLevelPreferenceController(mContext, "key");
         ReflectionHelpers.setField(mController, "mPackageManager", mPackageManager);
 
-        mController.onClick(mView);
+        final Preference pref = new Preference(mContext);
+        pref.setKey(mController.getPreferenceKey());
+
+        mController.handlePreferenceTreeClick(pref);
 
         verify(mContext).startActivity(any());
     }
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
index 2b7bdeb..4adc01b 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
@@ -34,6 +34,7 @@
 import android.app.admin.DevicePolicyManager.PasswordComplexity;
 import android.content.ComponentName;
 
+import com.android.internal.widget.LockPatternUtils;
 import com.android.settings.R;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
 
@@ -61,10 +62,14 @@
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
 
+    @Mock
+    private LockPatternUtils mLockPatternUtils;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(true);
         mController = createController(PASSWORD_COMPLEXITY_NONE);
         SettingsShadowResources.overrideResource(R.bool.config_hide_none_security_option, false);
         SettingsShadowResources.overrideResource(R.bool.config_hide_swipe_security_option, false);
@@ -266,6 +271,7 @@
                 0 /* userId */,
                 minPasswordComplexity,
                 mDevicePolicyManager,
-                mManagedLockPasswordProvider);
+                mManagedLockPasswordProvider,
+                mLockPatternUtils);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java
index 195c82d..9e8644f 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java
@@ -33,6 +33,7 @@
 import com.android.settings.R;
 import com.android.settings.password.ChooseLockTypeDialogFragment.OnLockTypeSelectedListener;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -43,7 +44,7 @@
 import org.robolectric.shadows.androidx.fragment.FragmentController;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowAlertDialogCompat.class)
+@Config(shadows = {ShadowAlertDialogCompat.class, ShadowLockPatternUtils.class})
 public class ChooseLockTypeDialogFragmentTest {
 
     private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
index e0c6ded..aeb16e6 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
@@ -34,6 +34,7 @@
 import com.android.settings.password.SetupChooseLockPassword.SetupChooseLockPasswordFragment;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
 import com.android.settings.testutils.shadow.ShadowUtils;
 import com.android.settings.widget.ScrollToParentEditText;
 
@@ -57,7 +58,13 @@
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {SettingsShadowResources.class, ShadowUtils.class, ShadowAlertDialogCompat.class})
+@Config(
+        shadows = {
+                SettingsShadowResources.class,
+                ShadowLockPatternUtils.class,
+                ShadowUtils.class,
+                ShadowAlertDialogCompat.class
+        })
 public class SetupChooseLockPasswordTest {
 
     @Before
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
index 430c535..4852546 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
@@ -38,6 +38,7 @@
 import com.android.settings.password.ChooseLockPattern.ChooseLockPatternFragment;
 import com.android.settings.password.ChooseLockPattern.IntentBuilder;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
 import com.android.settings.testutils.shadow.ShadowUtils;
 
 import com.google.android.setupcompat.PartnerCustomizationLayout;
@@ -57,7 +58,7 @@
 import java.util.Arrays;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowUtils.class, ShadowAlertDialogCompat.class})
+@Config(shadows = {ShadowUtils.class, ShadowAlertDialogCompat.class, ShadowLockPatternUtils.class})
 public class SetupChooseLockPatternTest {
 
     private SetupChooseLockPattern mActivity;
diff --git a/tests/robotests/src/com/android/settings/testutils/SliceTester.java b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
index 17edb6e..d84d42c 100644
--- a/tests/robotests/src/com/android/settings/testutils/SliceTester.java
+++ b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
@@ -238,22 +238,38 @@
      * @param title Title for asserting.
      */
     public static void assertAnySliceItemContainsTitle(List<SliceItem> sliceItems, String title) {
-        boolean hasTitle = false;
+        assertThat(hasText(sliceItems, title, HINT_TITLE)).isTrue();
+    }
+
+    /**
+     * Assert any slice item contains subtitle.
+     *
+     * @param sliceItems All slice items of a Slice.
+     * @param subtitle Subtitle for asserting.
+     */
+    public static void assertAnySliceItemContainsSubtitle(List<SliceItem> sliceItems,
+            String subtitle) {
+        // Subtitle has no hints
+        assertThat(hasText(sliceItems, subtitle, null /* hints */)).isTrue();
+    }
+
+    private static boolean hasText(List<SliceItem> sliceItems, String text, String hints) {
+        boolean hasText = false;
         for (SliceItem item : sliceItems) {
-            List<SliceItem> titleItems = SliceQuery.findAll(item, FORMAT_TEXT, HINT_TITLE,
+            List<SliceItem> textItems = SliceQuery.findAll(item, FORMAT_TEXT, hints,
                     null /* non-hints */);
-            if (titleItems == null) {
+            if (textItems == null) {
                 continue;
             }
 
-            for (SliceItem subTitleItem : titleItems) {
-                if (TextUtils.equals(subTitleItem.getText(), title)) {
-                    hasTitle = true;
+            for (SliceItem textItem : textItems) {
+                if (TextUtils.equals(textItem.getText(), text)) {
+                    hasText = true;
                     break;
                 }
             }
         }
-        assertThat(hasTitle).isTrue();
+        return hasText;
     }
 
     private static void assertKeywords(SliceMetadata metadata, SliceData data) {
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
index 7ce098d..f287085 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
@@ -32,6 +32,11 @@
     private static boolean sDeviceEncryptionEnabled;
 
     @Implementation
+    protected boolean hasSecureLockScreen() {
+        return true;
+    }
+
+    @Implementation
     protected boolean isSecure(int id) {
         return true;
     }
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
index dd99e55..6af8f80 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
@@ -118,7 +118,7 @@
         // All AP rows + title row
         assertThat(rows).isEqualTo(DEFAULT_EXPANDED_ROW_COUNT + 1);
         // Has scanning text
-        SliceTester.assertAnySliceItemContainsTitle(sliceItems,
+        SliceTester.assertAnySliceItemContainsSubtitle(sliceItems,
                 mContext.getString(R.string.wifi_empty_list_wifi_on));
     }