Snap for 11401641 from 2eba5be9b4ec334bdf000cf78ab7d58a1611e1b5 to 24Q2-release

Change-Id: I57bba30c0bbb7d7a02375e7b1d531e8259fdade3
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index 2f04b62..4fc0e16 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -46,6 +46,7 @@
 import android.service.autofill.AutofillServiceInfo;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 import android.view.View;
 import android.widget.CompoundButton;
 
@@ -77,6 +78,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.Executor;
 
@@ -114,7 +116,7 @@
     private @Nullable String mFlagOverrideForTest = null;
     private @Nullable PreferenceScreen mPreferenceScreen = null;
 
-    private boolean mVisibility = false;
+    private Optional<Boolean> mSimulateHiddenForTests = Optional.empty();
     private boolean mIsWorkProfile = false;
     private boolean mSimulateConnectedForTests = false;
 
@@ -159,7 +161,9 @@
             return UNSUPPORTED_ON_DEVICE;
         }
 
-        if (!mVisibility) {
+        // If there is no top provider or any providers in the list then
+        // we should hide this pref.
+        if (isHiddenDueToNoProviderSet()) {
             return CONDITIONALLY_UNAVAILABLE;
         }
 
@@ -378,20 +382,29 @@
     }
 
     @VisibleForTesting
-    public void setVisibility(boolean newVisibility) {
-        if (newVisibility == mVisibility) {
-            return;
-        }
-
-        mVisibility = newVisibility;
+    public void forceDelegateRefresh() {
         if (mDelegate != null) {
             mDelegate.forceDelegateRefresh();
         }
     }
 
     @VisibleForTesting
-    public boolean getVisibility() {
-        return mVisibility;
+    public void setSimulateHiddenForTests(Optional<Boolean> simulateHiddenForTests) {
+        mSimulateHiddenForTests = simulateHiddenForTests;
+    }
+
+    @VisibleForTesting
+    public boolean isHiddenDueToNoProviderSet() {
+        return isHiddenDueToNoProviderSet(getProviders());
+    }
+
+    private boolean isHiddenDueToNoProviderSet(
+            Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
+        if (mSimulateHiddenForTests.isPresent()) {
+            return mSimulateHiddenForTests.get();
+        }
+
+        return (providerPair.first.size() == 0 || providerPair.second == null);
     }
 
     @VisibleForTesting
@@ -459,10 +472,11 @@
         return preference;
     }
 
-    /** Aggregates the list of services and builds a list of UI prefs to show. */
-    @VisibleForTesting
-    public Map<String, CombiPreference> buildPreferenceList(
-            Context context, PreferenceGroup group) {
+    /**
+     * Returns a pair that contains a list of the providers in the first position and the top
+     * provider in the second position.
+     */
+    private Pair<List<CombinedProviderInfo>, CombinedProviderInfo> getProviders() {
         // Get the selected autofill provider. If it is the placeholder then replace it with an
         // empty string.
         String selectedAutofillProvider =
@@ -475,15 +489,25 @@
         // Get the list of combined providers.
         List<CombinedProviderInfo> providers =
                 CombinedProviderInfo.buildMergedList(
-                        AutofillServiceInfo.getAvailableServices(context, getUser()),
+                        AutofillServiceInfo.getAvailableServices(mContext, getUser()),
                         mServices,
                         selectedAutofillProvider);
+        return new Pair<>(providers, CombinedProviderInfo.getTopProvider(providers));
+    }
 
-        // Get the provider that is displayed at the top. If there is none then hide
-        // everything.
-        CombinedProviderInfo topProvider = CombinedProviderInfo.getTopProvider(providers);
-        if (topProvider == null) {
-            setVisibility(false);
+    /** Aggregates the list of services and builds a list of UI prefs to show. */
+    @VisibleForTesting
+    public @NonNull Map<String, CombiPreference> buildPreferenceList(
+            @NonNull Context context, @NonNull PreferenceGroup group) {
+        // Get the providers and extract the values.
+        Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair = getProviders();
+        CombinedProviderInfo topProvider = providerPair.second;
+        List<CombinedProviderInfo> providers = providerPair.first;
+
+        // If the provider is set to "none" or there are no providers then we should not
+        // return any providers.
+        if (isHiddenDueToNoProviderSet(providerPair)) {
+            forceDelegateRefresh();
             return new HashMap<>();
         }
 
@@ -520,7 +544,7 @@
         }
 
         // Set the visibility if we have services.
-        setVisibility(!output.isEmpty());
+        forceDelegateRefresh();
 
         return output;
     }
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
index 18ad210..3d85ca2 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
@@ -38,7 +38,8 @@
 public class BluetoothDetailsHearingDeviceControlsController extends BluetoothDetailsController
         implements Preference.OnPreferenceClickListener {
 
-    private static final String KEY_DEVICE_CONTROLS_GENERAL_GROUP = "device_controls_general";
+    @VisibleForTesting
+    static final String KEY_DEVICE_CONTROLS_GENERAL_GROUP = "device_controls_general";
     @VisibleForTesting
     static final String KEY_HEARING_DEVICE_CONTROLS = "hearing_device_controls";
 
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 5e41a20..9c68c9c 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -22,6 +22,7 @@
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.TypedArray;
 import android.hardware.input.InputManager;
 import android.net.Uri;
@@ -53,6 +54,7 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import java.util.ArrayList;
@@ -324,8 +326,11 @@
                     lifecycle));
             controllers.add(new BluetoothDetailsPairOtherController(context, this, mCachedDevice,
                     lifecycle));
-            controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this,
-                    mCachedDevice, lifecycle));
+            // Don't need to show hearing device again when launched from the same page.
+            if (!isLaunchFromHearingDevicePage()) {
+                controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this,
+                        mCachedDevice, lifecycle));
+            }
             controllers.add(new BluetoothDetailsDataSyncController(context, this,
                     mCachedDevice, lifecycle));
             controllers.add(
@@ -348,6 +353,16 @@
         return width;
     }
 
+    private boolean isLaunchFromHearingDevicePage() {
+        final Intent intent = getIntent();
+        if (intent == null) {
+            return false;
+        }
+
+        return intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
+                SettingsEnums.PAGE_UNKNOWN) == SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS;
+    }
+
     @VisibleForTesting
     void setTitleForInputDevice() {
         if (StylusDevicesController.isDeviceStylus(mInputDevice, mCachedDevice)) {
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java
index cc333a5..62be5df 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 
+import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 
 import java.util.List;
@@ -35,5 +36,9 @@
     boolean isBatteryInfoEnabled(Context context);
 
     /** A way to add more battery tip detectors. */
-    void addBatteryTipDetector(Context context, List<BatteryTip> tips, BatteryInfo batteryInfo);
+    void addBatteryTipDetector(
+            Context context,
+            List<BatteryTip> batteryTips,
+            BatteryInfo batteryInfo,
+            BatteryTipPolicy batteryTipPolicy);
 }
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java
index f974b9d..f398373 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 
+import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
+import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 
 import java.util.List;
@@ -42,5 +44,10 @@
 
     @Override
     public void addBatteryTipDetector(
-            Context context, List<BatteryTip> tips, BatteryInfo batteryInfo) {}
+            Context context,
+            List<BatteryTip> batteryTips,
+            BatteryInfo batteryInfo,
+            BatteryTipPolicy batteryTipPolicy) {
+        batteryTips.add(new LowBatteryDetector(context, batteryTipPolicy, batteryInfo).detect());
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 5352105..d68bf39 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.os.BatteryUsageStats;
-import android.os.PowerManager;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -27,7 +26,6 @@
 import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.IncompatibleChargerDetector;
-import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.utils.AsyncLoaderCompat;
@@ -56,19 +54,18 @@
     @Override
     public List<BatteryTip> loadInBackground() {
         final List<BatteryTip> tips = new ArrayList<>();
-        final BatteryTipPolicy policy = new BatteryTipPolicy(getContext());
+        final BatteryTipPolicy batteryTipPolicy = new BatteryTipPolicy(getContext());
         final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(TAG);
         final Context context = getContext().getApplicationContext();
-        final boolean isPowerSaveMode =
-                context.getSystemService(PowerManager.class).isPowerSaveMode();
 
-        tips.add(new LowBatteryDetector(context, policy, batteryInfo, isPowerSaveMode).detect());
-        tips.add(new HighUsageDetector(context, policy, mBatteryUsageStats, batteryInfo).detect());
+        tips.add(
+                new HighUsageDetector(context, batteryTipPolicy, mBatteryUsageStats, batteryInfo)
+                        .detect());
         tips.add(new BatteryDefenderDetector(batteryInfo, context).detect());
         tips.add(new IncompatibleChargerDetector(context).detect());
         FeatureFactory.getFeatureFactory()
                 .getBatterySettingsFeatureProvider()
-                .addBatteryTipDetector(context, tips, batteryInfo);
+                .addBatteryTipDetector(context, tips, batteryInfo, batteryTipPolicy);
         Collections.sort(tips);
         return tips;
     }
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
index 1ce5a8e..b1a1562 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
@@ -17,6 +17,7 @@
 package com.android.settings.fuelgauge.batterytip.detectors;
 
 import android.content.Context;
+import android.os.PowerManager;
 
 import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
@@ -26,37 +27,33 @@
 /** Detect whether the battery is too low */
 public class LowBatteryDetector implements BatteryTipDetector {
     private final BatteryInfo mBatteryInfo;
-    private final BatteryTipPolicy mPolicy;
+    private final BatteryTipPolicy mBatteryTipPolicy;
     private final boolean mIsPowerSaveMode;
     private final int mWarningLevel;
 
     public LowBatteryDetector(
-            Context context,
-            BatteryTipPolicy policy,
-            BatteryInfo batteryInfo,
-            boolean isPowerSaveMode) {
-        mPolicy = policy;
+            Context context, BatteryTipPolicy batteryTipPolicy, BatteryInfo batteryInfo) {
+        mBatteryTipPolicy = batteryTipPolicy;
         mBatteryInfo = batteryInfo;
         mWarningLevel =
                 context.getResources()
                         .getInteger(com.android.internal.R.integer.config_lowBatteryWarningLevel);
-        mIsPowerSaveMode = isPowerSaveMode;
+        mIsPowerSaveMode = context.getSystemService(PowerManager.class).isPowerSaveMode();
     }
 
     @Override
     public BatteryTip detect() {
         final boolean lowBattery = mBatteryInfo.batteryLevel <= mWarningLevel;
-        final boolean lowBatteryEnabled = mPolicy.lowBatteryEnabled && !mIsPowerSaveMode;
+        final boolean lowBatteryEnabled = mBatteryTipPolicy.lowBatteryEnabled && !mIsPowerSaveMode;
         final boolean dischargingLowBatteryState =
-                mPolicy.testLowBatteryTip || (mBatteryInfo.discharging && lowBattery);
-
-        int state = BatteryTip.StateType.INVISIBLE;
+                mBatteryTipPolicy.testLowBatteryTip || (mBatteryInfo.discharging && lowBattery);
 
         // Show it as new if in test or in discharging low battery state,
         // dismiss it if battery saver is on or disabled by config.
-        if (lowBatteryEnabled && dischargingLowBatteryState) {
-            state = BatteryTip.StateType.NEW;
-        }
+        final int state =
+                lowBatteryEnabled && dischargingLowBatteryState
+                        ? BatteryTip.StateType.NEW
+                        : BatteryTip.StateType.INVISIBLE;
 
         return new LowBatteryTip(state, mIsPowerSaveMode);
     }
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
index 047bf13..319ba7a 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
@@ -16,12 +16,14 @@
 
 package com.android.settings.fuelgauge.batterytip.tips;
 
+import android.app.Activity;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Parcel;
 import android.util.Log;
 
+import androidx.core.app.ActivityCompat;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
@@ -30,6 +32,8 @@
 import com.android.settingslib.HelpUtils;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
+import kotlin.Unit;
+
 /** Tip to show current battery is overheated */
 public class BatteryDefenderTip extends BatteryTip {
 
@@ -83,28 +87,39 @@
         }
 
         cardPreference.setSelectable(false);
+        cardPreference.setIconResId(getIconId());
         cardPreference.setPrimaryButtonText(context.getString(R.string.learn_more));
-        cardPreference.setPrimaryButtonClickListener(
-                button ->
-                        button.startActivityForResult(
-                                HelpUtils.getHelpIntent(
-                                        context,
-                                        context.getString(R.string.help_url_battery_defender),
-                                        /* backupContext */ ""), /* requestCode */
-                                0));
-        cardPreference.setPrimaryButtonVisible(true);
+        cardPreference.setPrimaryButtonAction(
+                () -> {
+                    var helpIntent =
+                            HelpUtils.getHelpIntent(
+                                    context,
+                                    context.getString(R.string.help_url_battery_defender),
+                                    /* backupContext= */ "");
+                    ActivityCompat.startActivityForResult(
+                            (Activity) preference.getContext(),
+                            helpIntent,
+                            /* requestCode= */ 0,
+                            /* options= */ null);
+
+                    return Unit.INSTANCE;
+                });
+        cardPreference.setPrimaryButtonVisibility(true);
         cardPreference.setPrimaryButtonContentDescription(
                 context.getString(
                         R.string.battery_tip_limited_temporarily_sec_button_content_description));
 
         cardPreference.setSecondaryButtonText(
                 context.getString(R.string.battery_tip_charge_to_full_button));
-        cardPreference.setSecondaryButtonClickListener(
-                unused -> {
+        cardPreference.setSecondaryButtonAction(
+                () -> {
                     resumeCharging(context);
                     preference.setVisible(false);
+
+                    return Unit.INSTANCE;
                 });
-        cardPreference.setSecondaryButtonVisible(mIsPluggedIn);
+        cardPreference.setSecondaryButtonVisibility(mIsPluggedIn);
+        cardPreference.buildContent();
     }
 
     private void resumeCharging(Context context) {
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
index 882b755..c9ff864 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
@@ -16,11 +16,13 @@
 
 package com.android.settings.fuelgauge.batterytip.tips;
 
+import android.app.Activity;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.os.Parcel;
 import android.util.Log;
 
+import androidx.core.app.ActivityCompat;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
@@ -28,6 +30,8 @@
 import com.android.settingslib.HelpUtils;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
+import kotlin.Unit;
+
 /** Tip to show incompatible charger state */
 public final class IncompatibleChargerTip extends BatteryTip {
     private static final String TAG = "IncompatibleChargerTip";
@@ -77,18 +81,27 @@
         }
 
         cardPreference.setSelectable(false);
+        cardPreference.setIconResId(getIconId());
         cardPreference.setPrimaryButtonText(context.getString(R.string.learn_more));
-        cardPreference.setPrimaryButtonClickListener(
-                button ->
-                        button.startActivityForResult(
-                                HelpUtils.getHelpIntent(
-                                        context,
-                                        context.getString(R.string.help_url_incompatible_charging),
-                                        /* backupContext */ ""), /* requestCode */
-                                0));
-        cardPreference.setPrimaryButtonVisible(true);
+        cardPreference.setPrimaryButtonAction(
+                () -> {
+                    var helpIntent =
+                            HelpUtils.getHelpIntent(
+                                    context,
+                                    context.getString(R.string.help_url_incompatible_charging),
+                                    /* backupContext */ "");
+                    ActivityCompat.startActivityForResult(
+                            (Activity) context,
+                            helpIntent,
+                            /* requestCode= */ 0,
+                            /* options= */ null);
+
+                    return Unit.INSTANCE;
+                });
+        cardPreference.setPrimaryButtonVisibility(true);
         cardPreference.setPrimaryButtonContentDescription(
                 context.getString(R.string.battery_tip_incompatible_charging_content_description));
+        cardPreference.buildContent();
     }
 
     public static final Creator CREATOR =
diff --git a/src/com/android/settings/widget/CardPreference.java b/src/com/android/settings/widget/CardPreference.java
deleted file mode 100644
index 61114d9..0000000
--- a/src/com/android/settings/widget/CardPreference.java
+++ /dev/null
@@ -1,170 +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.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.Button;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settings.R;
-
-import com.google.android.material.card.MaterialCardView;
-
-import java.util.Optional;
-
-/** Preference that wrapped by {@link MaterialCardView} */
-public class CardPreference extends Preference {
-
-    private View.OnClickListener mPrimaryBtnClickListener = null;
-    private View.OnClickListener mSecondaryBtnClickListener = null;
-
-    private String mPrimaryButtonText = null;
-    private String mSecondaryButtonText = null;
-
-    private Optional<Button> mPrimaryButton = Optional.empty();
-    private Optional<Button> mSecondaryButton = Optional.empty();
-    private Optional<View> mButtonsGroup = Optional.empty();
-
-    private boolean mPrimaryButtonVisible = false;
-    private boolean mSecondaryButtonVisible = false;
-
-    public CardPreference(Context context) {
-        this(context, null /* attrs */);
-    }
-
-    public CardPreference(Context context, AttributeSet attrs) {
-        super(context, attrs, R.attr.cardPreferenceStyle);
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder holder) {
-        super.onBindViewHolder(holder);
-
-        initButtonsAndLayout(holder);
-    }
-
-    private void initButtonsAndLayout(PreferenceViewHolder holder) {
-        mPrimaryButton = Optional.ofNullable((Button) holder.findViewById(android.R.id.button1));
-        mSecondaryButton = Optional.ofNullable((Button) holder.findViewById(android.R.id.button2));
-        mButtonsGroup = Optional.ofNullable(holder.findViewById(R.id.card_preference_buttons));
-
-        setPrimaryButtonText(mPrimaryButtonText);
-        setPrimaryButtonClickListener(mPrimaryBtnClickListener);
-        setPrimaryButtonVisible(mPrimaryButtonVisible);
-        setSecondaryButtonText(mSecondaryButtonText);
-        setSecondaryButtonClickListener(mSecondaryBtnClickListener);
-        setSecondaryButtonVisible(mSecondaryButtonVisible);
-    }
-
-    /** Clear layout state if needed */
-    public void resetLayoutState() {
-        setPrimaryButtonVisible(false);
-        setSecondaryButtonVisible(false);
-    }
-
-    /**
-     * Register a callback to be invoked when the primary button is clicked.
-     *
-     * @param l the callback that will run
-     */
-    public void setPrimaryButtonClickListener(View.OnClickListener l) {
-        mPrimaryButton.ifPresent(button -> button.setOnClickListener(l));
-        mPrimaryBtnClickListener = l;
-    }
-
-    /**
-     * Register a callback to be invoked when the secondary button is clicked.
-     *
-     * @param l the callback that will run
-     */
-    public void setSecondaryButtonClickListener(View.OnClickListener l) {
-        mSecondaryButton.ifPresent(button -> button.setOnClickListener(l));
-        mSecondaryBtnClickListener = l;
-    }
-
-    /**
-     * Sets the text to be displayed on primary button.
-     *
-     * @param text text to be displayed
-     */
-    public void setPrimaryButtonText(String text) {
-        mPrimaryButton.ifPresent(button -> button.setText(text));
-        mPrimaryButtonText = text;
-    }
-
-    /**
-     * Sets the text to be displayed on secondary button.
-     *
-     * @param text text to be displayed
-     */
-    public void setSecondaryButtonText(String text) {
-        mSecondaryButton.ifPresent(button -> button.setText(text));
-        mSecondaryButtonText = text;
-    }
-
-    /**
-     * Set the visible on the primary button.
-     *
-     * @param visible {@code true} for visible
-     */
-    public void setPrimaryButtonVisible(boolean visible) {
-        mPrimaryButton.ifPresent(
-                button -> button.setVisibility(visible ? View.VISIBLE : View.GONE));
-        mPrimaryButtonVisible = visible;
-        updateButtonGroupsVisibility();
-    }
-
-    /**
-     * Set the visible on the secondary button.
-     *
-     * @param visible {@code true} for visible
-     */
-    public void setSecondaryButtonVisible(boolean visible) {
-        mSecondaryButton.ifPresent(
-                button -> button.setVisibility(visible ? View.VISIBLE : View.GONE));
-        mSecondaryButtonVisible = visible;
-        updateButtonGroupsVisibility();
-    }
-
-    /**
-     * Sets the text of content description on primary button.
-     *
-     * @param text text for the content description
-     */
-    public void setPrimaryButtonContentDescription(String text) {
-        mPrimaryButton.ifPresent(button -> button.setContentDescription(text));
-    }
-
-    /**
-     * Sets the text of content description on secondary button.
-     *
-     * @param text text for the content description
-     */
-    public void setSecondaryButtonContentDescription(String text) {
-        mSecondaryButton.ifPresent(button -> button.setContentDescription(text));
-    }
-
-    private void updateButtonGroupsVisibility() {
-        int visibility =
-                (mPrimaryButtonVisible || mSecondaryButtonVisible) ? View.VISIBLE : View.GONE;
-        mButtonsGroup.ifPresent(group -> group.setVisibility(visibility));
-    }
-}
diff --git a/src/com/android/settings/widget/CardPreference.kt b/src/com/android/settings/widget/CardPreference.kt
new file mode 100644
index 0000000..7122ac6
--- /dev/null
+++ b/src/com/android/settings/widget/CardPreference.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget
+
+import android.content.Context
+import android.content.res.Resources
+import android.util.AttributeSet
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.vectorResource
+import com.android.settings.spa.preference.ComposePreference
+import com.android.settingslib.spa.widget.card.CardButton
+import com.android.settingslib.spa.widget.card.CardModel
+import com.android.settingslib.spa.widget.card.SettingsCard
+
+/** A preference for settings banner tips card. */
+class CardPreference
+@JvmOverloads
+constructor(
+    context: Context,
+    attr: AttributeSet? = null,
+) : ComposePreference(context, attr) {
+
+    /** A icon resource id for displaying icon on tips card. */
+    var iconResId: Int? = null
+
+    /** The primary button's text. */
+    var primaryButtonText: String = ""
+
+    /** The accessibility content description of the primary button. */
+    var primaryButtonContentDescription: String? = null
+
+    /** The action for click on primary button. */
+    var primaryButtonAction: () -> Unit = {}
+
+    /** The visibility of primary button on tips card. The default value is `false`. */
+    var primaryButtonVisibility: Boolean = false
+
+    /** The text on the second button of this [SettingsCard]. */
+    var secondaryButtonText: String = ""
+
+    /** The accessibility content description of the secondary button. */
+    var secondaryButtonContentDescription: String? = null
+
+    /** The action for click on secondary button. */
+    var secondaryButtonAction: () -> Unit = {}
+
+    /** The visibility of secondary button on tips card. The default value is `false`. */
+    var secondaryButtonVisibility: Boolean = false
+
+    private var onDismiss: (() -> Unit)? = null
+
+    /** Enable the dismiss button on tips card. */
+    fun enableDismiss(enable: Boolean) =
+        if (enable) onDismiss = { isVisible = false } else onDismiss = null
+
+    /** Clear layout state if needed. */
+    fun resetLayoutState() {
+        primaryButtonVisibility = false
+        secondaryButtonVisibility = false
+        notifyChanged()
+    }
+
+    /** Build the tips card content to apply any changes of this card's property. */
+    fun buildContent() {
+        setContent {
+            SettingsCard(
+                CardModel(
+                    title = title?.toString() ?: "",
+                    text = summary?.toString() ?: "",
+                    buttons = listOfNotNull(configPrimaryButton(), configSecondaryButton()),
+                    onDismiss = onDismiss,
+                    imageVector =
+                        iconResId
+                            ?.takeIf { it != Resources.ID_NULL }
+                            ?.let { ImageVector.vectorResource(it) },
+                )
+            )
+        }
+    }
+
+    private fun configPrimaryButton(): CardButton? {
+        return if (primaryButtonVisibility)
+            CardButton(
+                text = primaryButtonText,
+                contentDescription = primaryButtonContentDescription,
+                onClick = primaryButtonAction,
+            )
+        else null
+    }
+
+    private fun configSecondaryButton(): CardButton? {
+        return if (secondaryButtonVisibility)
+            CardButton(
+                text = secondaryButtonText,
+                contentDescription = secondaryButtonContentDescription,
+                onClick = secondaryButtonAction,
+            )
+        else null
+    }
+
+    override fun notifyChanged() {
+        buildContent()
+        super.notifyChanged()
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
index cfd256f..fc72c41 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
@@ -18,6 +18,8 @@
 
 import static android.bluetooth.BluetoothDevice.BOND_NONE;
 
+import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceControlsController.KEY_DEVICE_CONTROLS_GENERAL_GROUP;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -29,8 +31,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.settings.SettingsEnums;
 import android.companion.CompanionDeviceManager;
 import android.content.Context;
+import android.content.Intent;
 import android.hardware.input.InputManager;
 import android.os.Bundle;
 import android.os.UserManager;
@@ -49,6 +53,8 @@
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 import com.google.common.collect.ImmutableList;
 
@@ -65,6 +71,8 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.fakes.RoboMenu;
 
+import java.util.List;
+
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
         com.android.settings.testutils.shadow.ShadowUserManager.class,
@@ -216,6 +224,38 @@
         verify(mFragment).finish();
     }
 
+    @Test
+    public void createPreferenceControllers_launchFromHAPage_deviceControllerNotExist() {
+        BluetoothDeviceDetailsFragment fragment = setupFragment();
+        Intent intent = fragment.getActivity().getIntent();
+        intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
+                SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS);
+        fragment.onAttach(mContext);
+
+        List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
+                mContext);
+
+        assertThat(controllerList.stream()
+                .anyMatch(controller -> controller.getPreferenceKey().equals(
+                        KEY_DEVICE_CONTROLS_GENERAL_GROUP))).isFalse();
+    }
+
+    @Test
+    public void createPreferenceControllers_notLaunchFromHAPage_deviceControllerExist() {
+        BluetoothDeviceDetailsFragment fragment = setupFragment();
+        Intent intent = fragment.getActivity().getIntent();
+        intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
+                SettingsEnums.PAGE_UNKNOWN);
+        fragment.onAttach(mContext);
+
+        List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
+                mContext);
+
+        assertThat(controllerList.stream()
+                .anyMatch(controller -> controller.getPreferenceKey().equals(
+                        KEY_DEVICE_CONTROLS_GENERAL_GROUP))).isTrue();
+    }
+
     private InputDevice createInputDeviceWithMatchingBluetoothAddress() {
         doReturn(new int[]{0}).when(mInputManager).getInputDeviceIds();
         InputDevice device = mock(InputDevice.class);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java
index 554227e..14ba337 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java
@@ -22,11 +22,17 @@
 
 import androidx.test.core.app.ApplicationProvider;
 
+import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 
+import java.util.ArrayList;
+
 @RunWith(RobolectricTestRunner.class)
 public class BatterySettingsFeatureProviderImplTest {
     private BatterySettingsFeatureProviderImpl mImpl;
@@ -52,4 +58,15 @@
     public void isBatteryInfoEnabled_returnFalse() {
         assertThat(mImpl.isBatteryInfoEnabled(mContext)).isFalse();
     }
+
+    @Test
+    public void addBatteryTipDetector_containsLowBatteryTip() {
+        var tips = new ArrayList<BatteryTip>();
+
+        mImpl.addBatteryTipDetector(
+                mContext, tips, new BatteryInfo(), new BatteryTipPolicy(mContext));
+
+        var expectedResult = tips.stream().anyMatch(tip -> tip instanceof LowBatteryTip);
+        assertThat(expectedResult).isTrue();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
index 8e3de7c..c5897f2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
@@ -19,20 +19,25 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
+import static org.robolectric.Shadows.shadowOf;
 
 import android.content.Context;
+import android.os.PowerManager;
+
+import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 import org.robolectric.util.ReflectionHelpers;
 
 import java.util.concurrent.TimeUnit;
@@ -40,73 +45,79 @@
 @RunWith(RobolectricTestRunner.class)
 public class LowBatteryDetectorTest {
 
+    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
     @Mock private BatteryInfo mBatteryInfo;
-    private BatteryTipPolicy mPolicy;
+
+    private BatteryTipPolicy mBatteryTipPolicy;
     private LowBatteryDetector mLowBatteryDetector;
     private Context mContext;
+    private PowerManager mPowerManager;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
+        mContext = ApplicationProvider.getApplicationContext();
+        mBatteryTipPolicy = spy(new BatteryTipPolicy(mContext));
 
-        mPolicy = spy(new BatteryTipPolicy(RuntimeEnvironment.application));
-        mContext = RuntimeEnvironment.application;
-        ReflectionHelpers.setField(mPolicy, "lowBatteryEnabled", true);
+        mPowerManager = mContext.getSystemService(PowerManager.class);
+        shadowOf(mPowerManager).setIsPowerSaveMode(false);
+
+        ReflectionHelpers.setField(mBatteryTipPolicy, "lowBatteryEnabled", true);
         mBatteryInfo.discharging = true;
 
-        mLowBatteryDetector =
-                new LowBatteryDetector(
-                        mContext, mPolicy, mBatteryInfo, false /* isPowerSaveMode */);
+        mLowBatteryDetector = new LowBatteryDetector(mContext, mBatteryTipPolicy, mBatteryInfo);
     }
 
     @Test
-    public void testDetect_disabledByPolicy_tipInvisible() {
-        ReflectionHelpers.setField(mPolicy, "lowBatteryEnabled", false);
-        mLowBatteryDetector =
-                new LowBatteryDetector(mContext, mPolicy, mBatteryInfo, true /* isPowerSaveMode */);
+    public void detect_disabledByPolicy_tipInvisible() {
+        ReflectionHelpers.setField(mBatteryTipPolicy, "lowBatteryEnabled", false);
+        shadowOf(mPowerManager).setIsPowerSaveMode(true);
+        mLowBatteryDetector = new LowBatteryDetector(mContext, mBatteryTipPolicy, mBatteryInfo);
 
         assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
     }
 
     @Test
-    public void testDetect_enabledByTest_tipNew() {
-        ReflectionHelpers.setField(mPolicy, "testLowBatteryTip", true);
+    public void detect_enabledByTest_tipNew() {
+        ReflectionHelpers.setField(mBatteryTipPolicy, "testLowBatteryTip", true);
 
         assertThat(mLowBatteryDetector.detect().getState()).isEqualTo(BatteryTip.StateType.NEW);
     }
 
     @Test
-    public void testDetect_lowBattery_tipNew() {
+    public void detect_lowBattery_tipNew() {
         mBatteryInfo.batteryLevel = 20;
         mBatteryInfo.remainingTimeUs = TimeUnit.DAYS.toMillis(1);
+
         assertThat(mLowBatteryDetector.detect().getState()).isEqualTo(BatteryTip.StateType.NEW);
     }
 
     @Test
-    public void testDetect_batterySaverOn_tipInvisible() {
-        mLowBatteryDetector =
-                new LowBatteryDetector(mContext, mPolicy, mBatteryInfo, true /* isPowerSaveMode */);
+    public void detect_batterySaverOn_tipInvisible() {
+        shadowOf(mPowerManager).setIsPowerSaveMode(true);
+        mLowBatteryDetector = new LowBatteryDetector(mContext, mBatteryTipPolicy, mBatteryInfo);
 
         assertThat(mLowBatteryDetector.detect().getState())
                 .isEqualTo(BatteryTip.StateType.INVISIBLE);
     }
 
     @Test
-    public void testDetect_charging_tipInvisible() {
+    public void detect_charging_tipInvisible() {
         mBatteryInfo.discharging = false;
 
         assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
     }
 
     @Test
-    public void testDetect_lowTimeEstimation_tipInvisible() {
+    public void detect_lowTimeEstimation_tipInvisible() {
         mBatteryInfo.batteryLevel = 50;
         mBatteryInfo.remainingTimeUs = TimeUnit.MINUTES.toMillis(1);
+
         assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
     }
 
     @Test
-    public void testDetect_noEarlyWarning_tipInvisible() {
+    public void detect_noEarlyWarning_tipInvisible() {
         mBatteryInfo.remainingTimeUs = TimeUnit.DAYS.toMicros(1);
         mBatteryInfo.batteryLevel = 100;
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
index 296306d..3f89f9b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
@@ -124,7 +124,7 @@
     public void updatePreference_shouldSetPrimaryButtonVisible() {
         mBatteryDefenderTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setPrimaryButtonVisible(true);
+        verify(mCardPreference).setPrimaryButtonVisibility(true);
     }
 
     @Test
@@ -134,14 +134,14 @@
 
         mBatteryDefenderTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setPrimaryButtonVisible(true);
+        verify(mCardPreference).setPrimaryButtonVisibility(true);
     }
 
     @Test
     public void updatePreference_whenNotCharging_setSecondaryButtonVisibleToBeFalse() {
         mBatteryDefenderTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setSecondaryButtonVisible(false);
+        verify(mCardPreference).setSecondaryButtonVisibility(false);
     }
 
     @Test
@@ -150,7 +150,7 @@
 
         mBatteryDefenderTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setSecondaryButtonVisible(false);
+        verify(mCardPreference).setSecondaryButtonVisibility(false);
     }
 
     private void fakeGetChargingStatusFailed() {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
index 45fdc1f..ea72ff6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
@@ -91,7 +91,7 @@
                                 mContext, R.layout.card_preference_layout, /* parent= */ null));
         CardPreference cardPreference = new CardPreference(mContext);
         cardPreference.onBindViewHolder(holder);
-        cardPreference.setPrimaryButtonVisible(true);
+        cardPreference.setPrimaryButtonVisibility(true);
 
         mBatteryTip.updatePreference(cardPreference);
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
index c1d039b..c66cf37 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
@@ -113,7 +113,7 @@
     @Test
     public void updatePreference_shouldSetSecondaryButtonVisible() {
         mIncompatibleChargerTip.updatePreference(mCardPreference);
-        verify(mCardPreference).setPrimaryButtonVisible(true);
+        verify(mCardPreference).setPrimaryButtonVisibility(true);
     }
 
     private String getLastErrorLog() {
diff --git a/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java
deleted file mode 100644
index e26643f..0000000
--- a/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java
+++ /dev/null
@@ -1,344 +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
- *Visibility_setGoneForPrimaryButton_buttonGroupIsGone
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.widget;
-
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.content.Context;
-import android.view.View;
-import android.widget.Button;
-
-import androidx.preference.PreferenceViewHolder;
-import androidx.test.core.app.ApplicationProvider;
-
-import com.android.settings.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class CardPreferenceTest {
-
-    private CardPreference mCardPreference;
-    private PreferenceViewHolder mHolder;
-
-    @Before
-    public void setUp() {
-        Context context = ApplicationProvider.getApplicationContext();
-        context.setTheme(R.style.Theme_Settings);
-        mCardPreference = new CardPreference(context);
-
-        mHolder = PreferenceViewHolder.createInstanceForTests(
-                View.inflate(context, R.layout.card_preference_layout, /* parent= */ null));
-    }
-
-    @Test
-    public void newACardPreference_layoutResourceShouldBeCardPreferenceLayout() {
-        Context context = ApplicationProvider.getApplicationContext();
-        context.setTheme(R.style.SettingsPreferenceTheme);
-
-        CardPreference cardPreference = new CardPreference(context);
-
-        assertThat(cardPreference.getLayoutResource()).isEqualTo(R.layout.card_preference_layout);
-    }
-
-    @Test
-    public void onBindViewHolder_noButtonVisible_buttonsLayoutIsGone() {
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
-    }
-
-    @Test
-    public void onBindViewHolder_setPrimaryButtonVisibility_buttonsLayoutIsVisible() {
-        mCardPreference.setPrimaryButtonVisible(true);
-
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(VISIBLE);
-    }
-
-    @Test
-    public void onBindViewHolder_setPrimaryButtonVisibilityToVisible() {
-        mCardPreference.setPrimaryButtonVisible(true);
-
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getPrimaryButton().getVisibility()).isEqualTo(VISIBLE);
-    }
-
-    @Test
-    public void onBindViewHolder_setSecondaryButtonVisibility_buttonsLayoutIsVisible() {
-        mCardPreference.setSecondaryButtonVisible(true);
-
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(VISIBLE);
-    }
-
-    @Test
-    public void onBindViewHolder_setSecondaryButtonVisibilityToVisible() {
-        mCardPreference.setSecondaryButtonVisible(true);
-
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getSecondaryButton().getVisibility()).isEqualTo(VISIBLE);
-    }
-
-    @Test
-    public void onBindViewHolder_setPrimaryButtonTextToExpectedText() {
-        String expectedText = "primary-button";
-        mCardPreference.setPrimaryButtonText(expectedText);
-
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getPrimaryButton().getText().toString()).isEqualTo(expectedText);
-    }
-
-    @Test
-    public void onBindViewHolder_setSecondaryButtonTextToExpectedText() {
-        String expectedText = "secondary-button";
-        mCardPreference.setSecondaryButtonText(expectedText);
-
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getSecondaryButton().getText().toString()).isEqualTo(expectedText);
-    }
-
-    @Test
-    public void onBindViewHolder_initialTextForPrimaryButtonShouldBeEmpty() {
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getPrimaryButton().getText().toString()).isEqualTo("");
-    }
-
-    @Test
-    public void onBindViewHolder_initialTextForSecondaryButtonShouldBeEmpty() {
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getSecondaryButton().getText().toString()).isEqualTo("");
-    }
-
-    @Test
-    public void performClickOnPrimaryButton_callClickListener() {
-        final boolean[] hasCalled = {false};
-        View.OnClickListener clickListener = v -> hasCalled[0] = true;
-        mCardPreference.setPrimaryButtonClickListener(clickListener);
-
-        mCardPreference.onBindViewHolder(mHolder);
-        getPrimaryButton().performClick();
-
-        assertThat(hasCalled[0]).isTrue();
-    }
-
-    @Test
-    public void performClickOnSecondaryButton_callClickListener() {
-        final boolean[] hasCalled = {false};
-        View.OnClickListener clickListener = v -> hasCalled[0] = true;
-        mCardPreference.setSecondaryButtonClickListener(clickListener);
-
-        mCardPreference.onBindViewHolder(mHolder);
-        getSecondaryButton().performClick();
-
-        assertThat(hasCalled[0]).isTrue();
-    }
-
-    @Test
-    public void onBindViewHolder_primaryButtonDefaultIsGone() {
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getPrimaryButton().getVisibility()).isEqualTo(GONE);
-    }
-
-    @Test
-    public void onBindViewHolder_secondaryButtonDefaultIsGone() {
-        mCardPreference.onBindViewHolder(mHolder);
-
-        assertThat(getSecondaryButton().getVisibility()).isEqualTo(GONE);
-    }
-
-    @Test
-    public void setPrimaryButtonVisibility_setTrueAfterBindViewHolder_isVisible() {
-        mCardPreference.setPrimaryButtonVisible(false);
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setPrimaryButtonVisible(true);
-
-        assertThat(getPrimaryButton().getVisibility()).isEqualTo(VISIBLE);
-    }
-
-    @Test
-    public void setPrimaryButtonText_setAfterBindViewHolder_setOnUi() {
-        String expectedText = "123456";
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setPrimaryButtonText(expectedText);
-
-        assertThat(getPrimaryButton().getText().toString()).isEqualTo(expectedText);
-    }
-
-    @Test
-    public void setPrimaryButtonText_setNull_isEmptyText() {
-        final String emptyString = "";
-        mCardPreference.setPrimaryButtonText("1234");
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setPrimaryButtonText(null);
-
-        assertThat(getPrimaryButton().getText().toString()).isEqualTo(emptyString);
-    }
-
-    @Test
-    public void setPrimaryButtonClickListener_setAfterOnBindViewHolder() {
-        final String[] hasCalled = {""};
-        String expectedClickedResult = "was called";
-        View.OnClickListener clickListener = v -> hasCalled[0] = expectedClickedResult;
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setPrimaryButtonClickListener(clickListener);
-        getPrimaryButton().performClick();
-
-        assertThat(hasCalled[0]).isEqualTo(expectedClickedResult);
-    }
-
-    @Test
-    public void setPrimaryButtonClickListener_setNull_clearTheOnClickListener() {
-        final String[] hasCalled = {"not called"};
-        View.OnClickListener clickListener = v -> hasCalled[0] = "called once";
-        mCardPreference.setPrimaryButtonClickListener(clickListener);
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setPrimaryButtonClickListener(null);
-        getPrimaryButton().performClick();
-
-        assertThat(hasCalled[0]).isEqualTo("not called");
-    }
-
-    @Test
-    public void setSecondaryButtonVisibility_setTrueAfterBindViewHolder_isVisible() {
-        mCardPreference.setSecondaryButtonVisible(false);
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setSecondaryButtonVisible(true);
-
-        assertThat(getSecondaryButton().getVisibility()).isEqualTo(VISIBLE);
-    }
-
-    @Test
-    public void setSecondaryButtonText_setAfterBindViewHolder_setOnUi() {
-        String expectedText = "10101010";
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setSecondaryButtonText(expectedText);
-
-        assertThat(getSecondaryButton().getText().toString()).isEqualTo(expectedText);
-    }
-
-    @Test
-    public void setSecondaryButtonText_setNull_isEmptyText() {
-        String emptyString = "";
-        mCardPreference.setSecondaryButtonText("1234");
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setSecondaryButtonText(null);
-
-        assertThat(getSecondaryButton().getText().toString()).isEqualTo(emptyString);
-    }
-
-    @Test
-    public void setSecondaryButtonClickListener_setAfterOnBindViewHolder() {
-        final String[] hasCalled = {""};
-        String expectedClickedResult = "2nd was called";
-        View.OnClickListener clickListener = v -> hasCalled[0] = expectedClickedResult;
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setSecondaryButtonClickListener(clickListener);
-        getSecondaryButton().performClick();
-
-        assertThat(hasCalled[0]).isEqualTo(expectedClickedResult);
-    }
-
-    @Test
-    public void setSecondaryButtonClickListener_setNull_clearTheOnClickListener() {
-        final String[] hasCalled = {"not called"};
-        View.OnClickListener clickListener = v -> hasCalled[0] = "called once";
-        mCardPreference.setSecondaryButtonClickListener(clickListener);
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.setSecondaryButtonClickListener(null);
-        getSecondaryButton().performClick();
-
-        assertThat(hasCalled[0]).isEqualTo("not called");
-    }
-
-    @Test
-    public void setPrimaryButtonVisibility_setGoneForSecondaryButton_buttonGroupIsGone() {
-        mCardPreference.setPrimaryButtonVisible(true);
-        mCardPreference.setSecondaryButtonVisible(false);
-        mCardPreference.onBindViewHolder(mHolder);
-        assertWithMessage("PreCondition: buttonsView should be Visible")
-                .that(getCardPreferenceButtonsView().getVisibility())
-                .isEqualTo(VISIBLE);
-
-        mCardPreference.setPrimaryButtonVisible(false);
-
-        assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
-    }
-
-    @Test
-    public void setSecondaryButtonVisibility_setGoneForPrimaryButton_buttonGroupIsGone() {
-        mCardPreference.setPrimaryButtonVisible(false);
-        mCardPreference.setSecondaryButtonVisible(true);
-        mCardPreference.onBindViewHolder(mHolder);
-        assertWithMessage("PreCondition: buttonsView should be Visible")
-                .that(getCardPreferenceButtonsView().getVisibility())
-                .isEqualTo(VISIBLE);
-
-        mCardPreference.setSecondaryButtonVisible(false);
-
-        assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
-    }
-
-    @Test
-    public void resetLayoutState_buttonGroupIsGone() {
-        mCardPreference.setPrimaryButtonVisible(true);
-        mCardPreference.setSecondaryButtonVisible(true);
-        mCardPreference.onBindViewHolder(mHolder);
-
-        mCardPreference.resetLayoutState();
-
-        assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
-    }
-
-    private View getCardPreferenceButtonsView() {
-        return mHolder.findViewById(R.id.card_preference_buttons);
-    }
-
-    private Button getPrimaryButton() {
-        return (Button) mHolder.findViewById(android.R.id.button1);
-    }
-
-    private Button getSecondaryButton() {
-        return (Button) mHolder.findViewById(android.R.id.button2);
-    }
-}
diff --git a/tests/spa_unit/src/com/android/settings/widget/CardPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/widget/CardPreferenceTest.kt
new file mode 100644
index 0000000..0483e36
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/widget/CardPreferenceTest.kt
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget
+
+import android.content.Context
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.test.assertContentDescriptionEquals
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class CardPreferenceTest {
+
+    @get:Rule val composeTestRule = createComposeRule()
+    private lateinit var context: Context
+
+    @Before
+    fun setUp() {
+        context = ApplicationProvider.getApplicationContext()
+    }
+
+    @Test
+    fun enableDismiss_whenEnable_shouldBeDisplayed() {
+        composeTestRule.setContent { buildCardPreference(enableDismiss = true) }
+
+        composeTestRule.onNodeWithContentDescription("Dismiss").assertIsDisplayed()
+    }
+
+    @Test
+    fun enableDismiss_whenDisable_shouldBeDisplayed() {
+        composeTestRule.setContent { buildCardPreference(enableDismiss = false) }
+
+        composeTestRule.onNodeWithContentDescription("Dismiss").assertIsNotDisplayed()
+    }
+
+    @Test
+    fun primaryButton_whenVisible_shouldBeDisplayed() {
+        val expectedPrimaryButtonText = "You can see me"
+        composeTestRule.setContent {
+            buildCardPreference(
+                primaryButtonText = expectedPrimaryButtonText,
+                primaryButtonVisibility = true,
+            )
+        }
+
+        composeTestRule.onNodeWithText(expectedPrimaryButtonText).assertIsDisplayed()
+    }
+
+    @Test
+    fun primaryButton_whenInvisible_shouldBeDisplayed() {
+        val expectedButtonText = "You cannot see me"
+        composeTestRule.setContent {
+            buildCardPreference(
+                primaryButtonText = expectedButtonText,
+                primaryButtonVisibility = false,
+            )
+        }
+
+        composeTestRule.onNodeWithText(expectedButtonText).assertIsNotDisplayed()
+    }
+
+    @Test
+    fun primaryButtonAction_whenClick_performAction() {
+        val buttonText = "click me"
+        var clicked = false
+        composeTestRule.setContent {
+            buildCardPreference(
+                primaryButtonText = buttonText,
+                primaryButtonVisibility = true,
+                primaryButtonAction = { clicked = true }
+            )
+        }
+
+        composeTestRule.onNodeWithText(buttonText).performClick()
+
+        assertThat(clicked).isTrue()
+    }
+
+    @Test
+    fun primaryButtonContentDescription_whenSet_shouldBeExists() {
+        val expectedText = "this is a content description"
+        val buttonText = "primary-button"
+        composeTestRule.setContent {
+            buildCardPreference(
+                primaryButtonText = buttonText,
+                primaryButtonContentDescription = expectedText,
+                primaryButtonVisibility = true,
+            )
+        }
+
+        composeTestRule.onNodeWithText(buttonText).assertContentDescriptionEquals(expectedText)
+    }
+
+    @Test
+    fun secondaryButton_whenVisible_shouldBeDisplayed() {
+        val expectedSecondaryButtonText = "You can see me"
+        composeTestRule.setContent {
+            buildCardPreference(
+                secondaryButtonText = expectedSecondaryButtonText,
+                secondaryButtonVisibility = true,
+            )
+        }
+
+        composeTestRule.onNodeWithText(expectedSecondaryButtonText).assertIsDisplayed()
+    }
+
+    @Test
+    fun secondaryButton_whenInvisible_shouldBeDisplayed() {
+        val expectedButtonText = "You cannot see me"
+        composeTestRule.setContent {
+            buildCardPreference(
+                secondaryButtonText = expectedButtonText,
+                secondaryButtonVisibility = false,
+            )
+        }
+
+        composeTestRule.onNodeWithText(expectedButtonText).assertIsNotDisplayed()
+    }
+
+    @Test
+    fun secondaryButtonAction_whenClick_performAction() {
+        val buttonText = "click me2"
+        var clicked = false
+        composeTestRule.setContent {
+            buildCardPreference(
+                secondaryButtonText = buttonText,
+                secondaryButtonVisibility = true,
+                secondaryButtonAction = { clicked = true }
+            )
+        }
+
+        composeTestRule.onNodeWithText(buttonText).performClick()
+
+        assertThat(clicked).isTrue()
+    }
+
+    @Test
+    fun secondaryButtonContentDescription_whenSet_shouldBeExists() {
+        val expectedText = "found bug yay"
+        val buttonText = "secondary-button"
+        composeTestRule.setContent {
+            buildCardPreference(
+                secondaryButtonText = buttonText,
+                secondaryButtonContentDescription = expectedText,
+                secondaryButtonVisibility = true,
+            )
+        }
+
+        composeTestRule.onNodeWithText(buttonText).assertContentDescriptionEquals(expectedText)
+    }
+
+    @Test
+    fun resetLayoutState_shouldRemoveThePrimaryButton() {
+        val buttonText = "9527"
+        val cardPreference =
+            CardPreference(context)
+                .apply {
+                    primaryButtonText = buttonText
+                    primaryButtonVisibility = true
+                }
+                .also { it.buildContent() }
+
+        cardPreference.resetLayoutState()
+        composeTestRule.setContent { cardPreference.Content() }
+
+        composeTestRule.onNodeWithText(buttonText).assertDoesNotExist()
+    }
+
+    @Test
+    fun resetLayoutState_shouldRemoveTheSecondaryButton() {
+        val buttonText = "4567"
+        val cardPreference =
+            CardPreference(context)
+                .apply {
+                    secondaryButtonText = buttonText
+                    secondaryButtonVisibility = true
+                }
+                .also { it.buildContent() }
+
+        cardPreference.resetLayoutState()
+        composeTestRule.setContent { cardPreference.Content() }
+
+        composeTestRule.onNodeWithText(buttonText).assertDoesNotExist()
+    }
+
+    @Composable
+    private fun buildCardPreference(
+        iconResId: Int? = R.drawable.ic_battery_status_protected_24dp,
+        primaryButtonText: String = "primary text",
+        primaryButtonContentDescription: String? = "primary description",
+        primaryButtonAction: () -> Unit = {},
+        primaryButtonVisibility: Boolean = false,
+        secondaryButtonText: String = "secondary button",
+        secondaryButtonContentDescription: String? = null,
+        secondaryButtonAction: () -> Unit = {},
+        secondaryButtonVisibility: Boolean = false,
+        enableDismiss: Boolean = true,
+    ) =
+        CardPreference(context)
+            .apply {
+                this.iconResId = iconResId
+                this.primaryButtonText = primaryButtonText
+                this.primaryButtonContentDescription = primaryButtonContentDescription
+                this.primaryButtonAction = primaryButtonAction
+                this.primaryButtonVisibility = primaryButtonVisibility
+                this.secondaryButtonText = secondaryButtonText
+                this.secondaryButtonContentDescription = secondaryButtonContentDescription
+                this.secondaryButtonAction = secondaryButtonAction
+                this.secondaryButtonVisibility = secondaryButtonVisibility
+                this.enableDismiss(enableDismiss)
+            }
+            .also { it.buildContent() }
+            .Content()
+}
diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
index acf590b..b5aeac7 100644
--- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.settings.applications.credentials;
 
 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
 import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -55,6 +56,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 
 @RunWith(AndroidJUnit4.class)
@@ -121,17 +123,34 @@
                 createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
         controller.setSimulateConnectedForTests(true);
         assertThat(controller.isConnected()).isTrue();
-        controller.setVisibility(true);
-        assertThat(controller.getVisibility()).isTrue();
+        controller.setSimulateHiddenForTests(Optional.of(false));
+        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 
     @Test
+    public void getAvailabilityStatus_isHidden_returnsConditionallyUnavailable() {
+        CredentialManagerPreferenceController controller =
+                createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
+        controller.setSimulateConnectedForTests(true);
+        assertThat(controller.isConnected()).isTrue();
+        controller.setSimulateHiddenForTests(Optional.of(true));
+        assertThat(controller.isHiddenDueToNoProviderSet()).isTrue();
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
     public void displayPreference_withServices_preferencesAdded() {
         CredentialManagerPreferenceController controller =
                 createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
+        controller.setSimulateConnectedForTests(true);
+        controller.setSimulateHiddenForTests(Optional.of(false));
+
+        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+        assertThat(controller.isConnected()).isTrue();
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+
         controller.displayPreference(mScreen);
-        assertThat(controller.isConnected()).isFalse();
         assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
 
         Preference pref = mCredentialsPreferenceCategory.getPreference(0);
@@ -150,8 +169,8 @@
                 createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
         controller.setSimulateConnectedForTests(true);
         assertThat(controller.isConnected()).isTrue();
-        controller.setVisibility(true);
-        assertThat(controller.getVisibility()).isTrue();
+        controller.setSimulateHiddenForTests(Optional.of(false));
+        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
 
         // Test the data is correct.
@@ -194,8 +213,8 @@
                                 createCredentialProviderInfo("com.android.provider6", "ClassA")));
         controller.setSimulateConnectedForTests(true);
         assertThat(controller.isConnected()).isTrue();
-        controller.setVisibility(true);
-        assertThat(controller.getVisibility()).isTrue();
+        controller.setSimulateHiddenForTests(Optional.of(false));
+        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
 
         // Ensure that we stay under 5 providers.
@@ -263,8 +282,8 @@
                 createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
         controller.setSimulateConnectedForTests(true);
         assertThat(controller.isConnected()).isTrue();
-        controller.setVisibility(true);
-        assertThat(controller.getVisibility()).isTrue();
+        controller.setSimulateHiddenForTests(Optional.of(false));
+        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
 
         // Test the data is correct.
@@ -316,9 +335,14 @@
         CredentialManagerPreferenceController controller =
                 createControllerWithServices(
                         Lists.newArrayList(serviceA1, serviceB1, serviceC1, serviceC2, serviceC3));
-        controller.displayPreference(mScreen);
+        controller.setSimulateConnectedForTests(true);
+        controller.setSimulateHiddenForTests(Optional.of(false));
 
-        assertThat(controller.isConnected()).isFalse();
+        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+        assertThat(controller.isConnected()).isTrue();
+        assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+
+        controller.displayPreference(mScreen);
         assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(3);
 
         Map<String, CredentialManagerPreferenceController.CombiPreference> prefs =