Merge "Add sliceUri in broadcast intent"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index caca444..3933b9c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -717,8 +717,7 @@
             android:name="Settings$ZenModeSettingsActivity"
             android:label="@string/zen_mode_settings_title"
             android:icon="@drawable/ic_notifications"
-            android:exported="true"
-            android:parentActivityName="Settings">
+            android:exported="true">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.ZEN_MODE_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -875,8 +874,7 @@
             android:name="Settings$NightDisplaySettingsActivity"
             android:label="@string/night_display_title"
             android:enabled="@*android:bool/config_nightDisplayAvailable"
-            android:icon="@drawable/ic_settings_night_display"
-            android:parentActivityName="Settings">
+            android:icon="@drawable/ic_settings_night_display">
             <intent-filter android:priority="32">
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.android.settings.SHORTCUT" />
@@ -1626,7 +1624,7 @@
             android:icon="@drawable/ic_settings_security">
             <intent-filter android:priority="1">
                 <action android:name="android.intent.action.MAIN" />
-                <category android:name="com.android.settings.suggested.category.LOCK_SCREEN" />
+                <category android:name="com.android.settings.suggested.category.DEFAULT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.title"
                        android:resource="@string/suggested_lock_settings_title" />
@@ -2821,10 +2819,8 @@
             android:name=".Settings$AppAndNotificationDashboardActivity"
             android:label="@string/app_and_notification_dashboard_title"
             android:icon="@drawable/ic_homepage_apps"
-            android:parentActivityName="Settings">
-            <intent-filter>
-                <action android:name="com.android.settings.action.SETTINGS"/>
-            </intent-filter>
+            android:parentActivityName="Settings"
+            android:exported="true">
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                        android:value="com.android.settings.applications.AppAndNotificationDashboardFragment"/>
         </activity>
diff --git a/res/layout/slice_preference_layout.xml b/res/layout/slice_preference_layout.xml
new file mode 100644
index 0000000..4cea9c0
--- /dev/null
+++ b/res/layout/slice_preference_layout.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 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.
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+    <androidx.slice.widget.SliceView
+        android:id="@+id/slice_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+</FrameLayout>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 86763b7..383506d 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -52,6 +52,8 @@
 
     <attr name="apnPreferenceStyle" format="reference" />
 
+    <attr name="slicePreferenceStyle" format="reference" />
+
     <attr name="footerPreferenceStyle" format="reference" />
 
     <declare-styleable name="FixedLineSummaryPreference">
diff --git a/res/values/config.xml b/res/values/config.xml
index edd948f7..7108cbd 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -165,4 +165,7 @@
 
     <!-- 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>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1aaa374..d07cc53 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6963,6 +6963,8 @@
     <string name="keywords_sim_status">network, mobile network state, service state, signal strength, mobile network type, roaming, iccid</string>
     <string name="keywords_model_and_hardware">serial number, hardware version</string>
     <string name="keywords_android_version">android security patch level, baseband version, kernel version</string>
+    <!--Search keywords for financial apps sms access settings -->
+    <string name="keywords_financial_apps_sms_access">financial app, sms, permission</string>
 
     <!-- Search keyword for Device Theme Settings [CHAR LIMIT=NONE] -->
     <string name="keywords_systemui_theme">dark theme</string>
@@ -8853,6 +8855,10 @@
     <!-- Summary of number of apps currently can write system settings [CHAR LIMIT=60] -->
     <string name="write_settings_summary"><xliff:g id="count" example="10">%1$d</xliff:g> of <xliff:g id="count" example="10">%2$d</xliff:g> apps allowed to modify system settings</string>
 
+    <!-- Settings title in main settings screen for financial apps sms access [CHAR LIMIT=60] -->
+    <string name="financial_apps_sms_access_title">Financial Apps Sms Access</string>
+    <!-- Preference key for financial apps sms access screen -->
+    <string name="financial_sms_root_screen_key" translatable="false">financial_sms_root_screen_key</string>
     <!-- Label for showing apps that can install other apps [CHAR LIMIT=45] -->
     <string name="filter_install_sources_apps">Can install other apps</string>
     <!-- Label for showing apps that can write system settings [CHAR LIMIT=45] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 48cd876..15ec46d 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -489,4 +489,8 @@
         <item name="android:textAllCaps">false</item>
     </style>
 
+    <style name="Widget.SliceView.Settings">
+        <item name="titleSize">@*android:dimen/text_size_subhead_material</item>
+    </style>
+
 </resources>
diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml
index 0f7ecab..f25289d 100644
--- a/res/values/styles_preference.xml
+++ b/res/values/styles_preference.xml
@@ -21,6 +21,7 @@
 
     <style name="PreferenceTheme" parent="@style/PreferenceThemeOverlay.SettingsBase">
         <item name="apnPreferenceStyle">@style/ApnPreference</item>
+        <item name="slicePreferenceStyle">@style/SlicePreference</item>
         <item name="seekBarPreferenceStyle">@style/SettingsSeekBarPreference</item>
         <item name="twoStateButtonPreferenceStyle">@style/TwoStateButtonPreference</item>
     </style>
@@ -34,6 +35,10 @@
         <item name="android:layout">@layout/apn_preference_layout</item>
     </style>
 
+    <style name="SlicePreference" parent="@style/Preference.Material">
+        <item name="android:layout">@layout/slice_preference_layout</item>
+    </style>
+
     <style name="SettingsSeekBarPreference" parent="@style/Preference.Material">
         <item name="android:layout">@layout/preference_widget_seekbar_settings</item>
     </style>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 390be584..f22d111 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -32,9 +32,13 @@
         <item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
         <item name="face_layout_theme">@style/FaceLayoutTheme</item>
         <item name="ic_menu_moreoverflow">@*android:drawable/ic_menu_moreoverflow_holo_dark</item>
+
+        <!-- For wifi icon -->
         <item name="wifi_signal">@drawable/wifi_signal</item>
         <item name="wifi_signal_color">?android:attr/colorAccent</item>
         <item name="wifi_friction">@drawable/wifi_friction</item>
+        <item name="frictionIconColor">?android:colorControlNormal</item>
+
         <item name="side_margin">@dimen/settings_side_margin</item>
         <item name="suwListItemIconColor">?android:attr/colorAccent</item>
 
@@ -58,6 +62,9 @@
         <!-- TODO(118444000): Remove colorPrimary and colorPrimaryVariant -->
         <item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
         <item name="colorPrimaryVariant">@android:color/white</item>
+
+        <!-- For slice view in settings -->
+        <item name="sliceViewStyle">@style/Widget.SliceView.Settings</item>
     </style>
 
     <!-- Variant of the settings theme with no action bar. -->
@@ -71,9 +78,6 @@
         <item name="android:actionBarStyle">@style/Widget.ActionBar.SubSettings</item>
 
         <item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
-
-        <!-- Friction icon color for wifi preferences -->
-        <item name="frictionIconColor">?android:colorControlNormal</item>
     </style>
 
     <style name="Theme.SubSettings" parent="Theme.SubSettings.Base"/>
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 40ce93d..90895f2 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -26,7 +26,14 @@
         settings:allowDividerBelow="true"/>
 
     <com.android.settingslib.widget.ActionButtonsPreference
-        android:key="action_buttons" />
+        android:key="action_buttons"
+        settings:allowDividerBelow="true"/>
+
+    <com.android.settings.slices.SlicePreference
+        android:key="bt_device_slice"
+        settings:controller="com.android.settings.slices.SlicePreferenceController"
+        settings:allowDividerBelow="true"
+        settings:allowDividerAbove="true"/>
 
     <PreferenceCategory
         android:key="bluetooth_profiles"/>
diff --git a/res/xml/financial_app_sms_access.xml b/res/xml/financial_app_sms_access.xml
new file mode 100644
index 0000000..6f7ba50
--- /dev/null
+++ b/res/xml/financial_app_sms_access.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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="@string/financial_sms_root_screen_key"
+    android:title="@string/financial_apps_sms_access_title"
+    settings:controller="com.android.settings.applications.specialaccess.financialapps.FinancialAppsController" />
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index 57e673f..cb76693 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -130,4 +130,9 @@
             android:value="com.android.settings.Settings$ChangeWifiStateActivity" />
     </Preference>
 
+    <Preference
+        android:key="financial_apps_sms_access"
+        android:title="@string/financial_apps_sms_access_title"
+        android:fragment="com.android.settings.applications.specialaccess.financialapps.FinancialAppsSmsAccess"
+        settings:keywords="@string/keywords_financial_apps_sms_access" />
 </PreferenceScreen>
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index 6557aee..fdd7f2e 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -32,7 +32,6 @@
 import com.android.settings.display.ThemePreferenceController;
 import com.android.settings.display.TimeoutPreferenceController;
 import com.android.settings.display.VrDisplayPreferenceController;
-import com.android.settings.display.WallpaperPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settingslib.core.AbstractPreferenceController;
diff --git a/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsController.java b/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsController.java
new file mode 100644
index 0000000..492e4fd
--- /dev/null
+++ b/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsController.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2018 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.applications.specialaccess.financialapps;
+
+import static android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS;
+import static android.Manifest.permission.READ_SMS;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.Preference.OnPreferenceChangeListener;
+import androidx.preference.SwitchPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FinancialAppsController extends BasePreferenceController
+        implements ApplicationsState.Callbacks {
+    private final static String TAG = FinancialAppsController.class.getSimpleName();
+
+    @VisibleForTesting
+    PreferenceScreen mRoot;
+
+    public FinancialAppsController(Context context, String key) {
+        super(context, key);
+    }
+
+    @AvailabilityStatus
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mRoot = screen;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        updateList();
+    }
+
+    private void updateList() {
+        mRoot.removeAll();
+
+        final PackageManager packageManager = mContext.getPackageManager();
+        final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+
+        final List<PackageInfo> installedPackages =
+                packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
+        final int numPackages = installedPackages.size();
+        for (int i = 0; i < numPackages; i++) {
+            final PackageInfo installedPackage = installedPackages.get(i);
+
+            if (installedPackage.requestedPermissions == null) {
+                continue;
+            }
+            final int targetSdk = installedPackage.applicationInfo.targetSdkVersion;
+            final String pkgName = installedPackage.packageName;
+
+            if ((targetSdk >= Build.VERSION_CODES.Q
+                    && ArrayUtils.contains(installedPackage.requestedPermissions,
+                            SMS_FINANCIAL_TRANSACTIONS))
+                    || (targetSdk < Build.VERSION_CODES.Q
+                    && ArrayUtils.contains(installedPackage.requestedPermissions,
+                            READ_SMS))) {
+                final SwitchPreference pref = new SwitchPreference(mRoot.getContext());
+                pref.setTitle(installedPackage.applicationInfo.loadLabel(packageManager));
+                pref.setKey(pkgName);
+
+                pref.setChecked(
+                        appOpsManager.checkOp(
+                                targetSdk >= Build.VERSION_CODES.Q
+                                        ? AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS
+                                        : AppOpsManager.OP_READ_SMS,
+                                installedPackage.applicationInfo.uid,
+                                pkgName) == AppOpsManager.MODE_ALLOWED);
+
+                pref.setOnPreferenceChangeListener((preference, newValue) -> {
+                    final int uid;
+                    try {
+                        uid = packageManager.getPackageInfo(preference.getKey(), 0)
+                                .applicationInfo.uid;
+                    } catch (NameNotFoundException e) {
+                        Log.e(TAG, "onPreferenceChange: Failed to get uid for "
+                                + preference.getKey());
+                        return false;
+                    }
+
+                    appOpsManager.setMode(
+                            targetSdk >= Build.VERSION_CODES.Q
+                                    ? AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS
+                                    : AppOpsManager.OP_READ_SMS,
+                            uid,
+                            pkgName,
+                            (Boolean) newValue ? AppOpsManager.MODE_ALLOWED
+                                    : AppOpsManager.MODE_IGNORED);
+                    return true;
+                });
+                mRoot.addPreference(pref);
+            }
+        }
+    }
+
+    @Override
+    public void onRunningStateChanged(boolean running) {}
+
+    @Override
+    public void onPackageListChanged() {
+        updateList();
+    }
+
+    @Override
+    public void onRebuildComplete(ArrayList<AppEntry> apps) {}
+
+    @Override
+    public void onPackageIconChanged() {}
+
+    @Override
+    public void onPackageSizeChanged(String packageName) {}
+
+    @Override
+    public void onAllSizesComputed() {}
+
+    @Override
+    public void onLauncherInfoChanged() {}
+
+    @Override
+    public void onLoadEntriesCompleted() {}
+}
diff --git a/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java b/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java
new file mode 100644
index 0000000..92f4e28
--- /dev/null
+++ b/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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.applications.specialaccess.financialapps;
+
+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 FinancialAppsSmsAccess extends DashboardFragment {
+    private final static String TAG = FinancialAppsSmsAccess.class.getSimpleName();
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.financial_app_sms_access;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+      return SettingsEnums.SETTINGS_FINANCIAL_APPS_SMS_ACCESS;
+    }
+
+    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.financial_app_sms_access;
+                    result.add(sir);
+                    return result;
+                }
+            };
+}
diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java
index 0aa8936..2597b29 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollBase.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java
@@ -67,8 +67,11 @@
      */
     public static final int RESULT_TIMEOUT = RESULT_FIRST_USER + 2;
 
-    public static final int CONFIRM_REQUEST = 1;
-    public static final int ENROLLING = 2;
+    public static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
+    public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2;
+    public static final int LEARN_MORE_REQUEST = 3;
+    public static final int CONFIRM_REQUEST = 4;
+    public static final int ENROLLING = 5;
 
     protected boolean mLaunchedConfirmLock;
     protected byte[] mToken;
@@ -105,10 +108,6 @@
         initViews();
     }
 
-    protected boolean shouldLaunchConfirmLock() {
-        return mToken == null && !mLaunchedConfirmLock;
-    }
-
     protected void initViews() {
         getWindow().setStatusBarColor(Color.TRANSPARENT);
         Button nextButton = getNextButton();
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index 2424eb1..8a2a8ec 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -37,10 +37,6 @@
 public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
         implements LinkSpan.OnClickListener {
 
-    public static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
-    public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2;
-    public static final int LEARN_MORE_REQUEST = 3;
-
     private UserManager mUserManager;
     private boolean mHasPassword;
     private boolean mBiometricUnlockDisabledByAdmin;
@@ -110,6 +106,11 @@
     protected abstract Intent getEnrollingIntent();
 
     /**
+     * @return the title to be shown on the ConfirmLock screen.
+     */
+    protected abstract int getConfirmLockTitleResId();
+
+    /**
      * @param span
      */
     public abstract void onClick(LinkSpan span);
@@ -133,6 +134,13 @@
 
         mUserManager = UserManager.get(this);
         updatePasswordQuality();
+
+        if (!mHasPassword) {
+            // No password registered, launch into enrollment wizard.
+            launchChooseLock();
+        } else {
+            launchConfirmLock(getConfirmLockTitleResId(), getChallenge());
+        }
     }
 
     @Override
@@ -157,13 +165,8 @@
 
     @Override
     protected void onNextButtonClick() {
-        if (!mHasPassword) {
-            // No biometrics registered, launch into enrollment wizard.
-            launchChooseLock();
-        } else {
-            // Lock thingy is already set up, launch directly into find sensor step from wizard.
-            launchFindSensor(null);
-        }
+        // Lock thingy is already set up, launch directly to the next page
+        launchNextEnrollingActivity(mToken);
     }
 
     private void launchChooseLock() {
@@ -181,7 +184,7 @@
         startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
     }
 
-    private void launchFindSensor(byte[] token) {
+    private void launchNextEnrollingActivity(byte[] token) {
         Intent intent = getEnrollingIntent();
         if (token != null) {
             intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
@@ -199,9 +202,9 @@
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         final boolean isResultFinished = resultCode == RESULT_FINISHED;
+        final int result = isResultFinished ? RESULT_OK : RESULT_SKIP;
         if (requestCode == BIOMETRIC_FIND_SENSOR_REQUEST) {
             if (isResultFinished || resultCode == RESULT_SKIP) {
-                final int result = isResultFinished ? RESULT_OK : RESULT_SKIP;
                 setResult(result, data);
                 finish();
                 return;
@@ -209,10 +212,21 @@
         } else if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST) {
             if (isResultFinished) {
                 updatePasswordQuality();
-                byte[] token = data.getByteArrayExtra(
+                mToken = data.getByteArrayExtra(
                         ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
-                launchFindSensor(token);
+                overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
                 return;
+            } else {
+                setResult(result, data);
+                finish();
+            }
+        } else if (requestCode == CONFIRM_REQUEST) {
+            if (resultCode == RESULT_OK && data != null) {
+                mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
+                overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
+            } else {
+                setResult(result, data);
+                finish();
             }
         } else if (requestCode == LEARN_MORE_REQUEST) {
             overridePendingTransition(R.anim.suw_slide_back_in, R.anim.suw_slide_back_out);
diff --git a/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java b/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
index f101038..033fb4b 100644
--- a/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
@@ -48,13 +48,6 @@
      */
     protected abstract boolean shouldStartAutomatically();
 
-    /**
-     * @return true if enrollment should finish when onStop is called.
-     */
-    protected boolean shouldFinishOnStop() {
-        return true;
-    }
-
     @Override
     protected void onStart() {
         super.onStart();
@@ -70,7 +63,7 @@
             mSidecar.setListener(null);
         }
 
-        if (shouldFinishOnStop() && !isChangingConfigurations()) {
+        if (!isChangingConfigurations()) {
             if (mSidecar != null) {
                 mSidecar.cancelEnrollment();
                 getSupportFragmentManager()
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
index 727d74a..bb46b18 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
@@ -44,7 +44,6 @@
 
     private TextView mErrorText;
     private Interpolator mLinearOutSlowInInterpolator;
-    private boolean mShouldFinishOnStop = true;
     private FaceEnrollPreviewFragment mPreviewFragment;
 
     private FaceFeatureProvider.Listener mListener = new FaceFeatureProvider.Listener() {
@@ -92,13 +91,7 @@
         Button skipButton = findViewById(R.id.skip_button);
         skipButton.setOnClickListener(this);
 
-        if (shouldLaunchConfirmLock()) {
-            launchConfirmLock(R.string.security_settings_face_preference_title,
-                    Utils.getFaceManagerOrNull(this).generateChallenge());
-            mShouldFinishOnStop = false;
-        } else {
-            startEnrollment();
-        }
+        startEnrollment();
     }
 
     @Override
@@ -130,11 +123,6 @@
     }
 
     @Override
-    protected boolean shouldFinishOnStop() {
-        return mShouldFinishOnStop;
-    }
-
-    @Override
     public int getMetricsCategory() {
         return MetricsProto.MetricsEvent.FACE_ENROLL_ENROLLING;
     }
@@ -178,23 +166,6 @@
         }
     }
 
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == CONFIRM_REQUEST) {
-            if (resultCode == RESULT_OK && data != null) {
-                mShouldFinishOnStop = true;
-                mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
-                overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
-                getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
-                startEnrollment();
-            } else {
-                finish();
-            }
-        } else {
-            super.onActivityResult(requestCode, resultCode, data);
-        }
-    }
-
     private void showErrorDialog(CharSequence msg, int msgId) {
         BiometricErrorDialog dialog = FaceErrorDialog.newInstance(msg, msgId);
         dialog.show(getSupportFragmentManager(), FaceErrorDialog.class.getName());
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index c4a9c4f..b720ff4 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -102,6 +102,7 @@
 
     @Override
     protected long getChallenge() {
+        mFaceManager = Utils.getFaceManagerOrNull(this);
         if (mFaceManager == null) {
             return 0;
         }
@@ -119,6 +120,11 @@
     }
 
     @Override
+    protected int getConfirmLockTitleResId() {
+        return R.string.security_settings_face_preference_title;
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsProto.MetricsEvent.FACE_ENROLL_INTRO;
     }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index 4b4f65a..0772c66 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -51,12 +51,9 @@
 
         setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
 
-        if (shouldLaunchConfirmLock()) {
-            launchConfirmLock(R.string.security_settings_fingerprint_preference_title,
-                    Utils.getFingerprintManagerOrNull(this).preEnroll());
-        } else if (mToken != null) {
-            startLookingForFingerprint(); // already confirmed, so start looking for fingerprint
-        }
+
+        startLookingForFingerprint(); // already confirmed, so start looking for fingerprint
+
         View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
         if (animationView instanceof FingerprintFindSensorAnimation) {
             mAnimation = (FingerprintFindSensorAnimation) animationView;
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
index 8821ce5..61c67a5 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
@@ -106,6 +106,7 @@
 
     @Override
     protected long getChallenge() {
+        mFingerprintManager = Utils.getFingerprintManagerOrNull(this);
         if (mFingerprintManager == null) {
             return 0;
         }
@@ -123,6 +124,11 @@
     }
 
     @Override
+    protected int getConfirmLockTitleResId() {
+        return R.string.security_settings_fingerprint_preference_title;
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsProto.MetricsEvent.FINGERPRINT_ENROLL_INTRO;
     }
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index df32111..6ec419b 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -21,12 +21,16 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.os.Bundle;
+import android.util.FeatureFlagUtils;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
+import com.android.settings.core.FeatureFlags;
 import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.slices.SlicePreferenceController;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -98,6 +102,13 @@
         mManager = getLocalBluetoothManager(context);
         mCachedDevice = getCachedDevice(mDeviceAddress);
         super.onAttach(context);
+
+        if (FeatureFlagUtils.isEnabled(context, FeatureFlags.SLICE_INJECTION)) {
+            final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(context)
+                    .getBluetoothFeatureProvider(context);
+            use(SlicePreferenceController.class).setSliceUri(
+                    featureProvider.getBluetoothDeviceSettingsUri(mDeviceAddress));
+        }
     }
 
     @Override
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
new file mode 100644
index 0000000..2bca038
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.bluetooth;
+
+import android.net.Uri;
+
+/**
+ * Provider for bluetooth related feature
+ */
+public interface BluetoothFeatureProvider {
+
+    /**
+     * Get the {@link Uri} that represents extra settings for a specific bluetooth device
+     * @param macAddress Bluetooth mac address
+     * @return {@link Uri} for extra settings
+     */
+    Uri getBluetoothDeviceSettingsUri(String macAddress);
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
new file mode 100644
index 0000000..dcdc2fd7
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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.bluetooth;
+
+import android.content.Context;
+import android.net.Uri;
+
+import com.android.settings.R;
+
+/**
+ * Impl of {@link BluetoothFeatureProvider}
+ */
+public class BluetoothFeatureProviderImpl implements BluetoothFeatureProvider {
+
+    private Context mContext;
+
+    public BluetoothFeatureProviderImpl(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public Uri getBluetoothDeviceSettingsUri(String macAddress) {
+        final String uriString = mContext.getString(R.string.config_bluetooth_device_settings_uri,
+                macAddress);
+        return Uri.parse(uriString);
+    }
+}
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 56e9ee5..1916110 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -295,7 +295,13 @@
                 if (!controller.isAvailable()) {
                     continue;
                 }
+
                 final String key = controller.getPreferenceKey();
+                if (TextUtils.isEmpty(key)) {
+                    Log.d(TAG, String.format("Preference key is %s in Controller %s",
+                            key, controller.getClass().getSimpleName()));
+                    continue;
+                }
 
                 final Preference preference = screen.findPreference(key);
                 if (preference == null) {
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index 0320bf6..cf7df8d 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -24,6 +24,7 @@
 import com.android.settings.accounts.AccountFeatureProvider;
 import com.android.settings.applications.ApplicationFeatureProvider;
 import com.android.settings.biometrics.face.FaceFeatureProvider;
+import com.android.settings.bluetooth.BluetoothFeatureProvider;
 import com.android.settings.dashboard.DashboardFeatureProvider;
 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
 import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
@@ -114,6 +115,8 @@
 
     public abstract FaceFeatureProvider getFaceFeatureProvider();
 
+    public abstract BluetoothFeatureProvider getBluetoothFeatureProvider(Context context);
+
     public static final class FactoryNotFoundException extends RuntimeException {
         public FactoryNotFoundException(Throwable throwable) {
             super("Unable to create factory. Did you misconfigure Proguard?", throwable);
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index 0232964..e10aa41 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -30,6 +30,8 @@
 import com.android.settings.applications.ApplicationFeatureProviderImpl;
 import com.android.settings.biometrics.face.FaceFeatureProvider;
 import com.android.settings.biometrics.face.FaceFeatureProviderImpl;
+import com.android.settings.bluetooth.BluetoothFeatureProvider;
+import com.android.settings.bluetooth.BluetoothFeatureProviderImpl;
 import com.android.settings.connecteddevice.dock.DockUpdaterFeatureProviderImpl;
 import com.android.settings.core.instrumentation.SettingsMetricsFeatureProvider;
 import com.android.settings.dashboard.DashboardFeatureProvider;
@@ -81,6 +83,7 @@
     private PanelFeatureProvider mPanelFeatureProvider;
     private ContextualCardFeatureProvider mContextualCardFeatureProvider;
     private FaceFeatureProvider mFaceFeatureProvider;
+    private BluetoothFeatureProvider mBluetoothFeatureProvider;
 
     @Override
     public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -243,4 +246,13 @@
         }
         return mFaceFeatureProvider;
     }
+
+    @Override
+    public BluetoothFeatureProvider getBluetoothFeatureProvider(Context context) {
+        if (mBluetoothFeatureProvider == null) {
+            mBluetoothFeatureProvider = new BluetoothFeatureProviderImpl(
+                    context.getApplicationContext());
+        }
+        return mBluetoothFeatureProvider;
+    }
 }
diff --git a/src/com/android/settings/password/SetupChooseLockPassword.java b/src/com/android/settings/password/SetupChooseLockPassword.java
index b96c57df..8454cc5 100644
--- a/src/com/android/settings/password/SetupChooseLockPassword.java
+++ b/src/com/android/settings/password/SetupChooseLockPassword.java
@@ -135,8 +135,9 @@
         @Override
         protected void updateUi() {
             super.updateUi();
-            mSkipButton.setVisibility(mForFingerprint ? View.GONE : View.VISIBLE);
 
+            // Show the skip button during SUW but not during Settings > Biometric Enrollment
+            mSkipButton.setVisibility(View.VISIBLE);
             if (mOptionsButton != null) {
                 mOptionsButton.setVisibility(
                         mUiStage == Stage.Introduction ? View.VISIBLE : View.GONE);
diff --git a/src/com/android/settings/password/SetupChooseLockPattern.java b/src/com/android/settings/password/SetupChooseLockPattern.java
index 696380c..b24936b 100644
--- a/src/com/android/settings/password/SetupChooseLockPattern.java
+++ b/src/com/android/settings/password/SetupChooseLockPattern.java
@@ -70,17 +70,15 @@
                         ChooseLockTypeDialogFragment.newInstance(mUserId)
                                 .show(getChildFragmentManager(), null));
             }
-            // enable skip button only during setup wizard and not with fingerprint flow.
-            if (!mForFingerprint) {
-                Button skipButton = view.findViewById(R.id.skip_button);
-                skipButton.setVisibility(View.VISIBLE);
-                skipButton.setOnClickListener(v -> {
-                    SetupSkipDialog dialog = SetupSkipDialog.newInstance(
-                            getActivity().getIntent()
-                                    .getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false));
-                    dialog.show(getFragmentManager());
+            // Show the skip button during SUW but not during Settings > Biometric Enrollment
+            Button skipButton = view.findViewById(R.id.skip_button);
+            skipButton.setVisibility(View.VISIBLE);
+            skipButton.setOnClickListener(v -> {
+                SetupSkipDialog dialog = SetupSkipDialog.newInstance(
+                        getActivity().getIntent()
+                                .getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false));
+                dialog.show(getFragmentManager());
                 });
-            }
             return view;
         }
 
diff --git a/src/com/android/settings/slices/SlicePreference.java b/src/com/android/settings/slices/SlicePreference.java
new file mode 100644
index 0000000..98719f7
--- /dev/null
+++ b/src/com/android/settings/slices/SlicePreference.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.slices;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.slice.Slice;
+import androidx.slice.widget.SliceView;
+
+import com.android.settings.R;
+import com.android.settingslib.widget.LayoutPreference;
+
+/**
+ * Preference for {@link SliceView}
+ */
+public class SlicePreference extends LayoutPreference {
+    private SliceView mSliceView;
+
+    public SlicePreference(Context context, AttributeSet attrs) {
+        super(context, attrs, R.attr.slicePreferenceStyle);
+        mSliceView = findViewById(R.id.slice_view);
+    }
+
+    public SlicePreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, R.attr.slicePreferenceStyle);
+        mSliceView = findViewById(R.id.slice_view);
+    }
+
+    public void onSliceUpdated(Slice slice) {
+        mSliceView.onChanged(slice);
+        notifyChanged();
+    }
+}
diff --git a/src/com/android/settings/slices/SlicePreferenceController.java b/src/com/android/settings/slices/SlicePreferenceController.java
new file mode 100644
index 0000000..8c751c8
--- /dev/null
+++ b/src/com/android/settings/slices/SlicePreferenceController.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 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.slices;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.Observer;
+import androidx.preference.PreferenceScreen;
+import androidx.slice.Slice;
+import androidx.slice.widget.SliceLiveData;
+import androidx.slice.widget.SliceView;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+/**
+ * Default {@link BasePreferenceController} for {@link SliceView}. It will take {@link Uri} for
+ * Slice and display what's inside this {@link Uri}
+ */
+public class SlicePreferenceController extends BasePreferenceController implements
+        LifecycleObserver, OnStart, OnStop, Observer<Slice> {
+    @VisibleForTesting
+    LiveData<Slice> mLiveData;
+    private SlicePreference mSlicePreference;
+    private Uri mUri;
+
+    public SlicePreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        mSlicePreference = (SlicePreference) screen.findPreference(
+                getPreferenceKey());
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return mUri != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    public void setSliceUri(Uri uri) {
+        mUri = uri;
+        mLiveData = SliceLiveData.fromUri(mContext, mUri);
+
+        //TODO(b/120803703): figure out why we need to remove observer first
+        mLiveData.removeObserver(this);
+    }
+
+    @Override
+    public void onStart() {
+        if (mLiveData != null) {
+            mLiveData.observeForever(this);
+        }
+    }
+
+    @Override
+    public void onStop() {
+        if (mLiveData != null) {
+            mLiveData.removeObserver(this);
+        }
+    }
+
+    @Override
+    public void onChanged(Slice slice) {
+        mSlicePreference.onSliceUpdated(slice);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsControllerTest.java
new file mode 100644
index 0000000..39a05cb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsControllerTest.java
@@ -0,0 +1,125 @@
+package com.android.settings.applications.specialaccess.financialapps;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import static android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS;
+import static android.Manifest.permission.READ_SMS;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadow.api.Shadow;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@RunWith(RobolectricTestRunner.class)
+public class FinancialAppsControllerTest {
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private AppOpsManager mAppOpsManager;
+    @Mock
+    private PreferenceScreen mRoot;
+    @Mock
+    private Preference mPreference;
+
+    private Context mContext;
+    private PackageInfo mPackageInfoNoPermissionRequested;
+    private PackageInfo mPackageInfoPermissionRequestedQPlus;
+    private PackageInfo mPackageInfoPermissionRequestedPreQ;
+    private FinancialAppsController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager);
+
+        initializePackageInfos();
+
+        mController = new FinancialAppsController(mContext, "key");
+        mController.displayPreference(mRoot);
+    }
+
+    private void initializePackageInfos() {
+      mPackageInfoNoPermissionRequested = new PackageInfo();
+      mPackageInfoNoPermissionRequested.applicationInfo = new ApplicationInfo();
+
+      mPackageInfoPermissionRequestedQPlus = new PackageInfo();
+      mPackageInfoPermissionRequestedQPlus.applicationInfo = new ApplicationInfo();
+      // TODO(b/121161546): update after robolectric test support Q
+      //mPackageInfoPermissionRequestedQPlus.applicationInfo.targetSdkVersion =
+      //        Build.VERSION_CODES.Q;
+      mPackageInfoPermissionRequestedQPlus.applicationInfo.uid = 2001;
+      mPackageInfoPermissionRequestedQPlus.applicationInfo.nonLocalizedLabel = "QPLUS Package";
+      mPackageInfoPermissionRequestedQPlus.packageName = "QPLUS";
+      mPackageInfoPermissionRequestedQPlus.requestedPermissions =
+              new String[] {SMS_FINANCIAL_TRANSACTIONS};
+
+      mPackageInfoPermissionRequestedPreQ = new PackageInfo();
+      mPackageInfoPermissionRequestedPreQ.applicationInfo = new ApplicationInfo();
+      mPackageInfoPermissionRequestedPreQ.applicationInfo.targetSdkVersion = Build.VERSION_CODES.M;
+      mPackageInfoPermissionRequestedPreQ.applicationInfo.uid = 2002;
+      mPackageInfoPermissionRequestedPreQ.applicationInfo.nonLocalizedLabel = "PREQ Package";
+      mPackageInfoPermissionRequestedPreQ.packageName = "PREQ";
+      mPackageInfoPermissionRequestedPreQ.requestedPermissions = new String[] {READ_SMS};
+    }
+
+    @Test
+    public void isAvailable_true() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void noPreferenceAddedWhenNoPackageRequestPermission() {
+        when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
+            .thenReturn(new ArrayList<PackageInfo>(
+                    Arrays.asList(mPackageInfoNoPermissionRequested)));
+        mController.updateState(null);
+        assertThat(mController.mRoot.getPreferenceCount()).isEqualTo(0);
+    }
+
+    //TODO(b/121161546): Add these tests after robolectric test support Q
+    /*
+    @Test
+    public void preferenceAddedWhenPreQPackageRequestPermission() {
+        when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
+            .thenReturn(new ArrayList<PackageInfo>(
+                    Arrays.asList(mPackageInfoPermissionRequestedPreQ)));
+        mController.updateState(null);
+        assertThat(mController.mRoot.getPreferenceCount()).isEqualTo(1);
+        SwitchPreference pref = (SwitchPreference) mController.mRoot.getPreference(0);
+        assertThat(pref).isNotNull();
+    }
+
+    @Test
+    public void preferenceAddedWhenQPlusPackageRequestPermission() {
+        when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
+            .thenReturn(new ArrayList<PackageInfo>(
+                    Arrays.asList(mPackageInfoPermissionRequestedQPlus)));
+        mController.updateState(null);
+        assertThat(mController.mRoot.getPreferenceCount()).isEqualTo(1);
+        SwitchPreference pref = (SwitchPreference) mController.mRoot.getPreference(0);
+        assertThat(pref).isNotNull();
+        }*/
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java
new file mode 100644
index 0000000..887f58c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.Uri;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+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 BluetoothFeatureProvider mBluetoothFeatureProvider;
+
+    @Before
+    public void setUp() {
+        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);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
index c11d7eb..649a1ba 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
@@ -164,23 +164,6 @@
         assertThat(findFragment(mActivity).mChosenPattern).isNull();
     }
 
-    @Test
-    public void skipButton_shouldNotBeVisible_duringFingerprintFlow() {
-        final Intent intent =
-                SetupChooseLockPattern.modifyIntentForSetup(
-                        application,
-                        new IntentBuilder(application)
-                                .setUserId(UserHandle.myUserId())
-                                .setForFingerprint(true)
-                                .build());
-
-        mActivity = ActivityController.of(new SetupChooseLockPattern(), intent).setup().get();
-        Button skipButton = mActivity.findViewById(R.id.skip_button);
-
-        assertThat(skipButton).isNotNull();
-        assertThat(skipButton.getVisibility()).isEqualTo(View.GONE);
-    }
-
     private ChooseLockPatternFragment findFragment(FragmentActivity activity) {
         return (ChooseLockPatternFragment)
                 activity.getSupportFragmentManager().findFragmentById(R.id.main_content);
diff --git a/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
new file mode 100644
index 0000000..364fb60
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2018 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.slices;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.lifecycle.LiveData;
+import androidx.slice.Slice;
+
+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 SlicePreferenceControllerTest {
+    private static final String KEY = "slice_preference_key";
+
+    @Mock
+    private LiveData<Slice> mLiveData;
+    private Context mContext;
+    private SlicePreferenceController mController;
+    private Uri mUri;
+
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(RuntimeEnvironment.application);
+        mController = new SlicePreferenceController(mContext, KEY);
+        mController.mLiveData = mLiveData;
+        mUri = Uri.EMPTY;
+    }
+
+    @Test
+    public void isAvailable_uriNull_returnFalse() {
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_uriNotNull_returnTrue() {
+        mController.setSliceUri(mUri);
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void onStart_registerObserver() {
+        mController.onStart();
+        verify(mLiveData).observeForever(mController);
+    }
+
+    @Test
+    public void onStop_unregisterObserver() {
+        mController.onStop();
+        verify(mLiveData).removeObserver(mController);
+    }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index 1d8e2cb..bf86898 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -24,6 +24,7 @@
 import com.android.settings.accounts.AccountFeatureProvider;
 import com.android.settings.applications.ApplicationFeatureProvider;
 import com.android.settings.biometrics.face.FaceFeatureProvider;
+import com.android.settings.bluetooth.BluetoothFeatureProvider;
 import com.android.settings.dashboard.DashboardFeatureProvider;
 import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
 import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
@@ -66,6 +67,7 @@
     public final AccountFeatureProvider mAccountFeatureProvider;
     public final ContextualCardFeatureProvider mContextualCardFeatureProvider;
     public final FaceFeatureProvider mFaceFeatureProvider;
+    public final BluetoothFeatureProvider mBluetoothFeatureProvider;
 
     public PanelFeatureProvider panelFeatureProvider;
     public SlicesFeatureProvider slicesFeatureProvider;
@@ -111,6 +113,7 @@
         mContextualCardFeatureProvider = mock(ContextualCardFeatureProvider.class);
         panelFeatureProvider = mock(PanelFeatureProvider.class);
         mFaceFeatureProvider = mock(FaceFeatureProvider.class);
+        mBluetoothFeatureProvider = mock(BluetoothFeatureProvider.class);
     }
 
     @Override
@@ -206,4 +209,9 @@
     public FaceFeatureProvider getFaceFeatureProvider() {
         return mFaceFeatureProvider;
     }
+
+    @Override
+    public BluetoothFeatureProvider getBluetoothFeatureProvider(Context context) {
+        return mBluetoothFeatureProvider;
+    }
 }