Merge "Add developer option for screenshare protections" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c8f35ae..96b798a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3232,7 +3232,8 @@
 
         <receiver
             android:name=".fuelgauge.batteryusage.BootBroadcastReceiver"
-            android:exported="true">
+            android:exported="true"
+            android:permission="com.android.settings.BATTERY_DATA">
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
                 <action android:name="com.google.android.setupwizard.SETUP_WIZARD_FINISHED"/>
diff --git a/OWNERS b/OWNERS
index 6698752..12cd4ea 100644
--- a/OWNERS
+++ b/OWNERS
@@ -11,7 +11,6 @@
 jiannan@google.com
 millchen@google.com
 sunnyshao@google.com
-yantingyang@google.com
 
 # Android Settings extended
 chaohuiw@google.com
diff --git a/aconfig/settings_connecteddevice_flag_declarations.aconfig b/aconfig/settings_connecteddevice_flag_declarations.aconfig
index 5ba2129..0fc164e 100644
--- a/aconfig/settings_connecteddevice_flag_declarations.aconfig
+++ b/aconfig/settings_connecteddevice_flag_declarations.aconfig
@@ -33,4 +33,11 @@
   namespace: "pixel_cross_device_control"
   description: "Order the saved bluetooth devices by most recently connected."
   bug: "306160434"
+}
+
+flag {
+  name: "enable_hide_exclusively_managed_bluetooth_device"
+  namespace: "dck_framework"
+  description: "Hide exclusively managed Bluetooth devices in BT settings menu."
+  bug: "322285078"
 }
\ No newline at end of file
diff --git a/aconfig/settings_flag_declarations.aconfig b/aconfig/settings_flag_declarations.aconfig
index 56c4b32..36f104c 100644
--- a/aconfig/settings_flag_declarations.aconfig
+++ b/aconfig/settings_flag_declarations.aconfig
@@ -13,3 +13,10 @@
     description: "Enabling will provide an explicit package name for Intent to update mainline modules"
     bug: "278987474"
 }
+
+flag {
+    name: "app_archiving"
+    namespace: "android_settings"
+    description: "Feature flag to enable the archiving feature."
+    bug: "323164382"
+}
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c26e316..9762f83 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7265,7 +7265,7 @@
     <!-- Summary text describing signal strength to the user.  [CHAR LIMIT=60] -->
     <string name="sim_signal_strength"><xliff:g id="dbm">%1$d</xliff:g> dBm <xliff:g id="asu">%2$d</xliff:g> asu</string>
     <!-- Title for SIM notification.  [CHAR LIMIT=40] -->
-    <string name="sim_notification_title">SIMs changed.</string>
+    <string name="sim_notification_title">Your SIMs changed</string>
     <!-- Message under title informing the user to touch to go to SIM Cards in Settings.  [CHAR LIMIT=40] -->
     <string name="sim_notification_summary">Tap to set up</string>
 
@@ -9055,7 +9055,7 @@
     <string name="screen_pinning_unlock_none">Lock device when unpinning</string>
 
     <!-- [CHAR LIMIT=60] turn eSim deletion confirmation on/off  -->
-    <string name="confirm_sim_deletion_title">Confirm SIM deletion</string>
+    <string name="confirm_sim_deletion_title">Confirm you want to erase your eSIM</string>
     <!-- [CHAR LIMIT=NONE] eSim deletion confirmation description  -->
     <string name="confirm_sim_deletion_description">Verify it\u0027s you before erasing an eSIM</string>
 
@@ -11370,7 +11370,7 @@
          the user that the way to disable this SIM is to physically remove it. This is in contrast
          to eSIM's, which can disabled using an on/off toggle switch. [CHAR LIMIT=NONE] -->
     <string name="mobile_network_disable_sim_explanation">
-        To disable this SIM, remove the SIM card
+        To turn off this SIM, remove the SIM card
     </string>
 
     <!--Summary used when a physical SIM is disabled, indicating that tapping on the preference will
@@ -11378,7 +11378,7 @@
         Network & internet page (if there are no other SIMs), or on the mobile network list page.
         [CHAR LIMIT=50] -->
     <string name="mobile_network_tap_to_activate">
-        Tap to activate <xliff:g id="carrier" example="T-mobile">%1$s</xliff:g>
+        Tap to activate your <xliff:g id="carrier" example="T-mobile">%1$s</xliff:g> SIM
     </string>
 
     <!-- Mobile network details page. Label for an option that lets the user delete an eSIM from
@@ -11502,13 +11502,13 @@
     <!-- Text of carrier list item in the mep confirmation dialog asking the user if they want to turn off the carrier. [CHAR_LIMIT=NONE] -->
     <string name="sim_action_switch_sub_dialog_info_outline_for_turning_off">Turning off a SIM won\u2019t cancel your service</string>
     <!-- Status message indicating the device is in the process of disconnecting from one mobile network and immediately connecting to another. [CHAR_LIMIT=NONE] -->
-    <string name="sim_action_enabling_sim_without_carrier_name">Connecting to network&#8230;</string>
+    <string name="sim_action_enabling_sim_without_carrier_name">Activating your SIM&#8230;</string>
     <!-- Text of progress dialog indicating the subscription switch is in progress. [CHAR_LIMIT=NONE] -->
-    <string name="sim_action_switch_sub_dialog_progress">Switching to <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g> for calls and messages&#8230;</string>
+    <string name="sim_action_switch_sub_dialog_progress">Switching to <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>&#8230;</string>
     <!-- Title of error message indicating that the device could not disconnect from one mobile network and immediately connect to another. [CHAR_LIMIT=NONE] -->
-    <string name="sim_action_enable_sim_fail_title">Can\u2019t switch carrier</string>
+    <string name="sim_action_enable_sim_fail_title">Can\u2019t switch SIMs</string>
     <!-- Body text of error message indicating the device could not disconnect from one mobile network and immediately connect to another, due to an unspecified issue. [CHAR_LIMIT=NONE] -->
-    <string name="sim_action_enable_sim_fail_text">The carrier can\u2019t be switched due to an error.</string>
+    <string name="sim_action_enable_sim_fail_text">Something went wrong. Can\u2019t switch SIMs.</string>
     <!-- Title of confirmation dialog asking the user if they want to disable subscription. [CHAR_LIMIT=NONE] -->
     <string name="privileged_action_disable_sub_dialog_title">Turn off <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>?</string>
     <!-- Title of confirmation dialog asking the user if they want to disable subscription. [CHAR_LIMIT=NONE] -->
@@ -11516,9 +11516,9 @@
     <!-- Disabling SIMs progress dialog message [CHAR LIMIT=NONE] -->
     <string name="privileged_action_disable_sub_dialog_progress">Turning off SIM<xliff:g id="ellipsis" example="...">&#8230;</xliff:g></string>
     <!-- Title of error messaging indicating the device could not disable the mobile network. [CHAR LIMIT=NONE] -->
-    <string name="privileged_action_disable_fail_title">Can\u2019t disable carrier</string>
+    <string name="privileged_action_disable_fail_title">Can\u2019t turn off SIM</string>
     <!-- Body text of error message indicating the device could not disable the mobile network, due to an unknown issue. [CHAR LIMIT=NONE] -->
-    <string name="privileged_action_disable_fail_text">Something went wrong and your carrier could not be disabled.</string>
+    <string name="privileged_action_disable_fail_text">Something went wrong and your SIM could not be turned off.</string>
     <!-- Title on a dialog asking the users whether they want to enable DSDS mode. [CHAR LIMIT=NONE] -->
     <string name="sim_action_enable_dsds_title">Use 2 SIMs?</string>
     <!-- Message in a dialog indicating the user can enable DSDS mode. [CHAR LIMIT=NONE] -->
@@ -11598,7 +11598,7 @@
     <!-- Title on a push notification indicating that the user's device is in the middle of switching between mobile networks. [CHAR LIMIT=NONE] -->
     <string name="sim_switch_channel_id">Carrier switching</string>
     <!--  The title of post DSDS reboot notification. The title includes carrier's name. [CHAR LIMIT=NONE] -->
-    <string name="post_dsds_reboot_notification_title_with_carrier"><xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g> is active</string>
+    <string name="post_dsds_reboot_notification_title_with_carrier">Your <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g> SIM is active</string>
     <!--  The body text of post DSDS reboot notification. [CHAR LIMIT=NONE] -->
     <string name="post_dsds_reboot_notification_text">Tap to update SIM settings</string>
     <!-- Title on a push notification indicating that the user's device switched to a new mobile network. [CHAR LIMIT=NONE] -->
@@ -11614,17 +11614,17 @@
 
     <!-- Strings for choose SIM activity -->
     <!--  The title text of choose SIM activity. [CHAR LIMIT=NONE] -->
-    <string name="choose_sim_title">Choose a number to use</string>
+    <string name="choose_sim_title">Choose a SIM to use</string>
     <!--  The body text of choose SIM activity. [CHAR LIMIT=NONE] -->
     <string name="choose_sim_text">{count, plural,
-      =1      {1 number is available on this device, but only one can be used at a time}
-      =2      {2 numbers are available on this device, but only one can be used at a time}
-      other   {# numbers are available on this device, but only one can be used at a time}
+      =1      {1 SIM is available on this device, but only one can be used at a time}
+      =2      {2 SIMs are available on this device, but only one can be used at a time}
+      other   {# SIMs are available on this device, but only one can be used at a time}
     }</string>
     <!-- String indicating that we are activating the profile [CHAR LIMIT=NONE] -->
     <string name="choose_sim_activating">Activating<xliff:g id="ellipsis" example="...">&#8230;</xliff:g></string>
     <!-- String indicating that we failed to activate the selected profile [CHAR LIMIT=NONE] -->
-    <string name="choose_sim_could_not_activate">Couldn\u2019t be activated right now</string>
+    <string name="choose_sim_could_not_activate">Couldn\u2019t activate this SIM right now</string>
 
     <!-- Strings for switch SIM confirmation dialog. -->
     <!--  The title text of switch SIM confirmation dialog. [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/settings/applications/AppCounter.java b/src/com/android/settings/applications/AppCounter.java
index d536932..2b1e47e 100644
--- a/src/com/android/settings/applications/AppCounter.java
+++ b/src/com/android/settings/applications/AppCounter.java
@@ -22,12 +22,15 @@
 import android.content.pm.PackageManager.ApplicationInfoFlags;
 import android.content.pm.UserInfo;
 import android.os.AsyncTask;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.settings.flags.Flags;
+
 import java.util.List;
 
 public abstract class AppCounter extends AsyncTask<Void, Void, Integer> {
@@ -54,7 +57,7 @@
         for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {
             long flags = PackageManager.GET_DISABLED_COMPONENTS
                     | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
-                    | (mFf.archiving() ? PackageManager.MATCH_ARCHIVED_PACKAGES : 0)
+                    | (isArchivingEnabled() ? PackageManager.MATCH_ARCHIVED_PACKAGES : 0)
                     | (user.isAdmin() ? PackageManager.MATCH_ANY_USER : 0);
             ApplicationInfoFlags infoFlags = ApplicationInfoFlags.of(flags);
             final List<ApplicationInfo> list =
@@ -68,6 +71,11 @@
         return count;
     }
 
+    private boolean isArchivingEnabled() {
+        return mFf.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false)
+                || Flags.appArchiving();
+    }
+
     @Override
     protected void onPostExecute(Integer count) {
         onCountComplete(count);
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/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
index 489c095..012220c 100644
--- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
@@ -24,6 +24,8 @@
 import androidx.preference.Preference;
 
 import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.flags.Flags;
+import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
 /**
@@ -95,6 +97,15 @@
                         cachedDevice.getName() + ", isFilterMatched : " + isFilterMatched);
             }
         }
+        if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
+            if (BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext,
+                    cachedDevice.getDevice())) {
+                if (DBG) {
+                    Log.d(TAG, "isFilterMatched() hide BluetoothDevice with exclusive manager");
+                }
+                return false;
+            }
+        }
         return isFilterMatched;
     }
 
diff --git a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
index bfd4221..1db90fa 100644
--- a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
@@ -25,6 +25,8 @@
 import androidx.preference.Preference;
 
 import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.flags.Flags;
+import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
 
@@ -99,12 +101,22 @@
     @Override
     public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
         final BluetoothDevice device = cachedDevice.getDevice();
-        Log.d(TAG, "isFilterMatched() device name : " + cachedDevice.getName() +
-                ", is connected : " + device.isConnected() + ", is profile connected : "
-                + cachedDevice.isConnected());
-        return device.getBondState() == BluetoothDevice.BOND_BONDED
-                && (mShowConnectedDevice || (!device.isConnected() && isDeviceInCachedDevicesList(
-                cachedDevice)));
+        boolean isExclusivelyManaged = BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext,
+                cachedDevice.getDevice());
+        Log.d(TAG, "isFilterMatched() device name : " + cachedDevice.getName()
+                + ", is connected : " + device.isConnected() + ", is profile connected : "
+                + cachedDevice.isConnected() + ", is exclusively managed : "
+                + isExclusivelyManaged);
+        if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
+            return device.getBondState() == BluetoothDevice.BOND_BONDED
+                    && (mShowConnectedDevice || (!device.isConnected()
+                    && isDeviceInCachedDevicesList(cachedDevice)))
+                    && !isExclusivelyManaged;
+        } else {
+            return device.getBondState() == BluetoothDevice.BOND_BONDED
+                    && (mShowConnectedDevice || (!device.isConnected()
+                    && isDeviceInCachedDevicesList(cachedDevice)));
+        }
     }
 
     @Override
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/batterysaver/BatterySaverScheduleRadioButtonsController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java
index 45c1be0..6425833 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java
@@ -41,7 +41,7 @@
 public class BatterySaverScheduleRadioButtonsController {
     private static final String TAG = "BatterySaverScheduleRadioButtonsController";
 
-    public static final int TRIGGER_LEVEL_MIN = 10;
+    public static final int TRIGGER_LEVEL_MIN = 20;
 
     private Context mContext;
     private BatterySaverScheduleSeekBarController mSeekBarController;
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/gestures/SystemNavigationGestureSettings.java b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
index c6b1bdb..c40212b 100644
--- a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
+++ b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
@@ -41,7 +41,6 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.settings.R;
 import com.android.settings.accessibility.AccessibilityGestureNavigationTutorial;
 import com.android.settings.core.SubSettingLauncher;
@@ -354,7 +353,7 @@
     private boolean isAnyServiceSupportAccessibilityButton() {
         final AccessibilityManager ams = getContext().getSystemService(AccessibilityManager.class);
         final List<String> targets = ams.getAccessibilityShortcutTargets(
-                ShortcutConstants.UserShortcutType.SOFTWARE);
+                AccessibilityManager.ACCESSIBILITY_BUTTON);
         return !targets.isEmpty();
     }
 
diff --git a/src/com/android/settings/notification/PoliteNotifWorkProfileToggleController.java b/src/com/android/settings/notification/PoliteNotifWorkProfileToggleController.java
index 65b4fb8..99d0a69 100644
--- a/src/com/android/settings/notification/PoliteNotifWorkProfileToggleController.java
+++ b/src/com/android/settings/notification/PoliteNotifWorkProfileToggleController.java
@@ -62,7 +62,7 @@
     @Override
     public boolean isChecked() {
         return Settings.System.getIntForUser(mContext.getContentResolver(),
-                Settings.System.NOTIFICATION_COOLDOWN_ENABLED, OFF, mManagedProfileId) != OFF;
+                Settings.System.NOTIFICATION_COOLDOWN_ENABLED, ON, mManagedProfileId) != OFF;
     }
 
     @Override
diff --git a/src/com/android/settings/spa/app/appinfo/AppButtons.kt b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
index dcce1d9..3d9c4b1 100644
--- a/src/com/android/settings/spa/app/appinfo/AppButtons.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
@@ -17,8 +17,8 @@
 package com.android.settings.spa.app.appinfo
 
 import android.content.pm.ApplicationInfo
-import android.content.pm.FeatureFlags
-import android.content.pm.FeatureFlagsImpl
+import android.content.pm.FeatureFlags as PmFeatureFlags
+import android.content.pm.FeatureFlagsImpl as PmFeatureFlagsImpl
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -34,7 +34,7 @@
 fun AppButtons(
     packageInfoPresenter: PackageInfoPresenter,
     isHibernationSwitchEnabledStateFlow: MutableStateFlow<Boolean>,
-    featureFlags: FeatureFlags = FeatureFlagsImpl()
+    featureFlags: PmFeatureFlags = PmFeatureFlagsImpl()
 ) {
     if (remember(packageInfoPresenter) { packageInfoPresenter.isMainlineModule() }) return
     val presenter = remember {
@@ -53,7 +53,7 @@
 private class AppButtonsPresenter(
     private val packageInfoPresenter: PackageInfoPresenter,
     isHibernationSwitchEnabledStateFlow: MutableStateFlow<Boolean>,
-    private val featureFlags: FeatureFlags
+    private val featureFlags: PmFeatureFlags
 ) {
     private val appLaunchButton = AppLaunchButton(packageInfoPresenter)
     private val appInstallButton = AppInstallButton(packageInfoPresenter)
diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
index dba6184..695e114 100644
--- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
@@ -18,9 +18,8 @@
 
 import android.app.settings.SettingsEnums
 import android.content.pm.ApplicationInfo
-import android.content.pm.FeatureFlags
-import android.content.pm.FeatureFlagsImpl
 import android.os.Bundle
+import android.os.SystemProperties
 import android.os.UserHandle
 import android.util.FeatureFlagUtils
 import androidx.compose.runtime.Composable
@@ -51,6 +50,8 @@
 import com.android.settingslib.spaprivileged.model.app.toRoute
 import com.android.settingslib.spaprivileged.template.app.AppInfoProvider
 import kotlinx.coroutines.flow.MutableStateFlow
+import android.content.pm.FeatureFlags as PmFeatureFlags
+import android.content.pm.FeatureFlagsImpl as PmFeatureFlagsImpl
 
 private const val PACKAGE_NAME = "packageName"
 private const val USER_ID = "userId"
@@ -121,7 +122,7 @@
 @Composable
 private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
     val packageInfoState = packageInfoPresenter.flow.collectAsStateWithLifecycle()
-    val featureFlags: FeatureFlags = FeatureFlagsImpl()
+    val featureFlags: PmFeatureFlags = PmFeatureFlagsImpl()
     RegularScaffold(
         title = stringResource(R.string.application_info_label),
         actions = {
@@ -177,5 +178,6 @@
     }
 }
 
-fun isArchivingEnabled(featureFlags: FeatureFlags) =
-        featureFlags.archiving() || "true" == System.getProperty("pm.archiving.enabled")
+fun isArchivingEnabled(featureFlags: PmFeatureFlags) =
+        featureFlags.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false)
+                || Flags.appArchiving()
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt b/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
index 4f47266..86d7f44 100644
--- a/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
@@ -22,8 +22,9 @@
 import android.app.AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
 import android.content.Context
 import android.content.pm.ApplicationInfo
-import android.content.pm.Flags
+import android.content.pm.Flags as PmFlags
 import android.os.Build
+import android.os.SystemProperties
 import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM
 import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_UNKNOWN
 import android.provider.DeviceConfig
@@ -36,6 +37,7 @@
 import com.android.settings.R
 import com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED
 import com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS
+import com.android.settings.flags.Flags
 import com.android.settingslib.spa.framework.compose.OverridableFlow
 import com.android.settingslib.spa.widget.preference.SwitchPreference
 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
@@ -91,7 +93,8 @@
 }
 
 private fun isArchivingEnabled() =
-        Flags.archiving() || "true" == System.getProperty("pm.archiving.enabled")
+        PmFlags.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false)
+                || Flags.appArchiving()
 
 private class HibernationSwitchPresenter(context: Context, private val app: ApplicationInfo) {
     private val appOpsManager = context.appOpsManager
diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
index 230ccb9..81abae5 100644
--- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
+++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
@@ -20,14 +20,16 @@
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
-import android.content.pm.FeatureFlags
-import android.content.pm.FeatureFlagsImpl
+import android.content.pm.FeatureFlags as PmFeatureFlags
+import android.content.pm.FeatureFlagsImpl as PmFeatureFlagsImpl
 import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
 import android.os.UserHandle
 import android.util.Log
 import androidx.annotation.VisibleForTesting
 import androidx.compose.runtime.Composable
+import com.android.settings.flags.FeatureFlags
+import com.android.settings.flags.FeatureFlagsImpl
 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
 import com.android.settings.spa.app.startUninstallActivity
 import com.android.settingslib.spa.framework.compose.LocalNavController
@@ -60,7 +62,7 @@
     val userId: Int,
     private val coroutineScope: CoroutineScope,
     private val packageManagers: IPackageManagers = PackageManagers,
-    private val featureFlags: FeatureFlags = FeatureFlagsImpl(),
+    private val featureFlags: PmFeatureFlags = PmFeatureFlagsImpl(),
 ) {
     private val metricsFeatureProvider = featureFactory.metricsFeatureProvider
     private val userHandle = UserHandle.of(userId)
diff --git a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
index 3e48aa5..2b8d12d 100644
--- a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
+++ b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
@@ -27,7 +27,8 @@
 import androidx.compose.runtime.Composable
 import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
 import com.android.settingslib.R
-import com.android.settingslib.spa.livedata.observeAsCallback
+import com.android.settingslib.spa.lifecycle.collectAsCallbackWithLifecycle
+import com.android.settingslib.spaprivileged.model.app.AppOpsController
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 import com.android.settingslib.spaprivileged.model.app.PackageManagers
@@ -47,7 +48,7 @@
     override val app: ApplicationInfo,
     val isTrumped: Boolean,
     val isChangeable: Boolean,
-    var controller: AlarmsAndRemindersController,
+    var controller: AppOpsController,
 ) : AppRecord
 
 class AlarmsAndRemindersAppListModel(
@@ -82,7 +83,7 @@
     @Composable
     override fun isAllowed(record: AlarmsAndRemindersAppRecord): () -> Boolean? = when {
         record.isTrumped -> ({ true })
-        else -> record.controller.isAllowed.observeAsCallback()
+        else -> record.controller.isAllowed.collectAsCallbackWithLifecycle()
     }
 
     override fun isChangeable(record: AlarmsAndRemindersAppRecord) = record.isChangeable
@@ -112,7 +113,12 @@
             app = app,
             isTrumped = isTrumped,
             isChangeable = hasRequestPermission && !isTrumped,
-            controller = AlarmsAndRemindersController(context, app),
+            controller = AppOpsController(
+                context = context,
+                app = app,
+                op = AppOpsManager.OP_SCHEDULE_EXACT_ALARM,
+                setModeByUid = true,
+            ),
         )
     }
 
diff --git a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersController.kt b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersController.kt
deleted file mode 100644
index bd40f45..0000000
--- a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersController.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2022 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.spa.app.specialaccess
-
-import android.app.AppOpsManager
-import android.app.AppOpsManager.MODE_ALLOWED
-import android.app.AppOpsManager.MODE_ERRORED
-import android.content.Context
-import android.content.pm.ApplicationInfo
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import com.android.settingslib.spaprivileged.framework.common.alarmManager
-import com.android.settingslib.spaprivileged.framework.common.appOpsManager
-import com.android.settingslib.spaprivileged.model.app.userId
-
-class AlarmsAndRemindersController(
-    context: Context,
-    private val app: ApplicationInfo,
-) {
-    private val alarmManager = context.alarmManager
-    private val appOpsManager = context.appOpsManager
-
-    val isAllowed: LiveData<Boolean>
-        get() = _allowed
-
-    fun setAllowed(allowed: Boolean) {
-        val mode = if (allowed) MODE_ALLOWED else MODE_ERRORED
-        appOpsManager.setUidMode(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, app.uid, mode)
-        _allowed.postValue(allowed)
-    }
-
-    private val _allowed = object : MutableLiveData<Boolean>() {
-        override fun onActive() {
-            postValue(alarmManager.hasScheduleExactAlarm(app.packageName, app.userId))
-        }
-    }
-}
diff --git a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
index dc98330..3e9058f 100644
--- a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
+++ b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
@@ -26,7 +26,7 @@
 import android.os.UserManager
 import androidx.compose.runtime.Composable
 import com.android.settings.R
-import com.android.settingslib.spa.livedata.observeAsCallback
+import com.android.settingslib.spa.lifecycle.collectAsCallbackWithLifecycle
 import com.android.settingslib.spaprivileged.model.app.AppOpsController
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import com.android.settingslib.spaprivileged.model.app.userId
@@ -81,7 +81,7 @@
 
     @Composable
     override fun isAllowed(record: InstallUnknownAppsRecord) =
-        record.appOpsController.isAllowed.observeAsCallback()
+        record.appOpsController.isAllowed.collectAsCallbackWithLifecycle()
 
     override fun isChangeable(record: InstallUnknownAppsRecord) =
         isChangeable(record, getPotentialPackageNames(record.app.userId))
diff --git a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
index fe8f103..7885b86 100644
--- a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
+++ b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
@@ -27,7 +27,7 @@
 import android.util.Log
 import androidx.compose.runtime.Composable
 import com.android.settings.R
-import com.android.settingslib.spa.livedata.observeAsCallback
+import com.android.settingslib.spa.lifecycle.collectAsCallbackWithLifecycle
 import com.android.settingslib.spaprivileged.model.app.AppOpsController
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import com.android.settingslib.spaprivileged.model.app.installed
@@ -92,7 +92,7 @@
 
     @Composable
     override fun isAllowed(record: PictureInPictureRecord) =
-        record.appOpsController.isAllowed.observeAsCallback()
+        record.appOpsController.isAllowed.collectAsCallbackWithLifecycle()
 
     override fun isChangeable(record: PictureInPictureRecord) = record.isSupport
 
diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java
index a758e34..a030d86 100644
--- a/src/com/android/settings/users/UserDetailsSettings.java
+++ b/src/com/android/settings/users/UserDetailsSettings.java
@@ -476,9 +476,12 @@
 
     private void enableCallsAndSms(boolean enabled) {
         mPhonePref.setChecked(enabled);
-        UserHandle userHandle = UserHandle.of(mUserInfo.id);
-        mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, !enabled, userHandle);
-        mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, !enabled, userHandle);
+        int[] userProfiles = mUserManager.getProfileIdsWithDisabled(mUserInfo.id);
+        for (int userId : userProfiles) {
+            UserHandle user = UserHandle.of(userId);
+            mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, !enabled, user);
+            mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, !enabled, user);
+        }
     }
 
     /**
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/src/com/android/settings/wifi/WifiScanModeActivity.java b/src/com/android/settings/wifi/WifiScanModeActivity.java
index c10ee27..446891a 100644
--- a/src/com/android/settings/wifi/WifiScanModeActivity.java
+++ b/src/com/android/settings/wifi/WifiScanModeActivity.java
@@ -39,26 +39,24 @@
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settingslib.wifi.WifiPermissionChecker;
 
-/**
- * This activity requests users permission to allow scanning even when Wi-Fi is turned off
- */
+/** This activity requests users permission to allow scanning even when Wi-Fi is turned off */
 public class WifiScanModeActivity extends FragmentActivity {
     private static final String TAG = "WifiScanModeActivity";
     private DialogFragment mDialog;
-    @VisibleForTesting
-    String mApp;
-    @VisibleForTesting
-    WifiPermissionChecker mWifiPermissionChecker;
+    @VisibleForTesting String mApp;
+    @VisibleForTesting WifiPermissionChecker mWifiPermissionChecker;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        getWindow().addSystemFlags(
-                WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+        getWindow()
+                .addSystemFlags(
+                        WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
         Intent intent = getIntent();
         if (savedInstanceState == null) {
-            if (intent != null && WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
-                    .equals(intent.getAction())) {
+            if (intent != null
+                    && WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE.equals(
+                            intent.getAction())) {
                 refreshAppLabel();
             } else {
                 finish();
@@ -92,6 +90,12 @@
             return;
         }
 
+        if (!isWifiScanModeConfigAllowed(getApplicationContext())) {
+            Log.e(TAG, "This user is not allowed to configure Wi-Fi Scan Mode!");
+            finish();
+            return;
+        }
+
         if (mDialog == null) {
             mDialog = AlertDialogFragment.newInstance(mApp);
             mDialog.show(getSupportFragmentManager(), "dialog");
@@ -140,6 +144,7 @@
         }
 
         private final String mApp;
+
         public AlertDialogFragment(String app) {
             super();
             mApp = app;
@@ -158,25 +163,27 @@
         @Override
         public Dialog onCreateDialog(Bundle savedInstanceState) {
             return new AlertDialog.Builder(getActivity())
-                    .setMessage(TextUtils.isEmpty(mApp) ?
-                        getString(R.string.wifi_scan_always_turn_on_message_unknown) :
-                        getString(R.string.wifi_scan_always_turnon_message, mApp))
-                    .setPositiveButton(R.string.wifi_scan_always_confirm_allow,
+                    .setMessage(
+                            TextUtils.isEmpty(mApp)
+                                    ? getString(R.string.wifi_scan_always_turn_on_message_unknown)
+                                    : getString(R.string.wifi_scan_always_turnon_message, mApp))
+                    .setPositiveButton(
+                            R.string.wifi_scan_always_confirm_allow,
                             new DialogInterface.OnClickListener() {
                                 public void onClick(DialogInterface dialog, int whichButton) {
                                     ((WifiScanModeActivity) getActivity()).doPositiveClick();
                                 }
-                            }
-                    )
-                    .setNegativeButton(R.string.wifi_scan_always_confirm_deny,
+                            })
+                    .setNegativeButton(
+                            R.string.wifi_scan_always_confirm_deny,
                             new DialogInterface.OnClickListener() {
                                 public void onClick(DialogInterface dialog, int whichButton) {
                                     ((WifiScanModeActivity) getActivity()).doNegativeClick();
                                 }
-                            }
-                    )
+                            })
                     .create();
         }
+
         @Override
         public void onCancel(DialogInterface dialog) {
             ((WifiScanModeActivity) getActivity()).doNegativeClick();
@@ -184,9 +191,14 @@
     }
 
     private static boolean isGuestUser(Context context) {
-        if (context == null) return false;
         final UserManager userManager = context.getSystemService(UserManager.class);
         if (userManager == null) return false;
         return userManager.isGuestUser();
     }
+
+    private static boolean isWifiScanModeConfigAllowed(Context context) {
+        final UserManager userManager = context.getSystemService(UserManager.class);
+        if (userManager == null) return true;
+        return !userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_LOCATION);
+    }
 }
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index a90d627..82537d4 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
@@ -49,6 +50,7 @@
 import com.android.ims.ImsConfig;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.flags.Flags;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.SettingsPreferenceFragment;
@@ -97,6 +99,7 @@
     private boolean mEditableWfcMode = true;
     private boolean mEditableWfcRoamingMode = true;
     private boolean mUseWfcHomeModeForRoaming = false;
+    private boolean mOverrideWfcRoamingModeWhileUsingNtn = false;
 
     private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     private ImsMmTelManager mImsMmTelManager;
@@ -166,7 +169,8 @@
             final Preference pref_roam =
                     getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE);
             if (pref_roam != null) {
-                pref_roam.setEnabled(isWfcRoamingModeEditable);
+                pref_roam.setEnabled(isWfcRoamingModeEditable
+                        && !overrideWfcRoamingModeWhileUsingNtn());
             }
         }
     }
@@ -361,6 +365,9 @@
                         false);
                 isWifiOnlySupported = b.getBoolean(
                         CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
+                mOverrideWfcRoamingModeWhileUsingNtn = b.getBoolean(
+                        CarrierConfigManager.KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL,
+                        true);
             }
         }
 
@@ -577,7 +584,8 @@
         mButtonWfcMode.setSummary(getWfcModeSummary(wfcMode));
         mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode);
         // mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
-        mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode);
+        mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode
+                && !overrideWfcRoamingModeWhileUsingNtn());
 
         final PreferenceScreen preferenceScreen = getPreferenceScreen();
         final boolean updateAddressEnabled = (getCarrierActivityIntent() != null);
@@ -711,4 +719,30 @@
         }
         mProvisioningManager.unregisterProvisioningChangedCallback(mProvisioningCallback);
     }
+
+    /**
+     * Determine whether to override roaming Wi-Fi calling preference when device is connected to
+     * non-terrestrial network.
+     *
+     * @return {@code true} if phone is connected to non-terrestrial network and if
+     * {@link CarrierConfigManager#KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL} is true,
+     * {@code false} otherwise.
+     */
+    private boolean overrideWfcRoamingModeWhileUsingNtn() {
+        if (!Flags.carrierEnabledSatelliteFlag()) {
+            return false;
+        }
+
+        TelephonyManager tm = getTelephonyManagerForSub(mSubId);
+        ServiceState serviceState = tm.getServiceState();
+        if (serviceState == null) {
+            return false;
+        }
+
+        if (!serviceState.isUsingNonTerrestrialNetwork()) {
+            return false;
+        }
+
+        return mOverrideWfcRoamingModeWhileUsingNtn;
+    }
 }
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/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
index 00115d7..cd48bf1 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
@@ -20,6 +20,8 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -28,18 +30,26 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.Pair;
 
 import com.android.settings.connecteddevice.DevicePreferenceCallback;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.flags.Flags;
 import com.android.settings.testutils.shadow.ShadowAudioManager;
 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
 import com.android.settings.testutils.shadow.ShadowCachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -58,6 +68,10 @@
 public class ConnectedBluetoothDeviceUpdaterTest {
 
     private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
+    private static final String FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name";
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Mock
     private DashboardFragment mDashboardFragment;
@@ -69,6 +83,8 @@
     private BluetoothDevice mBluetoothDevice;
     @Mock
     private Drawable mDrawable;
+    @Mock
+    private PackageManager mPackageManager;
 
     private Context mContext;
     private ConnectedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
@@ -82,7 +98,7 @@
         MockitoAnnotations.initMocks(this);
 
         Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
         mAudioManager = mContext.getSystemService(AudioManager.class);
         mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
         mShadowBluetoothAdapter.setEnabled(true);
@@ -92,6 +108,7 @@
         mCachedDevices = new ArrayList<>();
         mCachedDevices.add(mCachedBluetoothDevice);
 
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
         when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
@@ -320,4 +337,97 @@
 
         assertThat(btPreference.shouldHideSecondTarget()).isTrue();
     }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_notExclusiveManagedDevice_addDevice() {
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                null);
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_notAllowedExclusiveManagedDevice_addDevice() {
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                FAKE_EXCLUSIVE_MANAGER_NAME.getBytes());
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_existingExclusivelyManagedDeviceWithPackageInstalled_removePreference()
+            throws Exception {
+        final String exclusiveManagerName =
+                BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+                        FAKE_EXCLUSIVE_MANAGER_NAME);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                exclusiveManagerName.getBytes());
+        doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+        verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_newExclusivelyManagedDeviceWithPackageInstalled_doNotAddPreference()
+            throws Exception {
+        final String exclusiveManagerName =
+                BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+                        FAKE_EXCLUSIVE_MANAGER_NAME);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                exclusiveManagerName.getBytes());
+        doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+        verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_exclusivelyManagedDeviceWithoutPackageInstalled_addDevice()
+            throws Exception {
+        final String exclusiveManagerName =
+                BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+                        FAKE_EXCLUSIVE_MANAGER_NAME);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                exclusiveManagerName.getBytes());
+        doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo(
+                exclusiveManagerName, 0);
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java
index c229449..349391d 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java
@@ -18,6 +18,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -28,17 +29,26 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.Pair;
 
 import com.android.settings.connecteddevice.DevicePreferenceCallback;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.flags.Flags;
 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -56,6 +66,10 @@
 public class SavedBluetoothDeviceUpdaterTest {
 
     private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
+    private static final String FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name";
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Mock
     private DashboardFragment mDashboardFragment;
@@ -73,6 +87,8 @@
     private LocalBluetoothManager mBluetoothManager;
     @Mock
     private Drawable mDrawable;
+    @Mock
+    private PackageManager mPackageManager;
 
     private Context mContext;
     private SavedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
@@ -84,12 +100,13 @@
         MockitoAnnotations.initMocks(this);
 
         Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
         doReturn(mContext).when(mDashboardFragment).getContext();
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
         when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
 
         mBluetoothDeviceUpdater = spy(new SavedBluetoothDeviceUpdater(mContext,
                 mDevicePreferenceCallback, false, /* metricsCategory= */ 0));
@@ -103,10 +120,10 @@
         mCachedDevices.add(mCachedBluetoothDevice);
         when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
         when(mDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices);
-
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     public void update_filterMatch_addPreference() {
         doReturn(BluetoothDevice.BOND_BONDED).when(mBluetoothDevice).getBondState();
         doReturn(false).when(mBluetoothDevice).isConnected();
@@ -118,6 +135,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     public void update_filterNotMatch_removePreference() {
         doReturn(BluetoothDevice.BOND_NONE).when(mBluetoothDevice).getBondState();
         doReturn(true).when(mBluetoothDevice).isConnected();
@@ -298,4 +316,125 @@
         verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice,
                 BluetoothDevicePreference.SortType.TYPE_NO_SORT);
     }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_notExclusivelyManagedDevice_addDevice() {
+        final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+        cachedDevices.add(mCachedBluetoothDevice);
+
+        when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+        when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+        when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mBluetoothDevice.isConnected()).thenReturn(false);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                null);
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
+                BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_notAllowedExclusivelyManagedDevice_addDevice() {
+        final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+        cachedDevices.add(mCachedBluetoothDevice);
+
+        when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+        when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+        when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mBluetoothDevice.isConnected()).thenReturn(false);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                FAKE_EXCLUSIVE_MANAGER_NAME.getBytes());
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
+                BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_existingExclusivelyManagedDeviceWithPackageInstalled_removePreference()
+            throws Exception {
+        final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+        final String exclusiveManagerName =
+                BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+                        FAKE_EXCLUSIVE_MANAGER_NAME);
+
+        when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+        when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+        when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mBluetoothDevice.isConnected()).thenReturn(false);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                exclusiveManagerName.getBytes());
+
+        doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
+        mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+        verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice,
+                BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_newExclusivelyManagedDeviceWithPackageInstalled_doNotAddPreference()
+            throws Exception {
+        final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+        final String exclusiveManagerName =
+                BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+                        FAKE_EXCLUSIVE_MANAGER_NAME);
+        cachedDevices.add(mCachedBluetoothDevice);
+
+        when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+        when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+        when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mBluetoothDevice.isConnected()).thenReturn(false);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                exclusiveManagerName.getBytes());
+
+        doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+        verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice,
+                BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    public void update_exclusivelyManagedDeviceWithoutPackageInstalled_addDevice()
+            throws Exception {
+        final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+        final String exclusiveManagerName =
+                BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+                        FAKE_EXCLUSIVE_MANAGER_NAME);
+        cachedDevices.add(mCachedBluetoothDevice);
+
+        when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+        when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+        when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mBluetoothDevice.isConnected()).thenReturn(false);
+        when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+                exclusiveManagerName.getBytes());
+
+        doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo(
+                exclusiveManagerName, 0);
+
+        mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+        verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
+                BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceControllerTest.java
index aa10517..4cdd364 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceControllerTest.java
@@ -171,6 +171,7 @@
         mShadowBluetoothAdapter.setEnabled(false);
         mController.displayPreference(mScreen);
         mController.updateVisibility();
+        shadowOf(Looper.getMainLooper()).idle();
         assertThat(mPreference.isVisible()).isFalse();
     }
 
@@ -180,6 +181,7 @@
         mShadowBluetoothAdapter.setEnabled(false);
         mController.displayPreference(mScreen);
         mController.updateVisibility();
+        shadowOf(Looper.getMainLooper()).idle();
         assertThat(mPreference.isVisible()).isFalse();
     }
 
@@ -188,6 +190,7 @@
         when(mBroadcast.isEnabled(any())).thenReturn(false);
         mController.displayPreference(mScreen);
         mController.updateVisibility();
+        shadowOf(Looper.getMainLooper()).idle();
         assertThat(mPreference.isVisible()).isFalse();
     }
 
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/BatteryTipPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
index eeedccc..c05d9ed 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
@@ -20,30 +20,29 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.os.Bundle;
-import android.text.format.DateUtils;
 
 import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.SettingsActivity;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.InstrumentedPreferenceFragment;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
-import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.widget.CardPreference;
 
 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 java.util.ArrayList;
 import java.util.List;
@@ -53,8 +52,8 @@
 
     private static final String KEY_PREF = "battery_tip";
     private static final String KEY_TIP = "key_battery_tip";
-    private static final long AVERAGE_TIME_MS = DateUtils.HOUR_IN_MILLIS;
 
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
     @Mock private BatteryTipPreferenceController.BatteryTipListener mBatteryTipListener;
     @Mock private PreferenceScreen mPreferenceScreen;
     @Mock private BatteryTip mBatteryTip;
@@ -64,21 +63,16 @@
     private Context mContext;
     private CardPreference mCardPreference;
     private BatteryTipPreferenceController mBatteryTipPreferenceController;
-    private List<BatteryTip> mOldBatteryTips;
     private List<BatteryTip> mNewBatteryTips;
-    private FakeFeatureFactory mFeatureFactory;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = ApplicationProvider.getApplicationContext();
 
-        mCardPreference = spy(new CardPreference(mContext));
+        mCardPreference = new CardPreference(mContext);
         when(mPreferenceScreen.getContext()).thenReturn(mContext);
         doReturn(mCardPreference).when(mPreferenceScreen).findPreference(KEY_PREF);
-        mFeatureFactory = FakeFeatureFactory.setupForTest();
 
-        mOldBatteryTips = new ArrayList<>();
         mNewBatteryTips = new ArrayList<>();
 
         mBatteryTipPreferenceController = buildBatteryTipPreferenceController();
@@ -87,32 +81,32 @@
     }
 
     @Test
-    public void testDisplayPreference_isInvisible() {
+    public void displayPreference_isInvisible() {
         mBatteryTipPreferenceController.displayPreference(mPreferenceScreen);
 
         assertThat(mCardPreference.isVisible()).isFalse();
     }
 
     @Test
-    public void testUpdateBatteryTips_tipsStateInvisible_isInvisible() {
+    public void updateBatteryTips_tipsStateInvisible_isInvisible() {
         mBatteryTipPreferenceController.updateBatteryTips(mNewBatteryTips);
 
         assertThat(mCardPreference.isVisible()).isFalse();
     }
 
     @Test
-    public void testGetCurrentBatteryTip_noTips_isNull() {
+    public void getCurrentBatteryTip_noTips_isNull() {
         assertThat(mBatteryTipPreferenceController.getCurrentBatteryTip()).isNull();
     }
 
     @Test
-    public void testGetCurrentBatteryTip_tipsInvisible_isNull() {
+    public void getCurrentBatteryTip_tipsInvisible_isNull() {
         mBatteryTipPreferenceController.updateBatteryTips(mNewBatteryTips);
         assertThat(mBatteryTipPreferenceController.getCurrentBatteryTip()).isNull();
     }
 
     @Test
-    public void testRestoreFromNull_shouldNotCrash() {
+    public void restoreFromNull_shouldNotCrash() {
         final Bundle bundle = new Bundle();
         // Battery tip list is null at this time
         mBatteryTipPreferenceController.saveInstanceState(bundle);
@@ -124,7 +118,7 @@
     }
 
     @Test
-    public void testHandlePreferenceTreeClick_noDialog_invokeCallback() {
+    public void handlePreferenceTreeClick_noDialog_invokeCallback() {
         when(mBatteryTip.getType()).thenReturn(SMART_BATTERY_MANAGER);
         List<BatteryTip> batteryTips = new ArrayList<>();
         batteryTips.add(mBatteryTip);
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..4efd850 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
@@ -17,8 +17,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -27,6 +25,7 @@
 import android.util.Log;
 
 import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
 import com.android.settings.testutils.FakeFeatureFactory;
@@ -34,12 +33,13 @@
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 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.shadows.ShadowLog;
 
 @RunWith(RobolectricTestRunner.class)
@@ -49,23 +49,22 @@
     private FakeFeatureFactory mFeatureFactory;
     private BatteryDefenderTip mBatteryDefenderTip;
     private MetricsFeatureProvider mMetricsFeatureProvider;
+    private CardPreference mCardPreference;
 
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
     @Mock private BatteryTip mBatteryTip;
     @Mock private Preference mPreference;
-    @Mock private CardPreference mCardPreference;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
+        mContext = ApplicationProvider.getApplicationContext();
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
-        mContext = RuntimeEnvironment.application;
         mBatteryDefenderTip =
-                new BatteryDefenderTip(BatteryTip.StateType.NEW, false /* isPluggedIn */);
+                new BatteryDefenderTip(BatteryTip.StateType.NEW, /* isPluggedIn= */ false);
+        mCardPreference = new CardPreference(mContext);
 
         when(mPreference.getContext()).thenReturn(mContext);
-        when(mCardPreference.getContext()).thenReturn(mContext);
     }
 
     @Test
@@ -87,7 +86,7 @@
     }
 
     @Test
-    public void testLog_logMetric() {
+    public void log_logMetric() {
         mBatteryDefenderTip.updateState(mBatteryTip);
         mBatteryDefenderTip.log(mContext, mMetricsFeatureProvider);
 
@@ -108,7 +107,7 @@
 
         mBatteryDefenderTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setPrimaryButtonText(expectedText);
+        assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo(expectedText);
     }
 
     @Test
@@ -117,46 +116,31 @@
 
         mBatteryDefenderTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setSecondaryButtonText(expected);
+        assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo(expected);
     }
 
     @Test
     public void updatePreference_shouldSetPrimaryButtonVisible() {
         mBatteryDefenderTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setPrimaryButtonVisible(true);
+        assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
     }
 
     @Test
     public void updatePreference_whenCharging_setPrimaryButtonVisibleToBeTrue() {
         mBatteryDefenderTip =
-                new BatteryDefenderTip(BatteryTip.StateType.NEW, true /* isPluggedIn */);
+                new BatteryDefenderTip(BatteryTip.StateType.NEW, /* isPluggedIn= */ true);
 
         mBatteryDefenderTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setPrimaryButtonVisible(true);
+        assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
     }
 
     @Test
     public void updatePreference_whenNotCharging_setSecondaryButtonVisibleToBeFalse() {
         mBatteryDefenderTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setSecondaryButtonVisible(false);
-    }
-
-    @Test
-    public void updatePreference_whenGetChargingStatusFailed_setSecondaryButtonVisibleToBeFalse() {
-        fakeGetChargingStatusFailed();
-
-        mBatteryDefenderTip.updatePreference(mCardPreference);
-
-        verify(mCardPreference).setSecondaryButtonVisible(false);
-    }
-
-    private void fakeGetChargingStatusFailed() {
-        Context mockContext = mock(Context.class);
-        when(mockContext.getString(anyInt())).thenReturn("fake_string");
-        when(mCardPreference.getContext()).thenReturn(mockContext);
+        assertThat(mCardPreference.getSecondaryButtonVisibility()).isFalse();
     }
 
     private String getLastErrorLog() {
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..097f484 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
@@ -20,11 +20,10 @@
 import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.view.View;
 
 import androidx.annotation.DrawableRes;
 import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
+import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
 import com.android.settings.widget.CardPreference;
@@ -32,10 +31,12 @@
 import com.android.settingslib.testutils.DrawableTestHelper;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -47,13 +48,15 @@
     private static final String SUMMARY = "summary";
     @DrawableRes private static final int ICON_ID = R.drawable.ic_fingerprint;
 
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
     private Context mContext;
     private TestBatteryTip mBatteryTip;
 
     @Before
     public void setUp() {
-        mContext = RuntimeEnvironment.application;
         mBatteryTip = new TestBatteryTip();
+        mContext = ApplicationProvider.getApplicationContext();
     }
 
     @Test
@@ -84,19 +87,14 @@
 
     @Test
     public void updatePreference_resetLayoutState() {
-        mContext.setTheme(R.style.Theme_Settings);
-        PreferenceViewHolder holder =
-                PreferenceViewHolder.createInstanceForTests(
-                        View.inflate(
-                                mContext, R.layout.card_preference_layout, /* parent= */ null));
         CardPreference cardPreference = new CardPreference(mContext);
-        cardPreference.onBindViewHolder(holder);
-        cardPreference.setPrimaryButtonVisible(true);
+        cardPreference.setPrimaryButtonVisibility(true);
+        cardPreference.setSecondaryButtonVisibility(true);
 
         mBatteryTip.updatePreference(cardPreference);
 
-        View view = holder.findViewById(R.id.card_preference_buttons);
-        assertThat(view.getVisibility()).isEqualTo(View.GONE);
+        assertThat(cardPreference.getPrimaryButtonVisibility()).isFalse();
+        assertThat(cardPreference.getSecondaryButtonVisibility()).isFalse();
     }
 
     @Test
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..7a23332 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
@@ -25,6 +25,7 @@
 import android.util.Log;
 
 import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
 import com.android.settings.testutils.FakeFeatureFactory;
@@ -32,12 +33,13 @@
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
 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.shadows.ShadowLog;
 
 @RunWith(RobolectricTestRunner.class)
@@ -47,22 +49,21 @@
     private FakeFeatureFactory mFeatureFactory;
     private IncompatibleChargerTip mIncompatibleChargerTip;
     private MetricsFeatureProvider mMetricsFeatureProvider;
+    private CardPreference mCardPreference;
 
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
     @Mock private BatteryTip mBatteryTip;
     @Mock private Preference mPreference;
-    @Mock private CardPreference mCardPreference;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
-        mContext = RuntimeEnvironment.application;
+        mContext = ApplicationProvider.getApplicationContext();
         mIncompatibleChargerTip = new IncompatibleChargerTip(BatteryTip.StateType.NEW);
+        mCardPreference = new CardPreference(mContext);
 
         when(mPreference.getContext()).thenReturn(mContext);
-        when(mCardPreference.getContext()).thenReturn(mContext);
     }
 
     @Test
@@ -107,13 +108,13 @@
 
         mIncompatibleChargerTip.updatePreference(mCardPreference);
 
-        verify(mCardPreference).setPrimaryButtonText(expected);
+        assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo(expected);
     }
 
     @Test
     public void updatePreference_shouldSetSecondaryButtonVisible() {
         mIncompatibleChargerTip.updatePreference(mCardPreference);
-        verify(mCardPreference).setPrimaryButtonVisible(true);
+        assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
     }
 
     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/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
index 2e6189e..4497a0a 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
@@ -40,7 +40,10 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.PersistableBundle;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.telephony.CarrierConfigManager;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.view.View;
@@ -48,6 +51,7 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
+import com.android.internal.telephony.flags.Flags;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.network.ims.MockWifiCallingQueryImsState;
@@ -57,6 +61,7 @@
 import com.android.settings.widget.SettingsMainSwitchPreference;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -70,6 +75,7 @@
 @Config(shadows = ShadowFragment.class)
 @RunWith(RobolectricTestRunner.class)
 public class WifiCallingSettingsForSubTest {
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
     private static final int SUB_ID = 2;
 
     private static final String SWITCH_BAR = "wifi_calling_switch_bar";
@@ -158,6 +164,7 @@
         mFragment.onAttach(mContext);
         mFragment.onCreate(null);
         mFragment.onActivityCreated(null);
+        mSetFlagsRule.disableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG);
     }
 
     private void setDefaultCarrierConfigValues() {
@@ -241,6 +248,31 @@
     }
 
     @Test
+    public void onResume_overrideWfcRoamingModeWhileUsingNTN_shouldDisableWfcRoaming() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG);
+        mBundle.putBoolean(
+                CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
+        mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
+        mBundle.putBoolean(
+                CarrierConfigManager.KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL, true);
+
+        // Phone connected to non-terrestrial network
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setIsNonTerrestrialNetwork(true)
+                .build();
+        ServiceState ss = new ServiceState();
+        ss.addNetworkRegistrationInfo(nri);
+        doReturn(ss).when(mTelephonyManager).getServiceState();
+
+        // Call onResume to update the WFC roaming preference.
+        mFragment.onResume();
+
+        // Check that WFC roaming preference is visible but disabled
+        verify(mButtonWfcRoamingMode, times(1)).setEnabled(false);
+        verify(mButtonWfcRoamingMode, times(1)).setVisible(true);
+    }
+
+    @Test
     public void onResume_useWfcHomeModeConfigTrueAndNotEditable_shouldHideWfcRoaming() {
         mBundle.putBoolean(
                 CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, true);
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
index 74aa861..537764a 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
@@ -21,7 +21,6 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.lifecycle.MutableLiveData
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
@@ -270,7 +269,7 @@
 private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController {
     var setAllowedCalledWith: Boolean? = null
 
-    override val mode = MutableLiveData(fakeMode)
+    override val mode = flowOf(fakeMode)
 
     override fun setAllowed(allowed: Boolean) {
         setAllowedCalledWith = allowed
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
index cc2c1e1..b61e3a9 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
@@ -24,8 +24,9 @@
 import android.apphibernation.AppHibernationManager
 import android.content.Context
 import android.content.pm.ApplicationInfo
-import android.content.pm.Flags
+import android.content.pm.Flags as PmFlags
 import android.os.Build
+import android.os.SystemProperties
 import android.permission.PermissionControllerManager
 import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_ELIGIBLE
 import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM
@@ -48,6 +49,7 @@
 import com.android.settings.R
 import com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED
 import com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS
+import com.android.settings.flags.Flags
 import com.android.settings.testutils.TestDeviceConfig
 import com.android.settings.testutils.mockAsUser
 import com.android.settingslib.spaprivileged.framework.common.appHibernationManager
@@ -161,8 +163,8 @@
     }
 
     private fun isArchivingEnabled() =
-            Flags.archiving() || "true" == System.getProperty("pm.archiving.enabled")
-
+            PmFlags.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false)
+                    || Flags.appArchiving()
     @Test
     fun `An app targets Q with ops mode default when hibernation targets pre S - not exempted`() {
         mockOpsMode(MODE_DEFAULT)
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/MediaRoutingControlTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/MediaRoutingControlTest.kt
index 2f4740e..990ec5c 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/MediaRoutingControlTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/MediaRoutingControlTest.kt
@@ -24,7 +24,6 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.platform.test.flag.junit.SetFlagsRule
-import androidx.lifecycle.MutableLiveData
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.media.flags.Flags
@@ -33,6 +32,7 @@
 import com.android.settingslib.spaprivileged.model.app.IAppOpsController
 import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -223,16 +223,13 @@
 
     private class FakeAppOpsController(fakeMode: Int) : IAppOpsController {
 
-        override val mode = MutableLiveData(fakeMode)
+        override val mode = MutableStateFlow(fakeMode)
 
         override fun setAllowed(allowed: Boolean) {
-            if (allowed)
-                mode.postValue(AppOpsManager.MODE_ALLOWED)
-            else
-                mode.postValue(AppOpsManager.MODE_ERRORED)
+            mode.value = if (allowed) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_ERRORED
         }
 
-        override fun getMode(): Int = mode.value!!
+        override fun getMode(): Int = mode.value
     }
 
     companion object {
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 =
diff --git a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
index f6356bc..71d419e 100644
--- a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
@@ -114,7 +114,7 @@
 
     @Test
     public void setSafetySourceData_whenSafetyCenterIsEnabled_withoutBiometrics_setsNullData() {
-        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
+        when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
         when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
         when(mFaceManager.isHardwareDetected()).thenReturn(false);
 
diff --git a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
index 3538727..e528c4e 100644
--- a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
@@ -413,6 +413,8 @@
         when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
         when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
                 .thenReturn(false);
+        when(mScreenLockPreferenceDetailsUtils.isLockPatternSecure()).thenReturn(true);
+        when(mScreenLockPreferenceDetailsUtils.shouldShowGearMenu()).thenReturn(true);
 
         LockScreenSafetySource.setSafetySourceData(
                 mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
diff --git a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java
index 9851a1a..31f7878 100644
--- a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java
+++ b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java
@@ -107,7 +107,7 @@
 
     @Test
     public void whenSafetyCenterIsEnabled_pageIndexExcluded() throws Exception {
-        when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(false);
+        when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(true);
         BaseSearchIndexProvider indexProvider = SecurityAdvancedSettings.SEARCH_INDEX_DATA_PROVIDER;
 
         List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);