Merge "Add ethernet interface details settings subpage" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index de54b83..47d3360 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -5538,10 +5538,14 @@
         </service>
 
         <receiver android:name="com.android.settings.connecteddevice.audiosharing.AudioSharingReceiver"
-            android:exported="true">
+            android:permission="android.permission.BLUETOOTH_PRIVILEGED"
+            android:exported="true"> <!-- Exported for SystemUI. -->
             <intent-filter>
                 <action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STATE_CHANGE" />
                 <action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STOP" />
+                <action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_DEVICE_CONNECTED" />
+                <action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_ADD_SOURCE" />
+                <action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_CANCEL_NOTIF" />
             </intent-filter>
         </receiver>
 
diff --git a/aconfig/settings_communal_flag_declarations.aconfig b/aconfig/settings_communal_flag_declarations.aconfig
index 3d3a805..fff8f49 100644
--- a/aconfig/settings_communal_flag_declarations.aconfig
+++ b/aconfig/settings_communal_flag_declarations.aconfig
@@ -1,5 +1,5 @@
 package: "com.android.settings.flags"
-container: "system"
+container: "system_ext"
 
 flag {
   name: "enable_hub_mode_settings_on_mobile"
diff --git a/res/color/color_battery_anomaly_app_warning_selector.xml b/res/color/color_battery_anomaly_app_warning_selector.xml
deleted file mode 100644
index 4ad78e6..0000000
--- a/res/color/color_battery_anomaly_app_warning_selector.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/power_anomaly_app_warning_hint_color"/>
-</selector>
diff --git a/res/drawable/ic_battery_tips_warning_icon.xml b/res/drawable/ic_battery_tips_warning_icon.xml
index 0dcfa6d..1555930 100644
--- a/res/drawable/ic_battery_tips_warning_icon.xml
+++ b/res/drawable/ic_battery_tips_warning_icon.xml
@@ -20,6 +20,6 @@
     android:viewportWidth="960"
     android:viewportHeight="960">
     <path
-        android:fillColor="@color/color_battery_anomaly_app_warning_selector"
+        android:fillColor="@color/settingslib_colorBackgroundLevel_medium"
         android:pathData="M40,840L480,80L920,840L40,840ZM178,760L782,760L480,240L178,760ZM480,720Q497,720 508.5,708.5Q520,697 520,680Q520,663 508.5,651.5Q497,640 480,640Q463,640 451.5,651.5Q440,663 440,680Q440,697 451.5,708.5Q463,720 480,720ZM440,600L520,600L520,400L440,400L440,600ZM480,500L480,500L480,500L480,500Z"/>
 </vector>
\ No newline at end of file
diff --git a/res/layout/wifi_network_config.xml b/res/layout/wifi_network_config.xml
index dbd3e67..d3680b1 100644
--- a/res/layout/wifi_network_config.xml
+++ b/res/layout/wifi_network_config.xml
@@ -16,11 +16,13 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/l_wifidialog"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical"
-    android:paddingBottom="8dip">
+    android:paddingBottom="8dip"
+    android:theme="@style/Theme.AppCompat.DayNight">
 
     <LinearLayout android:id="@+id/wep_warning_layout"
         android:layout_width="match_parent"
@@ -50,30 +52,34 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             style="@style/wifi_item">
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                style="@style/wifi_item_label"
-                android:text="@string/wifi_ssid"
-                android:textDirection="locale"/>
-
             <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="horizontal">
-                <EditText android:id="@+id/ssid"
-                          android:layout_width="0dp"
-                          android:layout_height="wrap_content"
-                          android:layout_weight="1"
-                          style="@style/wifi_item_edit_content"
-                          android:hint="@string/wifi_ssid_hint"
-                          android:singleLine="true"
-                          android:inputType="textNoSuggestions"/>
+                <com.google.android.material.textfield.TextInputLayout
+                    android:id="@+id/ssid_layout"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:hint="@string/wifi_ssid"
+                    android:theme="@style/Theme.Settings"
+                    android:textDirection="locale"
+                    app:endIconMode="clear_text"
+                    app:errorEnabled="true">
+
+                    <com.google.android.material.textfield.TextInputEditText
+                        android:id="@+id/ssid"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:inputType="textNoSuggestions"
+                        android:singleLine="true"/>
+                </com.google.android.material.textfield.TextInputLayout>
 
                 <ImageButton
                     android:id="@+id/ssid_scanner_button"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
+                    android:layout_gravity="center"
                     android:minWidth="@dimen/min_tap_target_size"
                     android:minHeight="@dimen/min_tap_target_size"
                     android:background="?android:attr/selectableItemBackground"
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index c767f04..212f1a6 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -55,9 +55,6 @@
     <!-- Icon tint color for battery usage system icon -->
     <color name="battery_usage_system_icon_color">@android:color/white</color>
 
-    <!-- Power anomaly color for icons, button and text -->
-    <color name="power_anomaly_app_warning_hint_color">#FDD663</color>
-
     <!-- UDFPS colors -->
     <color name="udfps_enroll_icon">#7DA7F1</color>
     <color name="udfps_moving_target_fill">#475670</color>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 5de6222..e653c63 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1459,11 +1459,6 @@
         <item>ic_battery_tips_warning_icon</item>
     </string-array>
 
-    <string-array name="battery_tips_card_colors" translatable="false">
-        <item>color_accent_selector</item>
-        <item>color_battery_anomaly_app_warning_selector</item>
-    </string-array>
-
     <!-- The following 4 arrays are for power anomaly tips card. Please keep them the same size. -->
     <string-array name="power_anomaly_title_ids" translatable="false">
         <item>battery_tips_settings_summary_brightness</item>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 7c4dd42..08818a9 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -168,9 +168,6 @@
     <!-- Icon tint color for battery usage system icon -->
     <color name="battery_usage_system_icon_color">?android:attr/textColorPrimary</color>
 
-    <!-- Power anomaly color for icons, button -->
-    <color name="power_anomaly_app_warning_hint_color">#D56E0C</color>
-
     <!-- UDFPS colors -->
     <!-- colorPrimaryGoogle light #1A73E8 (Blue600)-->
     <color name="udfps_enroll_icon">#1A73E8</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 95b789da..9ded9ad 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10798,7 +10798,7 @@
     <string name="apps_summary"><xliff:g id="count" example="24">%1$d</xliff:g> apps installed</string>
 
     <!-- Summary of storage usage [CHAR LIMIT=NONE] -->
-    <string name="storage_summary"><xliff:g id="percentage" example="54%">%1$s</xliff:g> used - <xliff:g id="free_space" example="32GB">%2$s</xliff:g> free</string>
+    <string name="storage_summary"><xliff:g id="percentage" example="54%">%1$s</xliff:g> used - <xliff:g id="free_space_value" example="32">%2$s</xliff:g> <xliff:g id="free_space_units" example="GB">%3$s</xliff:g> free</string>
 
     <!-- Summary for Display settings, explaining a few important settings under it [CHAR LIMIT=NONE]-->
     <string name="display_dashboard_summary">Dark theme, font size, brightness</string>
@@ -14057,6 +14057,8 @@
     <string name="audio_sharing_block_pairing_dialog_content">To pair a new device, turn off Audio Sharing first.</string>
     <!-- Text for audio sharing turn off button [CHAR LIMIT=none]-->
     <string name="audio_sharing_turn_off_button_label">Turn off</string>
+    <!-- Title for audio sharing notification to share audio with headset [CHAR LIMIT=none]-->
+    <string name="share_audio_notification_title">Share audio with <xliff:g example="My buds" id="device_name">%1$s</xliff:g></string>
 
     <!-- Title for audio streams preference category [CHAR LIMIT=none]-->
     <string name="audio_streams_category_title">Connect to a LE audio stream</string>
diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml
index 4f7a494..ce71f54 100644
--- a/res/xml/mobile_network_settings.xml
+++ b/res/xml/mobile_network_settings.xml
@@ -204,7 +204,7 @@
 
         <PreferenceCategory
             android:key="telephony_satellite_settings_category_key"
-            android:title="@string/satellite_setting_title"
+            android:title="@string/category_title_satellite_connectivity"
             settings:controller="com.android.settings.network.telephony.SatelliteSettingsPreferenceCategoryController">
 
             <com.android.settingslib.RestrictedPreference
diff --git a/res/xml/power_usage_advanced.xml b/res/xml/power_usage_advanced.xml
index 3258b7b..cc37625 100644
--- a/res/xml/power_usage_advanced.xml
+++ b/res/xml/power_usage_advanced.xml
@@ -21,18 +21,11 @@
     android:title="@string/advanced_battery_title"
     settings:keywords="@string/keywords_battery_usage">
 
-    <PreferenceCategory
-        android:key="battery_tips_category"
-        android:layout="@layout/preference_category_no_label"
+    <com.android.settingslib.widget.BannerMessagePreference
+        android:key="battery_tips_card"
         settings:controller=
             "com.android.settings.fuelgauge.batteryusage.BatteryTipsController"
-        settings:isPreferenceVisible="false">
-
-        <com.android.settings.widget.TipCardPreference
-            android:key="battery_tips_card"
-            settings:isPreferenceVisible="false" />
-
-    </PreferenceCategory>
+        settings:isPreferenceVisible="false" />
 
     <com.android.settings.fuelgauge.batteryusage.BatteryHistoryPreference
         android:key="battery_chart"
diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index f272c1d..77c39cd 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -50,12 +50,14 @@
 import com.android.settings.core.InstrumentedPreferenceFragment;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settings.flags.Flags;
+import com.android.settings.restriction.UserRestrictionBindingHelper;
 import com.android.settings.support.actionbar.HelpResourceProvider;
 import com.android.settings.widget.HighlightablePreferenceGroupAdapter;
 import com.android.settings.widget.LoadingViewController;
 import com.android.settingslib.CustomDialogPreferenceCompat;
 import com.android.settingslib.CustomEditTextPreferenceCompat;
 import com.android.settingslib.core.instrumentation.Instrumentable;
+import com.android.settingslib.preference.PreferenceScreenBindingHelper;
 import com.android.settingslib.preference.PreferenceScreenCreator;
 import com.android.settingslib.search.Indexable;
 import com.android.settingslib.widget.LayoutPreference;
@@ -130,6 +132,8 @@
     public HighlightablePreferenceGroupAdapter mAdapter;
     private boolean mPreferenceHighlighted = false;
 
+    private @Nullable UserRestrictionBindingHelper mUserRestrictionBindingHelper;
+
     @Override
     public void onAttach(Context context) {
         if (shouldSkipForInitialSUW() && !WizardManagerHelper.isDeviceProvisioned(getContext())) {
@@ -148,6 +152,14 @@
             mPreferenceHighlighted = icicle.getBoolean(SAVE_HIGHLIGHTED_KEY);
         }
         HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(this /* host */);
+
+        if (isCatalystEnabled()) {
+            PreferenceScreenBindingHelper helper = getPreferenceScreenBindingHelper();
+            if (helper != null) {
+                mUserRestrictionBindingHelper = new UserRestrictionBindingHelper(requireContext(),
+                        helper);
+            }
+        }
     }
 
     @Override
@@ -501,6 +513,15 @@
     }
 
     @Override
+    public void onDestroy() {
+        if (mUserRestrictionBindingHelper != null) {
+            mUserRestrictionBindingHelper.close();
+            mUserRestrictionBindingHelper = null;
+        }
+        super.onDestroy();
+    }
+
+    @Override
     public void onDetach() {
         if (isRemoving()) {
             if (mDialogFragment != null) {
diff --git a/src/com/android/settings/accessibility/AccessibilityDialogUtils.java b/src/com/android/settings/accessibility/AccessibilityDialogUtils.java
index a1f59c8..c89b8d7 100644
--- a/src/com/android/settings/accessibility/AccessibilityDialogUtils.java
+++ b/src/com/android/settings/accessibility/AccessibilityDialogUtils.java
@@ -24,6 +24,7 @@
 import android.view.View;
 import android.widget.AbsListView;
 import android.widget.AdapterView;
+import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.ScrollView;
 
@@ -34,14 +35,15 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * Utility class for creating the edit dialog.
  */
 public class AccessibilityDialogUtils {
-    private static final String TAG = "AccessibilityDialogUtils";
+    private static final String TAG = AccessibilityDialogUtils.class.getSimpleName();
 
-    /** Denotes the dialog emuns for show dialog. */
+    /** Denotes the dialog enums for show dialog. */
     @Retention(RetentionPolicy.SOURCE)
     public @interface DialogEnums {
         /**
@@ -89,6 +91,19 @@
          * OPEN: Settings > Accessibility > Display size and text > Click 'Reset settings' button.
          */
         int DIALOG_RESET_SETTINGS = 1009;
+
+        /**
+         * OPEN: Settings > Accessibility > Magnification > Magnification type.
+         */
+        int DIALOG_MAGNIFICATION_MODE = 1010;
+
+        /**
+         * Enable: Settings > Accessibility > Magnification > Magnification shortcut > Advanced >
+         * Triple tap.
+         * OPEN: Settings > Accessibility > Magnification > Magnification type > Magnify part of
+         * screen / Switch between full and partial screen > Save.
+         */
+        int DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING = 1011;
     }
 
     /**
@@ -118,17 +133,26 @@
      *                         is clicked
      * @return the {@link Dialog} with the given view
      */
-    public static Dialog createCustomDialog(Context context, CharSequence dialogTitle,
-            View customView, CharSequence positiveButtonText,
-            DialogInterface.OnClickListener positiveListener, CharSequence negativeButtonText,
-            DialogInterface.OnClickListener negativeListener) {
-        final AlertDialog alertDialog = new AlertDialog.Builder(context)
-                .setView(customView)
+    @NonNull
+    public static Dialog createCustomDialog(@NonNull Context context,
+            @NonNull CharSequence dialogTitle, @Nullable View customView,
+            @NonNull CharSequence positiveButtonText,
+            @Nullable DialogInterface.OnClickListener positiveListener,
+            @NonNull CharSequence negativeButtonText,
+            @Nullable DialogInterface.OnClickListener negativeListener) {
+        DialogInterface.OnClickListener doNothingListener =
+                (DialogInterface dialogInterface, int which) -> {};
+        final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context)
                 .setTitle(dialogTitle)
                 .setCancelable(true)
-                .setPositiveButton(positiveButtonText, positiveListener)
-                .setNegativeButton(negativeButtonText, negativeListener)
-                .create();
+                .setPositiveButton(positiveButtonText,
+                        Optional.ofNullable(positiveListener).orElse(doNothingListener))
+                .setNegativeButton(negativeButtonText,
+                        Optional.ofNullable(negativeListener).orElse(doNothingListener));
+        if (customView != null) {
+            dialogBuilder.setView(customView);
+        }
+        final AlertDialog alertDialog = dialogBuilder.create();
         if (customView instanceof ScrollView || customView instanceof AbsListView) {
             setScrollIndicators(customView);
         }
@@ -151,8 +175,7 @@
         list.setId(android.R.id.list);
         list.setDivider(/* divider= */ null);
         list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-        final ItemInfoArrayAdapter
-                adapter = new ItemInfoArrayAdapter(context, itemInfoList);
+        final ListAdapter adapter = new ItemInfoArrayAdapter<>(context, itemInfoList);
         list.setAdapter(adapter);
         list.setOnItemClickListener(itemListener);
         return list;
diff --git a/src/com/android/settings/accessibility/DialogHelper.java b/src/com/android/settings/accessibility/DialogHelper.java
new file mode 100644
index 0000000..6b86de5
--- /dev/null
+++ b/src/com/android/settings/accessibility/DialogHelper.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2025 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.accessibility;
+
+/**
+ * The {@code DialogHelper} interface provides methods for displaying dialogs.
+ * It helps the dialog delegate to show the dialog, and will be injected to the dialog delegate.
+ */
+public interface DialogHelper {
+    /**
+     * Shows a dialog with the specified dialog ID.
+     *
+     * @param dialogId The ID of the dialog to display.
+     */
+    void showDialog(int dialogId);
+}
diff --git a/src/com/android/settings/accessibility/MagnificationModePreferenceController.java b/src/com/android/settings/accessibility/MagnificationModePreferenceController.java
index a8814ac..71ea4c2 100644
--- a/src/com/android/settings/accessibility/MagnificationModePreferenceController.java
+++ b/src/com/android/settings/accessibility/MagnificationModePreferenceController.java
@@ -37,11 +37,13 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.util.Preconditions;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.DialogCreatable;
 import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
 import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.utils.AnnotationSpan;
@@ -57,33 +59,37 @@
         DialogCreatable, LifecycleObserver, OnCreate, OnSaveInstanceState {
 
     static final String PREF_KEY = "screen_magnification_mode";
-    private static final int DIALOG_ID_BASE = 10;
-    @VisibleForTesting
-    static final int DIALOG_MAGNIFICATION_MODE = DIALOG_ID_BASE + 1;
-    @VisibleForTesting
-    static final int DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING = DIALOG_ID_BASE + 2;
-    @VisibleForTesting
     static final String EXTRA_MODE = "mode";
 
-    private static final String TAG = "MagnificationModePreferenceController";
+    private static final String TAG = MagnificationModePreferenceController.class.getSimpleName();
 
+    @Nullable
     private DialogHelper mDialogHelper;
     // The magnification mode in the dialog.
     @MagnificationMode
     private int mModeCache = MagnificationMode.NONE;
+    @Nullable
     private Preference mModePreference;
+    @Nullable
     private ShortcutPreference mLinkPreference;
 
     @VisibleForTesting
+    @Nullable
     ListView mMagnificationModesListView;
 
     private final List<MagnificationModeInfo> mModeInfos = new ArrayList<>();
 
-    public MagnificationModePreferenceController(Context context, String preferenceKey) {
+    public MagnificationModePreferenceController(@NonNull Context context,
+            @NonNull String preferenceKey) {
         super(context, preferenceKey);
         initModeInfos();
     }
 
+
+    public void setDialogHelper(@NonNull DialogHelper dialogHelper) {
+        mDialogHelper = dialogHelper;
+    }
+
     private void initModeInfos() {
         mModeInfos.add(new MagnificationModeInfo(mContext.getText(
                 R.string.accessibility_magnification_mode_dialog_option_full_screen), null,
@@ -103,6 +109,7 @@
         return AVAILABLE;
     }
 
+    @NonNull
     @Override
     public CharSequence getSummary() {
         final int capabilities = MagnificationCapabilities.getCapabilities(mContext);
@@ -110,99 +117,98 @@
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         if (savedInstanceState != null) {
             mModeCache = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE);
         }
     }
 
     @Override
-    public void displayPreference(PreferenceScreen screen) {
+    public void displayPreference(@NonNull PreferenceScreen screen) {
         super.displayPreference(screen);
         mModePreference = screen.findPreference(getPreferenceKey());
         mLinkPreference = screen.findPreference(
                 ToggleFeaturePreferenceFragment.KEY_SHORTCUT_PREFERENCE);
-        mModePreference.setOnPreferenceClickListener(preference -> {
+        Preconditions.checkNotNull(mModePreference).setOnPreferenceClickListener(preference -> {
             mModeCache = MagnificationCapabilities.getCapabilities(mContext);
-            mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
+            Preconditions.checkNotNull(mDialogHelper).showDialog(
+                    DialogEnums.DIALOG_MAGNIFICATION_MODE);
             return true;
         });
     }
 
     @Override
-    public void onSaveInstanceState(Bundle outState) {
+    public void onSaveInstanceState(@NonNull Bundle outState) {
         outState.putInt(EXTRA_MODE, mModeCache);
     }
 
-    /**
-     * Sets {@link DialogHelper} used to show the dialog.
-     */
-    public void setDialogHelper(DialogHelper dialogHelper) {
-        mDialogHelper = dialogHelper;
-        mDialogHelper.setDialogDelegate(this);
-    }
-
+    @NonNull
     @Override
     public Dialog onCreateDialog(int dialogId) {
-        switch (dialogId) {
-            case DIALOG_MAGNIFICATION_MODE:
-                return createMagnificationModeDialog();
-
-            case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
-                return createMagnificationTripleTapWarningDialog();
-        }
-        return null;
+        return switch (dialogId) {
+            case DialogEnums.DIALOG_MAGNIFICATION_MODE -> createMagnificationModeDialog();
+            case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING ->
+                    createMagnificationTripleTapWarningDialog();
+            default -> throw new IllegalArgumentException(
+                    "This only handles magnification mode and triple tap warning dialog");
+        };
     }
 
     @Override
     public int getDialogMetricsCategory(int dialogId) {
-        switch (dialogId) {
-            case DIALOG_MAGNIFICATION_MODE:
-                return SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY;
-            case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
-                return SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING;
-            default:
-                return 0;
-        }
+        return switch (dialogId) {
+            case DialogEnums.DIALOG_MAGNIFICATION_MODE ->
+                    SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY;
+            case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING ->
+                    SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING;
+            default -> 0;
+        };
     }
 
+    @NonNull
+    private ListView getMagnificationModesListView() {
+        return Preconditions.checkNotNull(mMagnificationModesListView);
+    }
+
+    @NonNull
     private Dialog createMagnificationModeDialog() {
         mMagnificationModesListView = AccessibilityDialogUtils.createSingleChoiceListView(
                 mContext, mModeInfos, this::onMagnificationModeSelected);
 
         final View headerView = LayoutInflater.from(mContext).inflate(
-                R.layout.accessibility_magnification_mode_header, mMagnificationModesListView,
-                false);
-        mMagnificationModesListView.addHeaderView(headerView, /* data= */ null, /* isSelectable= */
-                false);
+                R.layout.accessibility_magnification_mode_header,
+                getMagnificationModesListView(), /* attachToRoot= */false);
+        getMagnificationModesListView().addHeaderView(headerView, /* data= */null,
+                /* isSelectable= */false);
 
-        mMagnificationModesListView.setItemChecked(computeSelectionIndex(), true);
+        getMagnificationModesListView().setItemChecked(computeSelectionIndex(), /* value= */true);
         final CharSequence title = mContext.getString(
                 R.string.accessibility_magnification_mode_dialog_title);
         final CharSequence positiveBtnText = mContext.getString(R.string.save);
         final CharSequence negativeBtnText = mContext.getString(R.string.cancel);
 
         return AccessibilityDialogUtils.createCustomDialog(mContext, title,
-                mMagnificationModesListView,
-                positiveBtnText, this::onMagnificationModeDialogPositiveButtonClicked,
-                negativeBtnText, /* negativeListener= */ null);
+                getMagnificationModesListView(), positiveBtnText,
+                this::onMagnificationModeDialogPositiveButtonClicked,
+                negativeBtnText, /* negativeListener= */null);
     }
 
     @VisibleForTesting
-    void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface,
+    void onMagnificationModeDialogPositiveButtonClicked(@NonNull DialogInterface dialogInterface,
             int which) {
-        final int selectedIndex = mMagnificationModesListView.getCheckedItemPosition();
+        final int selectedIndex = getMagnificationModesListView().getCheckedItemPosition();
         if (selectedIndex == AdapterView.INVALID_POSITION) {
-            Log.w(TAG, "invalid index");
+            Log.w(TAG, "Selected positive button with INVALID_POSITION index");
             return;
         }
 
-        mModeCache = ((MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
-                        selectedIndex)).mMagnificationMode;
+        mModeCache = ((MagnificationModeInfo) getMagnificationModesListView().getItemAtPosition(
+                selectedIndex)).mMagnificationMode;
 
         // Do not save mode until user clicks positive button in triple tap warning dialog.
         if (isTripleTapEnabled(mContext) && mModeCache != MagnificationMode.FULLSCREEN) {
-            mDialogHelper.showDialog(DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+            Preconditions.checkNotNull(mDialogHelper).showDialog(
+                    DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
         } else { // Save mode (capabilities) value, don't need to show dialog to confirm.
             updateCapabilitiesAndSummary(mModeCache);
         }
@@ -211,15 +217,14 @@
     private void updateCapabilitiesAndSummary(@MagnificationMode int mode) {
         mModeCache = mode;
         MagnificationCapabilities.setCapabilities(mContext, mModeCache);
-        mModePreference.setSummary(
+        Preconditions.checkNotNull(mModePreference).setSummary(
                 MagnificationCapabilities.getSummary(mContext, mModeCache));
     }
 
-    private void onMagnificationModeSelected(AdapterView<?> parent, View view, int position,
-            long id) {
+    private void onMagnificationModeSelected(@NonNull AdapterView<?> parent, @NonNull View view,
+            int position, long id) {
         final MagnificationModeInfo modeInfo =
-                (MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
-                        position);
+                (MagnificationModeInfo) getMagnificationModesListView().getItemAtPosition(position);
         if (modeInfo.mMagnificationMode == mModeCache) {
             return;
         }
@@ -230,20 +235,22 @@
         final int modesSize = mModeInfos.size();
         for (int i = 0; i < modesSize; i++) {
             if (mModeInfos.get(i).mMagnificationMode == mModeCache) {
-                return i + mMagnificationModesListView.getHeaderViewsCount();
+                return i + getMagnificationModesListView().getHeaderViewsCount();
             }
         }
-        Log.w(TAG, "computeSelectionIndex failed");
+        Log.w(TAG, "Can not find matching mode in mModeInfos");
         return 0;
     }
 
     @VisibleForTesting
-    static boolean isTripleTapEnabled(Context context) {
+    static boolean isTripleTapEnabled(@NonNull Context context) {
         return Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
     }
 
+    @NonNull
     private Dialog createMagnificationTripleTapWarningDialog() {
+        @SuppressWarnings({"InflateParams"})
         final View contentView = LayoutInflater.from(mContext).inflate(
                 R.layout.magnification_triple_tap_warning_dialog, /* root= */ null);
         final CharSequence title = mContext.getString(
@@ -263,12 +270,13 @@
         return dialog;
     }
 
-    private void updateLinkInTripleTapWarningDialog(Dialog dialog, View contentView) {
+    private void updateLinkInTripleTapWarningDialog(@NonNull Dialog dialog,
+            @NonNull View contentView) {
         final TextView messageView = contentView.findViewById(R.id.message);
         // TODO(b/225682559): Need to remove performClick() after refactoring accessibility dialog.
         final View.OnClickListener linkListener = view -> {
             updateCapabilitiesAndSummary(mModeCache);
-            mLinkPreference.performClick();
+            Preconditions.checkNotNull(mLinkPreference).performClick();
             dialog.dismiss();
         };
         final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
@@ -285,25 +293,18 @@
 
     @VisibleForTesting
     void onMagnificationTripleTapWarningDialogNegativeButtonClicked(
-            DialogInterface dialogInterface, int which) {
+            @NonNull DialogInterface dialogInterface, int which) {
         mModeCache = MagnificationCapabilities.getCapabilities(mContext);
-        mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
+        Preconditions.checkNotNull(mDialogHelper).showDialog(
+                DialogEnums.DIALOG_MAGNIFICATION_MODE);
     }
 
     @VisibleForTesting
     void onMagnificationTripleTapWarningDialogPositiveButtonClicked(
-            DialogInterface dialogInterface, int which) {
+            @NonNull DialogInterface dialogInterface, int which) {
         updateCapabilitiesAndSummary(mModeCache);
     }
 
-    /**
-     * An interface to help the delegate to show the dialog. It will be injected to the delegate.
-     */
-    interface DialogHelper extends DialogCreatable {
-        void showDialog(int dialogId);
-        void setDialogDelegate(DialogCreatable delegate);
-    }
-
     @VisibleForTesting
     static class MagnificationModeInfo extends ItemInfoArrayAdapter.ItemInfo {
         @MagnificationMode
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 5ecdf67..e0da6f4 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -19,7 +19,6 @@
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
-import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
 import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
 import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
 import static com.android.settings.accessibility.AccessibilityUtil.getShortcutSummaryList;
@@ -42,8 +41,10 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
+import androidx.core.util.Preconditions;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceCategory;
 import androidx.preference.SwitchPreferenceCompat;
@@ -53,6 +54,7 @@
 import com.android.server.accessibility.Flags;
 import com.android.settings.DialogCreatable;
 import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
 import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -74,10 +76,10 @@
  */
 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
 public class ToggleScreenMagnificationPreferenceFragment extends
-        ToggleFeaturePreferenceFragment implements
-        MagnificationModePreferenceController.DialogHelper {
+        ToggleFeaturePreferenceFragment implements DialogHelper {
 
-    private static final String TAG = "ToggleScreenMagnificationPreferenceFragment";
+    private static final String TAG =
+            ToggleScreenMagnificationPreferenceFragment.class.getSimpleName();
     @VisibleForTesting
     static final String KEY_MAGNIFICATION_SHORTCUT_PREFERENCE = "magnification_shortcut_preference";
     private static final char COMPONENT_NAME_SEPARATOR = ':';
@@ -86,23 +88,30 @@
 
     // TODO(b/147021230): Move duplicated functions with android/internal/accessibility into util.
     private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener;
-    private DialogCreatable mDialogDelegate;
+    @Nullable
+    private DialogCreatable mMagnificationModeDialogDelegate;
 
     @Nullable
     MagnificationOneFingerPanningPreferenceController mOneFingerPanningPreferenceController;
 
     private boolean mInSetupWizard;
 
+    @VisibleForTesting
+    public void setMagnificationModeDialogDelegate(@NonNull DialogCreatable delegate) {
+        mMagnificationModeDialogDelegate = delegate;
+    }
+
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         getActivity().setTitle(R.string.accessibility_screen_magnification_title);
         mInSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
     }
 
+    @NonNull
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @NonNull Bundle savedInstanceState) {
         mFeatureName = getString(R.string.accessibility_screen_magnification_title);
         mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                 .authority(getPrefContext().getPackageName())
@@ -161,15 +170,14 @@
         super.onPause();
     }
 
+    @NonNull
     @Override
     public Dialog onCreateDialog(int dialogId) {
-        if (mDialogDelegate != null) {
-            mDialog = mDialogDelegate.onCreateDialog(dialogId);
-            if (mDialog != null) {
-                return mDialog;
-            }
-        }
         switch (dialogId) {
+            case DialogEnums.DIALOG_MAGNIFICATION_MODE:
+            case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
+                return Preconditions.checkNotNull(mMagnificationModeDialogDelegate)
+                        .onCreateDialog(dialogId);
             case DialogEnums.GESTURE_NAVIGATION_TUTORIAL:
                 return AccessibilityShortcutsTutorial
                         .showAccessibilityGestureTutorialDialog(getPrefContext());
@@ -238,9 +246,10 @@
         generalCategory.addPreference(mSettingsPreference);
 
         final MagnificationModePreferenceController magnificationModePreferenceController =
-                new MagnificationModePreferenceController(getContext(),
+                new MagnificationModePreferenceController(Preconditions.checkNotNull(getContext()),
                         MagnificationModePreferenceController.PREF_KEY);
-        magnificationModePreferenceController.setDialogHelper(this);
+        magnificationModePreferenceController.setDialogHelper(/* dialogHelper= */this);
+        mMagnificationModeDialogDelegate = magnificationModePreferenceController;
         getSettingsLifecycle().addObserver(magnificationModePreferenceController);
         magnificationModePreferenceController.displayPreference(getPreferenceScreen());
         addPreferenceController(magnificationModePreferenceController);
@@ -389,11 +398,6 @@
     }
 
     @Override
-    public void setDialogDelegate(DialogCreatable delegate) {
-        mDialogDelegate = delegate;
-    }
-
-    @Override
     protected void registerKeysToObserverCallback(
             AccessibilitySettingsContentObserver contentObserver) {
         super.registerKeysToObserverCallback(contentObserver);
@@ -470,14 +474,11 @@
 
     @Override
     public int getDialogMetricsCategory(int dialogId) {
-        if (mDialogDelegate != null) {
-            final int category = mDialogDelegate.getDialogMetricsCategory(dialogId);
-            if (category != 0) {
-                return category;
-            }
-        }
-
         switch (dialogId) {
+            case DialogEnums.DIALOG_MAGNIFICATION_MODE:
+            case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
+                return Preconditions.checkNotNull(mMagnificationModeDialogDelegate)
+                        .getDialogMetricsCategory(dialogId);
             case DialogEnums.GESTURE_NAVIGATION_TUTORIAL:
                 return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_GESTURE_NAVIGATION;
             case DialogEnums.ACCESSIBILITY_BUTTON_TUTORIAL:
@@ -514,7 +515,7 @@
     }
 
     @Override
-    public void onToggleClicked(ShortcutPreference preference) {
+    public void onToggleClicked(@NonNull ShortcutPreference preference) {
         final int shortcutTypes = getUserPreferredShortcutTypes();
         getPrefContext().getSystemService(AccessibilityManager.class).enableShortcutsForTargets(
                 preference.isChecked(), shortcutTypes,
@@ -527,7 +528,7 @@
     }
 
     @Override
-    public void onSettingsClicked(ShortcutPreference preference) {
+    public void onSettingsClicked(@NonNull ShortcutPreference preference) {
         EditShortcutsPreferenceFragment.showEditShortcutScreen(
                 requireContext(),
                 getMetricsCategory(),
@@ -581,7 +582,8 @@
      *
      * @param context The current context.
      */
-    public static CharSequence getServiceSummary(Context context) {
+    @NonNull
+    public static CharSequence getServiceSummary(@NonNull Context context) {
         // Get the user shortcut type from settings provider.
         final int userShortcutType = ShortcutUtils.getEnabledShortcutTypes(
                 context, MAGNIFICATION_CONTROLLER_NAME);
@@ -604,8 +606,9 @@
     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new BaseSearchIndexProvider() {
                 // LINT.IfChange(search_data)
+                @NonNull
                 @Override
-                public List<SearchIndexableRaw> getRawDataToIndex(Context context,
+                public List<SearchIndexableRaw> getRawDataToIndex(@NonNull Context context,
                         boolean enabled) {
                     final List<SearchIndexableRaw> rawData =
                             super.getRawDataToIndex(context, enabled);
@@ -628,8 +631,9 @@
                     return rawData;
                 }
 
+                @NonNull
                 @Override
-                public List<String> getNonIndexableKeys(Context context) {
+                public List<String> getNonIndexableKeys(@NonNull Context context) {
                     final List<String> niks = super.getNonIndexableKeys(context);
 
                     if (!com.android.settings.accessibility.Flags.fixA11ySettingsSearch()) {
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
index 1ab86f9..1598e10 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
@@ -52,6 +52,7 @@
 import com.android.settings.privatespace.delete.PrivateSpaceDeleteActivity;
 import com.android.settings.remoteauth.RemoteAuthActivity;
 import com.android.settings.remoteauth.RemoteAuthActivityInternal;
+import com.android.settingslib.users.CreateUserActivity;
 
 import java.util.Collection;
 import java.util.HashSet;
@@ -278,6 +279,10 @@
         String action = mContext.getString(R.string.config_avatar_picker_action);
         addActivityFilter(activityFilters, new Intent(action));
 
+        if (android.multiuser.Flags.placeAddUserDialogWithinActivity()) {
+            addActivityFilter(activityFilters, CreateUserActivity.class);
+        }
+
         ActivityRule activityRule = new ActivityRule.Builder(activityFilters).setAlwaysExpand(true)
                 .build();
         mRuleController.addRule(activityRule);
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
index 86f0314..f0bed94 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
@@ -46,7 +46,6 @@
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
-import com.android.settingslib.flags.Flags;
 import com.android.settingslib.utils.ThreadUtils;
 
 import com.google.common.collect.ImmutableList;
@@ -63,7 +62,6 @@
 public abstract class BluetoothDevicePairingDetailBase extends DeviceListPreferenceFragment {
     private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(15);
     private static final int AUTO_DISMISS_MESSAGE_ID = 1001;
-    private static final int AUTO_FINISH_MESSAGE_ID = 1002;
     private static final ImmutableList<Integer> AUDIO_SHARING_PROFILES = ImmutableList.of(
             BluetoothProfile.LE_AUDIO,
             BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, BluetoothProfile.VOLUME_CONTROL);
@@ -91,8 +89,8 @@
     // onDeviceBondStateChanged(BOND_BONDED), BluetoothDevicePreference's summary has already
     // change from "Pairing..." to empty since it listens to metadata changes happens earlier.
     //
-    // In pairing flow during audio sharing, we have to wait on this page till the device is
-    // connected to check the device type and handle extra logic for audio sharing.
+    // In share then pair flow, we have to wait on this page till the device is connected to check
+    // the device type and handle extra logic for audio sharing.
     // The BluetoothDevicePreference summary will be blank for seconds between "Pairing..." and
     // "Connecting..." To help users better understand the process, we listen to metadata change
     // as well and show a progress dialog with "Connecting to ...." once BluetoothDevice.getState()
@@ -103,11 +101,10 @@
                 public void onMetadataChanged(@NonNull BluetoothDevice device, int key,
                         @Nullable byte[] value) {
                     Log.d(getLogTag(), "onMetadataChanged device = " + device + ", key  = " + key);
-                    if ((mShouldTriggerShareThenPairFlow || shouldSetTempBondMetadata())
-                            && mProgressDialog == null
+                    if (mShouldTriggerShareThenPairFlow && mProgressDialog == null
                             && device.getBondState() == BluetoothDevice.BOND_BONDED
                             && mSelectedList.contains(device)) {
-                        handleDeviceBondedInAudioSharing(device);
+                        handleShareThenPair(device);
                         // Once device is bonded, remove the listener
                         removeOnMetadataChangedListener(device);
                     }
@@ -181,12 +178,11 @@
 
     @Override
     public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
-        boolean shouldSetTempBond = shouldSetTempBondMetadata();
         if (bondState == BluetoothDevice.BOND_BONDED) {
-            if (cachedDevice != null && (mShouldTriggerShareThenPairFlow || shouldSetTempBond)) {
+            if (cachedDevice != null && mShouldTriggerShareThenPairFlow) {
                 BluetoothDevice device = cachedDevice.getDevice();
                 if (device != null && mSelectedList.contains(device)) {
-                    handleDeviceBondedInAudioSharing(device);
+                    handleShareThenPair(device);
                     removeOnMetadataChangedListener(device);
                     return;
                 }
@@ -195,7 +191,7 @@
             finish();
             return;
         } else if (bondState == BluetoothDevice.BOND_BONDING) {
-            if ((mShouldTriggerShareThenPairFlow || shouldSetTempBond) && cachedDevice != null) {
+            if (mShouldTriggerShareThenPairFlow && cachedDevice != null) {
                 BluetoothDevice device = cachedDevice.getDevice();
                 if (device != null && mSelectedList.contains(device)) {
                     addOnMetadataChangedListener(device);
@@ -208,7 +204,7 @@
                     pageId);
             HearingAidStatsLogUtils.setBondEntryForDevice(bondEntry, cachedDevice);
         } else if (bondState == BluetoothDevice.BOND_NONE) {
-            if ((mShouldTriggerShareThenPairFlow || shouldSetTempBond) && cachedDevice != null) {
+            if (mShouldTriggerShareThenPairFlow && cachedDevice != null) {
                 BluetoothDevice device = cachedDevice.getDevice();
                 if (device != null && mSelectedList.contains(device)) {
                     removeOnMetadataChangedListener(device);
@@ -240,22 +236,15 @@
                     && mSelectedList.contains(device)) {
                 var unused = ThreadUtils.postOnBackgroundThread(() -> {
                     if (BluetoothUtils.isAudioSharingUIAvailable(getContext())) {
-                        if ((mShouldTriggerShareThenPairFlow || shouldSetTempBondMetadata())
+                        if (mShouldTriggerShareThenPairFlow
                                 && state == BluetoothAdapter.STATE_CONNECTED
                                 && device.equals(mJustBonded)
                                 && AUDIO_SHARING_PROFILES.contains(bluetoothProfile)
                                 && isReadyForAudioSharing(cachedDevice, bluetoothProfile)) {
                             Log.d(getLogTag(), "onProfileConnectionStateChanged, lea eligible");
                             dismissConnectingDialog();
-                            BluetoothUtils.setTemporaryBondMetadata(device);
-                            if (mShouldTriggerShareThenPairFlow) {
-                                mHandler.removeMessages(AUTO_DISMISS_MESSAGE_ID);
-                                postOnMainThread(() ->
-                                        finishFragmentWithResultForAudioSharing(device));
-                            } else {
-                                mHandler.removeMessages(AUTO_FINISH_MESSAGE_ID);
-                                postOnMainThread(() -> finish());
-                            }
+                            mHandler.removeMessages(AUTO_DISMISS_MESSAGE_ID);
+                            postOnMainThread(() -> finishFragmentWithResultForAudioSharing(device));
                         }
                     } else {
                         postOnMainThread(() -> finish());
@@ -341,16 +330,6 @@
         return false;
     }
 
-    private boolean shouldSetTempBondMetadata() {
-        return Flags.enableTemporaryBondDevicesUi()
-                && BluetoothUtils.isAudioSharingUIAvailable(getContext())
-                && BluetoothUtils.isBroadcasting(mLocalManager)
-                && mLocalManager != null
-                && mLocalManager.getCachedDeviceManager() != null
-                && mLocalManager.getProfileManager().getLeAudioBroadcastAssistantProfile() != null
-                && !Utils.shouldBlockPairingInAudioSharing(mLocalManager);
-    }
-
     private boolean isReadyForAudioSharing(@NonNull CachedBluetoothDevice cachedDevice,
             int justConnectedProfile) {
         for (int profile : AUDIO_SHARING_PROFILES) {
@@ -405,10 +384,10 @@
         });
     }
 
-    private void handleDeviceBondedInAudioSharing(@Nullable BluetoothDevice device) {
+    private void handleShareThenPair(@Nullable BluetoothDevice device) {
         var unused = ThreadUtils.postOnBackgroundThread(() -> {
             if (mJustBonded != null) {
-                Log.d(getLogTag(), "Skip handleDeviceBondedInAudioSharing, already done");
+                Log.d(getLogTag(), "Skip handleShareThenPair, already done");
                 return;
             }
             mJustBonded = device;
@@ -417,38 +396,21 @@
             String deviceName = TextUtils.isEmpty(aliasName) ? device.getAddress()
                     : aliasName;
             showConnectingDialog(deviceName);
-            if (mShouldTriggerShareThenPairFlow) {
-                // For share then pair flow, we have strong signal that users wish to pair new
-                // device to join sharing.
-                // So we wait for AUTO_DISMISS_TIME_THRESHOLD_MS, if we find that the bonded device
-                // is lea in onProfileConnectionStateChanged, we finish the activity, set the device
-                // as temp bond and auto add source; otherwise, show dialog to notify that the
-                // device is incompatible for audio sharing.
-                if (!mHandler.hasMessages(AUTO_DISMISS_MESSAGE_ID)) {
-                    mHandler.postDelayed(() ->
-                            postOnMainThread(
-                                    () -> {
-                                        Log.d(getLogTag(),
-                                                "Show incompatible dialog when timeout");
-                                        dismissConnectingDialog();
-                                        AudioSharingIncompatibleDialogFragment.show(this,
-                                                deviceName,
-                                                () -> finish());
-                                    }), AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
-                }
-            } else {
-                // For other pairing request during audio sharing with sinks < 2, we wait for
-                // AUTO_DISMISS_TIME_THRESHOLD_MS, if we find that the bonded device is lea in
-                // onProfileConnectionStateChanged, we finish the activity and set the device as
-                // temp bond; otherwise, we just finish the activity.
-                if (!mHandler.hasMessages(AUTO_FINISH_MESSAGE_ID)) {
-                    mHandler.postDelayed(() ->
-                            postOnMainThread(
-                                    () -> {
-                                        Log.d(getLogTag(), "Finish activity when timeout");
-                                        finish();
-                                    }), AUTO_FINISH_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
-                }
+            // For share then pair flow, we have strong signal that users wish to pair new
+            // device to join sharing.
+            // So we wait for AUTO_DISMISS_TIME_THRESHOLD_MS, if we find that the bonded device
+            // is lea in onProfileConnectionStateChanged, we finish the activity, set the device
+            // as temp bond and auto add source; otherwise, show dialog to notify that the
+            // device is incompatible for audio sharing.
+            if (!mHandler.hasMessages(AUTO_DISMISS_MESSAGE_ID)) {
+                mHandler.postDelayed(() ->
+                        postOnMainThread(
+                                () -> {
+                                    Log.d(getLogTag(), "Show incompatible dialog when timeout");
+                                    dismissConnectingDialog();
+                                    AudioSharingIncompatibleDialogFragment.show(this, deviceName,
+                                            () -> finish());
+                                }), AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
             }
         });
     }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java
index 740fb35..a7c7984 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java
@@ -16,17 +16,26 @@
 
 package com.android.settings.connecteddevice.audiosharing;
 
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE;
+
+import android.Manifest;
+import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.settings.SettingsEnums;
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
 import androidx.core.app.NotificationCompat;
 
 import com.android.settings.R;
@@ -37,18 +46,30 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Map;
+
 public class AudioSharingReceiver extends BroadcastReceiver {
     private static final String TAG = "AudioSharingReceiver";
     private static final String ACTION_LE_AUDIO_SHARING_SETTINGS =
             "com.android.settings.BLUETOOTH_AUDIO_SHARING_SETTINGS";
     private static final String ACTION_LE_AUDIO_SHARING_STOP =
             "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STOP";
+    private static final String ACTION_LE_AUDIO_SHARING_ADD_SOURCE =
+            "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_ADD_SOURCE";
+    private static final String ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF =
+            "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_CANCEL_NOTIF";
+    private static final String EXTRA_NOTIF_ID = "NOTIF_ID";
     private static final String CHANNEL_ID = "bluetooth_notification_channel";
-    private static final int NOTIFICATION_ID =
+    private static final int AUDIO_SHARING_NOTIFICATION_ID =
             com.android.settingslib.R.drawable.ic_bt_le_audio_sharing;
+    private static final int ADD_SOURCE_NOTIFICATION_ID = R.string.share_audio_notification_title;
+    private static final int NOTIF_AUTO_DISMISS_MILLIS = 300000; //5mins
 
     @Override
-    public void onReceive(Context context, Intent intent) {
+    public void onReceive(@NonNull Context context, @NonNull Intent intent) {
         String action = intent.getAction();
         if (action == null) {
             Log.w(TAG, "Received unexpected intent with null action.");
@@ -74,10 +95,12 @@
                     //       isLeAudioBroadcastSourceSupported() and BluetoothAdapter#
                     //       isLeAudioBroadcastAssistantSupported() always return FEATURE_SUPPORTED
                     //       or FEATURE_NOT_SUPPORTED when BT and BLE off
-                    cancelSharingNotification(context);
+                    cancelSharingNotification(context, AUDIO_SHARING_NOTIFICATION_ID);
                     metricsFeatureProvider.action(
                             context, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION,
                             LocalBluetoothLeBroadcast.ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
+                    cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+                    // TODO: add metric
                 } else {
                     Log.w(
                             TAG,
@@ -99,27 +122,92 @@
                 //       isLeAudioBroadcastSourceSupported() and BluetoothAdapter#
                 //       isLeAudioBroadcastAssistantSupported() always return FEATURE_SUPPORTED
                 //       or FEATURE_NOT_SUPPORTED when BT and BLE off
-                cancelSharingNotification(context);
+                cancelSharingNotification(context, AUDIO_SHARING_NOTIFICATION_ID);
                 metricsFeatureProvider.action(
                         context, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION,
                         ACTION_LE_AUDIO_SHARING_STOP);
+                cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+                break;
+            case LocalBluetoothLeBroadcast.ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED:
+                if (!BluetoothUtils.isAudioSharingUIAvailable(context)) {
+                    Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED, feature disabled.");
+                    return;
+                }
+                BluetoothDevice device = intent.getParcelableExtra(EXTRA_BLUETOOTH_DEVICE,
+                        BluetoothDevice.class);
+                if (device == null) {
+                    Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED, null device");
+                    return;
+                }
+                if (isAppInForeground(context)) {
+                    // TODO: show dialog
+                    Log.d(TAG, "App in foreground, show share audio dialog");
+                } else {
+                    Log.d(TAG, "App not in foreground, show share audio notification");
+                    showAddSourceNotification(context, device);
+                }
+                break;
+            case ACTION_LE_AUDIO_SHARING_ADD_SOURCE:
+                if (!BluetoothUtils.isAudioSharingUIAvailable(context)) {
+                    Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, feature disabled.");
+                    cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+                    return;
+                }
+                BluetoothDevice sink = intent.getParcelableExtra(EXTRA_BLUETOOTH_DEVICE,
+                        BluetoothDevice.class);
+                if (sink == null) {
+                    Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, null device");
+                    cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+                    return;
+                }
+                LocalBluetoothManager manager = Utils.getLocalBtManager(context);
+                boolean isBroadcasting = BluetoothUtils.isBroadcasting(manager);
+                if (!isBroadcasting) {
+                    Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, not broadcasting");
+                    cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+                    return;
+                }
+                Map<Integer, List<BluetoothDevice>> groupedDevices =
+                        AudioSharingUtils.fetchConnectedDevicesByGroupId(manager);
+                int groupId = groupedDevices.entrySet().stream().filter(
+                        entry -> entry.getValue().contains(sink)).findFirst().map(
+                        Map.Entry::getKey).orElse(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+                if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+                    Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, no valid group id");
+                    cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+                    return;
+                }
+                List<BluetoothDevice> sinksToAdd = groupedDevices.getOrDefault(groupId,
+                        ImmutableList.of()).stream().filter(
+                            d -> !BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(d,
+                                manager)).toList();
+                if (sinksToAdd.isEmpty()) {
+                    Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, already has source");
+                } else if (groupedDevices.entrySet().stream().filter(
+                        entry -> entry.getKey() != groupId && entry.getValue().stream().anyMatch(
+                                d -> BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(d,
+                                        manager))).toList().size() >= 2) {
+                    Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, already 2 sinks");
+                } else {
+                    AudioSharingUtils.addSourceToTargetSinks(sinksToAdd, manager);
+                }
+                cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+                break;
+            case ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF:
+                int notifId = intent.getIntExtra(EXTRA_NOTIF_ID, -1);
+                if (notifId != -1) {
+                    cancelSharingNotification(context, notifId);
+                }
                 break;
             default:
                 Log.w(TAG, "Received unexpected intent " + intent.getAction());
         }
     }
 
-    private void showSharingNotification(Context context) {
+    private void showSharingNotification(@NonNull Context context) {
         NotificationManager nm = context.getSystemService(NotificationManager.class);
-        if (nm.getNotificationChannel(CHANNEL_ID) == null) {
-            Log.d(TAG, "Create bluetooth notification channel");
-            NotificationChannel notificationChannel =
-                    new NotificationChannel(
-                            CHANNEL_ID,
-                            context.getString(com.android.settings.R.string.bluetooth),
-                            NotificationManager.IMPORTANCE_HIGH);
-            nm.createNotificationChannel(notificationChannel);
-        }
+        if (nm == null) return;
+        createNotificationChannelIfNeeded(nm, context);
         Intent stopIntent =
                 new Intent(ACTION_LE_AUDIO_SHARING_STOP).setPackage(context.getPackageName());
         PendingIntent stopPendingIntent =
@@ -174,11 +262,110 @@
                         .addAction(stopAction)
                         .addAction(settingsAction)
                         .addExtras(extras);
-        nm.notify(NOTIFICATION_ID, builder.build());
+        nm.notify(AUDIO_SHARING_NOTIFICATION_ID, builder.build());
     }
 
-    private void cancelSharingNotification(Context context) {
+    private void showAddSourceNotification(@NonNull Context context,
+            @NonNull BluetoothDevice device) {
         NotificationManager nm = context.getSystemService(NotificationManager.class);
-        nm.cancel(NOTIFICATION_ID);
+        if (nm == null) return;
+        createNotificationChannelIfNeeded(nm, context);
+        Intent addSourceIntent =
+                new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE).setPackage(context.getPackageName())
+                        .putExtra(EXTRA_BLUETOOTH_DEVICE, device);
+        PendingIntent addSourcePendingIntent =
+                PendingIntent.getBroadcast(
+                        context,
+                        R.string.audio_sharing_share_button_label,
+                        addSourceIntent,
+                        PendingIntent.FLAG_IMMUTABLE);
+        NotificationCompat.Action addSourceAction =
+                new NotificationCompat.Action.Builder(
+                        0,
+                        context.getString(R.string.audio_sharing_share_button_label),
+                        addSourcePendingIntent)
+                        .build();
+        Intent cancelIntent = new Intent(ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF).setPackage(
+                        context.getPackageName())
+                .putExtra(EXTRA_NOTIF_ID, ADD_SOURCE_NOTIFICATION_ID);
+        PendingIntent cancelPendingIntent =
+                PendingIntent.getBroadcast(
+                        context,
+                        R.string.cancel,
+                        cancelIntent,
+                        PendingIntent.FLAG_IMMUTABLE);
+        NotificationCompat.Action cancelAction =
+                new NotificationCompat.Action.Builder(
+                        0,
+                        context.getString(R.string.cancel),
+                        cancelPendingIntent)
+                        .build();
+        final Bundle extras = new Bundle();
+        extras.putString(
+                Notification.EXTRA_SUBSTITUTE_APP_NAME,
+                context.getString(R.string.audio_sharing_title));
+        String deviceName = device.getAlias();
+        if (TextUtils.isEmpty(deviceName)) {
+            deviceName = device.getAddress();
+        }
+        NotificationCompat.Builder builder =
+                new NotificationCompat.Builder(context, CHANNEL_ID)
+                        .setSmallIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
+                        .setLocalOnly(true)
+                        .setContentTitle(context.getString(R.string.share_audio_notification_title,
+                                deviceName))
+                        .setContentText(
+                                context.getString(R.string.audio_sharing_notification_content))
+                        .setOngoing(true)
+                        .setSilent(true)
+                        .setColor(
+                                context.getColor(
+                                        com.android.internal.R.color
+                                                .system_notification_accent_color))
+                        .addAction(addSourceAction)
+                        .addAction(cancelAction)
+                        .setTimeoutAfter(NOTIF_AUTO_DISMISS_MILLIS)
+                        .addExtras(extras);
+        nm.notify(ADD_SOURCE_NOTIFICATION_ID, builder.build());
+    }
+
+    private void cancelSharingNotification(@NonNull Context context, int notifId) {
+        NotificationManager nm = context.getSystemService(NotificationManager.class);
+        if (nm != null) {
+            nm.cancel(notifId);
+        }
+    }
+
+    private void createNotificationChannelIfNeeded(@NonNull NotificationManager nm,
+            @NonNull Context context) {
+        if (nm.getNotificationChannel(CHANNEL_ID) == null) {
+            Log.d(TAG, "Create bluetooth notification channel");
+            NotificationChannel notificationChannel =
+                    new NotificationChannel(
+                            CHANNEL_ID,
+                            context.getString(com.android.settings.R.string.bluetooth),
+                            NotificationManager.IMPORTANCE_HIGH);
+            nm.createNotificationChannel(notificationChannel);
+        }
+    }
+
+    private boolean isAppInForeground(@NonNull Context context) {
+        try {
+            ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+            String packageName = context.getPackageName();
+            if (context.getPackageManager().checkPermission(Manifest.permission.PACKAGE_USAGE_STATS,
+                    packageName) != PackageManager.PERMISSION_GRANTED) {
+                Log.d(TAG, "check isAppInForeground, returns false due to no permission");
+                return false;
+            }
+            if (packageName != null && activityManager.getPackageImportance(packageName)
+                    == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+                Log.d(TAG, "check isAppInForeground, returns true");
+                return true;
+            }
+        } catch (RuntimeException e) {
+            Log.d(TAG, "check isAppInForeground, error = " + e.getMessage());
+        }
+        return false;
     }
 }
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 9acdfaa..e97834f 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -48,13 +48,11 @@
 import com.android.settings.core.PreferenceControllerListHelper;
 import com.android.settings.flags.Flags;
 import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.restriction.UserRestrictionBindingHelper;
 import com.android.settingslib.PrimarySwitchPreference;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.drawer.DashboardCategory;
 import com.android.settingslib.drawer.Tile;
-import com.android.settingslib.preference.PreferenceScreenBindingHelper;
 import com.android.settingslib.preference.PreferenceScreenCreator;
 import com.android.settingslib.search.Indexable;
 
@@ -94,8 +92,6 @@
     private boolean mListeningToCategoryChange;
     private List<String> mSuppressInjectedTileKeys;
 
-    private @Nullable UserRestrictionBindingHelper mUserRestrictionBindingHelper;
-
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
@@ -182,13 +178,6 @@
             // editing dialog is recreated (that would happen before onResume is called).
             updatePreferenceStates();
         }
-        if (isCatalystEnabled()) {
-            PreferenceScreenBindingHelper helper = getPreferenceScreenBindingHelper();
-            if (helper != null) {
-                mUserRestrictionBindingHelper = new UserRestrictionBindingHelper(requireContext(),
-                        helper);
-            }
-        }
     }
 
     @Override
@@ -300,15 +289,6 @@
     }
 
     @Override
-    public void onDestroy() {
-        if (mUserRestrictionBindingHelper != null) {
-            mUserRestrictionBindingHelper.close();
-            mUserRestrictionBindingHelper = null;
-        }
-        super.onDestroy();
-    }
-
-    @Override
     protected abstract int getPreferenceScreenResId();
 
     @Override
diff --git a/src/com/android/settings/development/PageAgnosticNotificationService.java b/src/com/android/settings/development/PageAgnosticNotificationService.java
index 58c26df..c89cbc0 100644
--- a/src/com/android/settings/development/PageAgnosticNotificationService.java
+++ b/src/com/android/settings/development/PageAgnosticNotificationService.java
@@ -23,6 +23,7 @@
 import android.app.Service;
 import android.content.Intent;
 import android.os.IBinder;
+import android.os.UserHandle;
 import android.provider.Settings;
 
 import androidx.annotation.NonNull;
@@ -148,7 +149,8 @@
     public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
         Notification notification = buildNotification();
         if (mNotificationManager != null) {
-            mNotificationManager.notify(NOTIFICATION_ID, notification);
+            mNotificationManager.notifyAsUser(null, NOTIFICATION_ID, notification,
+                    UserHandle.ALL);
         }
         return Service.START_REDELIVER_INTENT;
     }
diff --git a/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java b/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java
index 1955f36..785d84a 100644
--- a/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java
@@ -92,9 +92,10 @@
 
     private String getSummary(long usedBytes, long totalBytes) {
         NumberFormat percentageFormat = NumberFormat.getPercentInstance();
-
+        final String[] freeSpace =
+                Formatter.formatFileSize(mContext, totalBytes - usedBytes).split(" ");
         return mContext.getString(R.string.storage_summary,
                 totalBytes == 0L ? "0" : percentageFormat.format(((double) usedBytes) / totalBytes),
-                Formatter.formatFileSize(mContext, totalBytes - usedBytes));
+                freeSpace[0], freeSpace[1]);
     }
 }
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt b/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt
index f765d8c..54331aa 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt
+++ b/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt
@@ -64,8 +64,12 @@
      * Also check [getIsAvailableAndUpdateEid] for other availability check which retrieved
      * asynchronously later.
      */
-    override fun getAvailabilityStatus() =
-        if (SubscriptionUtil.isSimHardwareVisible(mContext)) AVAILABLE else UNSUPPORTED_ON_DEVICE
+    override fun getAvailabilityStatus() = when {
+        !SubscriptionUtil.isSimHardwareVisible(mContext)
+            || Utils.isWifiOnly(mContext) -> UNSUPPORTED_ON_DEVICE
+        !mContext.userManager.isAdminUser -> DISABLED_FOR_USER
+        else -> AVAILABLE
+    }
 
     override fun displayPreference(screen: PreferenceScreen) {
         super.displayPreference(screen)
@@ -98,7 +102,6 @@
     }
 
     private fun getIsAvailableAndUpdateEid(): Boolean {
-        if (!mContext.userManager.isAdminUser || Utils.isWifiOnly(mContext)) return false
         eid = eidStatus?.eid ?: ""
         return eid.isNotEmpty()
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java b/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
index c62728b..ad2455e 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
@@ -17,6 +17,7 @@
 package com.android.settings.fuelgauge.batteryusage;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -28,7 +29,8 @@
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.widget.TipCardPreference;
+import com.android.settingslib.widget.BannerMessagePreference;
+import com.android.settingslib.widget.BannerMessagePreference.AttentionLevel;
 
 import java.util.function.Function;
 
@@ -37,6 +39,7 @@
 
     private final Context mContext;
     private final PowerAnomalyEvent mPowerAnomalyEvent;
+    private final AttentionLevel mAttentionLevel;
 
     private final int mCardStyleId;
     private final int mResourceIndex;
@@ -51,6 +54,7 @@
         // Set basic battery tips card info
         mCardStyleId = mPowerAnomalyEvent.getType().getNumber();
         mResourceIndex = mPowerAnomalyEvent.getKey().getNumber();
+        mAttentionLevel = mCardStyleId == 0 ? AttentionLevel.NORMAL : AttentionLevel.MEDIUM;
     }
 
     private <T> T getInfo(
@@ -104,12 +108,14 @@
         return mPowerAnomalyEvent.hasEventId() ? mPowerAnomalyEvent.getEventId() : null;
     }
 
-    int getIconResId() {
-        return getResourceId(R.array.battery_tips_card_icons, mCardStyleId, "drawable");
-    }
-
-    int getColorResId() {
-        return getResourceId(R.array.battery_tips_card_colors, mCardStyleId, "color");
+    Drawable getIconDrawable() {
+        final int iconResId =
+                getResourceId(R.array.battery_tips_card_icons, mCardStyleId, "drawable");
+        Drawable drawable = mContext.getDrawable(iconResId);
+        if (drawable != null && mAttentionLevel != AttentionLevel.NORMAL) {
+            drawable.setTint(mContext.getColor(mAttentionLevel.getButtonBackgroundColorResId()));
+        }
+        return drawable;
     }
 
     String getTitleString() {
@@ -236,16 +242,16 @@
         return mHighlightSlotPair;
     }
 
-    boolean updateTipsCardPreference(TipCardPreference preference) {
+    boolean updateTipsCardPreference(BannerMessagePreference preference) {
         final String titleString = getTitleString();
         if (TextUtils.isEmpty(titleString)) {
             return false;
         }
         preference.setTitle(titleString);
-        preference.setIconResId(getIconResId());
-        preference.setTintColorResId(getColorResId());
-        preference.setPrimaryButtonText(getDismissBtnString());
-        preference.setSecondaryButtonText(getMainBtnString());
+        preference.setIcon(getIconDrawable());
+        preference.setAttentionLevel(mAttentionLevel);
+        preference.setNegativeButtonText(getDismissBtnString());
+        preference.setPositiveButtonText(getMainBtnString());
         return true;
     }
 
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
index 88f99c3..eafccdb 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
@@ -377,7 +377,9 @@
         mTransomTop = resources.getDimensionPixelSize(R.dimen.chartview_transom_padding_top);
         mTransomLineDefaultColor = Utils.getDisabled(mContext, DIVIDER_COLOR);
         mTransomLineSelectedColor =
-                resources.getColor(R.color.color_battery_anomaly_app_warning_selector);
+                resources.getColor(
+                        com.android.settingslib.widget.preference.banner.R.color
+                                .settingslib_banner_button_background_medium);
         final int slotHighlightColor = Utils.getDisabled(mContext, mTransomLineSelectedColor);
         mTransomIconSize = resources.getDimensionPixelSize(R.dimen.chartview_transom_icon_size);
         mTransomLinePaint = new Paint();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
index 405b786..705ec6a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -25,15 +25,14 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.widget.TipCardPreference;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.widget.BannerMessagePreference;
 
 /** Controls the update for battery tips card */
 public class BatteryTipsController extends BasePreferenceController {
 
     private static final String TAG = "BatteryTipsController";
-    private static final String ROOT_PREFERENCE_KEY = "battery_tips_category";
-    private static final String CARD_PREFERENCE_KEY = "battery_tips_card";
+    private static final String PREFERENCE_KEY = "battery_tips_card";
 
     @VisibleForTesting static final String ANOMALY_KEY = "anomaly_key";
 
@@ -53,12 +52,12 @@
 
     @VisibleForTesting OnAnomalyConfirmListener mOnAnomalyConfirmListener;
     @VisibleForTesting OnAnomalyRejectListener mOnAnomalyRejectListener;
-    @VisibleForTesting TipCardPreference mCardPreference;
+    @VisibleForTesting BannerMessagePreference mCardPreference;
     @VisibleForTesting AnomalyEventWrapper mAnomalyEventWrapper = null;
     @VisibleForTesting Boolean mIsAcceptable = false;
 
     public BatteryTipsController(Context context) {
-        super(context, ROOT_PREFERENCE_KEY);
+        super(context, PREFERENCE_KEY);
         final FeatureFactory featureFactory = FeatureFactory.getFeatureFactory();
         mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
     }
@@ -71,7 +70,10 @@
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
-        mCardPreference = screen.findPreference(CARD_PREFERENCE_KEY);
+        mCardPreference = screen.findPreference(PREFERENCE_KEY);
+
+        // Set preference as invisible since there is no default tips.
+        mCardPreference.setVisible(false);
     }
 
     void setOnAnomalyConfirmListener(OnAnomalyConfirmListener listener) {
@@ -117,20 +119,13 @@
             return;
         }
 
-        mCardPreference.setPrimaryButtonAction(
-                () -> {
-                    onBatteryTipsCardDismiss(anomalyKeyNumber);
-                    return null;
-                });
-        mCardPreference.setSecondaryButtonAction(
-                () -> {
-                    onBatteryTipsCardAccept(anomalyKeyNumber);
-                    return null;
-                });
+        mCardPreference.setNegativeButtonOnClickListener(
+                view -> onBatteryTipsCardDismiss(anomalyKeyNumber));
+        mCardPreference.setPositiveButtonOnClickListener(
+                view -> onBatteryTipsCardAccept(anomalyKeyNumber));
 
-        mCardPreference.setPrimaryButtonVisibility(true);
-        mCardPreference.setSecondaryButtonVisibility(true);
-        mCardPreference.buildContent();
+        mCardPreference.setPositiveButtonVisible(true);
+        mCardPreference.setNegativeButtonVisible(true);
         mCardPreference.setVisible(true);
         mMetricsFeatureProvider.action(
                 /* attribution= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
diff --git a/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
index 22e3431..121bd82 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
@@ -64,7 +64,9 @@
 
         // Generate Low storage Slice.
         final String percentageString = NumberFormat.getPercentInstance().format(usedPercentage);
-        final String freeSizeString = Formatter.formatFileSize(mContext, info.freeBytes);
+        final String[] freeSizeString =
+                Formatter.formatFileSize(mContext, info.freeBytes).split(" ");
+
         final ListBuilder listBuilder = new ListBuilder(mContext,
                 CustomSliceRegistry.LOW_STORAGE_SLICE_URI, ListBuilder.INFINITY).setAccentColor(
                 Utils.getColorAccentDefaultColor(mContext));
@@ -74,7 +76,7 @@
             // For clients that ignore error checking, a generic storage slice will be given.
             final CharSequence titleStorage = mContext.getText(R.string.storage_settings);
             final String summaryStorage = mContext.getString(R.string.storage_summary,
-                    percentageString, freeSizeString);
+                    percentageString, freeSizeString[0], freeSizeString[1]);
 
             return listBuilder
                     .addRow(buildRowBuilder(titleStorage, summaryStorage, icon))
diff --git a/src/com/android/settings/notification/modes/ConfigurationActivityHelper.java b/src/com/android/settings/notification/modes/ConfigurationActivityHelper.java
index d001651..ad76802 100644
--- a/src/com/android/settings/notification/modes/ConfigurationActivityHelper.java
+++ b/src/com/android/settings/notification/modes/ConfigurationActivityHelper.java
@@ -48,21 +48,22 @@
     Intent getConfigurationActivityIntentForMode(ZenMode zenMode,
             Function<ComponentName, ComponentInfo> approvedServiceFinder) {
 
-        String owner = zenMode.getRule().getPackageName();
+        ZenMode.Owner owner = zenMode.getOwner();
         ComponentName configActivity = null;
-        if (zenMode.getRule().getConfigurationActivity() != null) {
+        if (owner.configurationActivity() != null) {
             // If a configuration activity is present, use that directly in the intent
-            configActivity = zenMode.getRule().getConfigurationActivity();
+            configActivity = owner.configurationActivity();
         } else {
             // Otherwise, look for a condition provider service for the rule's package
-            ComponentInfo ci = approvedServiceFinder.apply(zenMode.getRule().getOwner());
+            ComponentInfo ci = approvedServiceFinder.apply(owner.conditionProvider());
             if (ci != null) {
                 configActivity = extractConfigurationActivityFromComponent(ci);
             }
         }
 
         if (configActivity != null
-                && (owner == null || isSameOwnerPackage(owner, configActivity))
+                && (owner.packageName() == null
+                    || isSameOwnerPackage(owner.packageName(), configActivity))
                 && isResolvableActivity(configActivity)) {
             return new Intent()
                     .setComponent(configActivity)
diff --git a/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
index 72ff524..dbbc486 100644
--- a/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
@@ -51,7 +51,7 @@
     @Override
     public boolean isAvailable(ZenMode zenMode) {
         return zenMode.isEnabled()
-                && (zenMode.isActive() || zenMode.getRule().isManualInvocationAllowed());
+                && (zenMode.isActive() || zenMode.isManualInvocationAllowed());
     }
 
     @Override
diff --git a/src/com/android/settings/notification/modes/ZenModeEditNameIconFragment.java b/src/com/android/settings/notification/modes/ZenModeEditNameIconFragment.java
index 60f7316..f043298 100644
--- a/src/com/android/settings/notification/modes/ZenModeEditNameIconFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeEditNameIconFragment.java
@@ -54,8 +54,8 @@
             return;
         }
 
-        modeToUpdate.getRule().setName(mode.getRule().getName());
-        modeToUpdate.getRule().setIconResId(mode.getRule().getIconResId());
+        modeToUpdate.setName(mode.getName());
+        modeToUpdate.setIconResId(mode.getIconResId());
         requireBackend().updateMode(modeToUpdate);
         finish();
     }
diff --git a/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentBase.java b/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentBase.java
index 6dd9076..20a30f7 100644
--- a/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentBase.java
+++ b/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentBase.java
@@ -128,13 +128,13 @@
 
     @VisibleForTesting
     final void setModeName(String name) {
-        checkNotNull(mZenMode).getRule().setName(Strings.nullToEmpty(name));
+        checkNotNull(mZenMode).setName(Strings.nullToEmpty(name));
         forceUpdatePreferences(); // Updates confirmation button.
     }
 
     @VisibleForTesting
     final void setModeIcon(@DrawableRes int iconResId) {
-        checkNotNull(mZenMode).getRule().setIconResId(iconResId);
+        checkNotNull(mZenMode).setIconResId(iconResId);
         forceUpdatePreferences();  // Updates icon at the top.
     }
 
diff --git a/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java
index 18e3fc1..7bf2e88 100644
--- a/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.notification.modes;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import android.content.Context;
 import android.service.notification.ZenModeConfig;
 
@@ -24,6 +26,7 @@
 import androidx.preference.TwoStatePreference;
 
 import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
 /**
@@ -40,7 +43,7 @@
 
     @Override
     public void updateState(Preference preference, @NonNull ZenMode zenMode) {
-        mSchedule = ZenModeConfig.tryParseScheduleConditionId(zenMode.getRule().getConditionId());
+        mSchedule = checkNotNull(ZenModeSchedules.getTimeSchedule(zenMode));
         ((TwoStatePreference) preference).setChecked(mSchedule.exitAtAlarm);
     }
 
diff --git a/src/com/android/settings/notification/modes/ZenModeNewCustomFragment.java b/src/com/android/settings/notification/modes/ZenModeNewCustomFragment.java
index d7dbaaf..8ff23e7 100644
--- a/src/com/android/settings/notification/modes/ZenModeNewCustomFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeNewCustomFragment.java
@@ -47,8 +47,7 @@
                 ? requireContext().getString(R.string.zen_mode_new_custom_default_name)
                 : mode.getName();
 
-        ZenMode created = requireBackend().addCustomManualMode(modeName,
-                mode.getRule().getIconResId());
+        ZenMode created = requireBackend().addCustomManualMode(modeName, mode.getIconResId());
         if (created != null) {
             // Open the mode view fragment and close the "add mode" fragment, so exiting the mode
             // view goes back to previous screen (which should be the modes list).
diff --git a/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java
index 4f45c5c8..6788236 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java
@@ -32,6 +32,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
 import java.util.ArrayList;
@@ -85,7 +86,7 @@
         mReply.setOnPreferenceChangeListener(mReplyChangeListener);
 
         // Parse the zen mode's condition to update our EventInfo object.
-        mEvent = ZenModeConfig.tryParseEventConditionId(zenMode.getRule().getConditionId());
+        mEvent = ZenModeSchedules.getCalendarSchedule(zenMode);
         if (mEvent != null) {
             reloadCalendar();
             updatePrefValues();
diff --git a/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java
index 651b7cc..d5e6a75 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java
@@ -32,6 +32,7 @@
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 import com.android.settingslib.widget.LayoutPreference;
 
@@ -62,7 +63,7 @@
 
     @Override
     public void updateState(Preference preference, @NonNull ZenMode zenMode) {
-        mSchedule = ZenModeConfig.tryParseScheduleConditionId(zenMode.getRule().getConditionId());
+        mSchedule = ZenModeSchedules.getTimeSchedule(zenMode);
         LayoutPreference layoutPref = (LayoutPreference) preference;
 
         TextView start = layoutPref.findViewById(R.id.start_time);
diff --git a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
index bbed5b9..a0e5b50 100644
--- a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
@@ -20,7 +20,6 @@
 import static android.app.AutomaticZenRule.TYPE_DRIVING;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
-import static android.service.notification.ZenModeConfig.tryParseScheduleConditionId;
 
 import android.annotation.SuppressLint;
 import android.app.AlertDialog;
@@ -43,6 +42,7 @@
 import com.android.settings.Utils;
 import com.android.settingslib.PrimarySwitchPreference;
 import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
 import com.google.common.base.Strings;
@@ -105,8 +105,7 @@
 
             // [Clock Icon] 9:00 - 17:00 / Sun-Mon
             preference.setIcon(com.android.internal.R.drawable.ic_zen_mode_type_schedule_time);
-            ZenModeConfig.ScheduleInfo schedule =
-                    tryParseScheduleConditionId(mode.getRule().getConditionId());
+            ZenModeConfig.ScheduleInfo schedule = ZenModeSchedules.getTimeSchedule(mode);
             if (schedule != null) {
                 preference.setTitle(SystemZenRules.getTimeSummary(mContext, schedule));
                 String shortDaysSummary = SystemZenRules.getDaysOfWeekShort(mContext, schedule);
@@ -138,7 +137,7 @@
     @SuppressLint("SwitchIntDef")
     private void setUpForAppTrigger(Preference preference, ZenMode mode) {
         // App-owned mode may have triggerDescription, configurationActivity, or both/neither.
-        mServiceListing.loadApprovedComponents(mode.getRule().getPackageName());
+        mServiceListing.loadApprovedComponents(mode.getOwnerPackage());
         Intent configurationIntent =
                 mConfigurationActivityHelper.getConfigurationActivityIntentForMode(
                         mode, mServiceListing::findService);
@@ -152,11 +151,11 @@
         String summary;
         if (!Strings.isNullOrEmpty(mode.getTriggerDescription())) {
             summary = mode.getTriggerDescription();
-        } else if (!Strings.isNullOrEmpty(mode.getRule().getPackageName())) {
+        } else if (!Strings.isNullOrEmpty(mode.getOwnerPackage())) {
             String appName = null;
             try {
                 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
-                        mode.getRule().getPackageName(), 0);
+                        mode.getOwnerPackage(), 0);
                 appName = appInfo.loadLabel(mPackageManager).toString();
             } catch (PackageManager.NameNotFoundException e) {
                 Log.e(TAG, "Couldn't resolve owner for mode: " + mode);
@@ -219,7 +218,7 @@
     private void setModeEnabled(boolean enabled) {
         saveMode((zenMode) -> {
             if (enabled != zenMode.isEnabled()) {
-                zenMode.getRule().setEnabled(enabled);
+                zenMode.setEnabled(enabled);
             }
             return zenMode;
         });
diff --git a/src/com/android/settings/notification/modes/ZenModesListFragment.java b/src/com/android/settings/notification/modes/ZenModesListFragment.java
index 00f652d..76a4366 100644
--- a/src/com/android/settings/notification/modes/ZenModesListFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModesListFragment.java
@@ -125,7 +125,7 @@
         // If we find a new mode owned by the same package, presumably that's it. Open its page.
         Optional<ZenMode> createdZenMode = mBackend.getModes().stream()
                 .filter(m -> !previousIds.contains(m.getId()))
-                .filter(m -> m.getRule().getPackageName().equals(activityInvoked.getPackageName()))
+                .filter(m -> activityInvoked.getPackageName().equals(m.getOwnerPackage()))
                 .findFirst();
         createdZenMode.ifPresent(
                 mode ->
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 28d2f4f..aacc11d 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -18,6 +18,9 @@
 
 import static com.android.settingslib.Utils.getColorAttrDefaultColor;
 
+import android.Manifest;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.Dialog;
@@ -83,6 +86,7 @@
 import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.search.SearchIndexableRaw;
+import com.android.settingslib.users.CreateUserActivity;
 import com.android.settingslib.users.CreateUserDialogController;
 import com.android.settingslib.users.EditUserInfoController;
 import com.android.settingslib.users.GrantAdminDialogController;
@@ -91,6 +95,7 @@
 
 import com.google.android.setupcompat.util.WizardManagerHelper;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -171,6 +176,7 @@
 
     private static final int REQUEST_CHOOSE_LOCK = 10;
     private static final int REQUEST_EDIT_GUEST = 11;
+    private static final int REQUEST_ADD_USER = 12;
 
     static final int RESULT_GUEST_REMOVED = 100;
 
@@ -234,6 +240,8 @@
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
 
     private CharSequence mPendingUserName;
+    @Nullable
+    private String mPendingUserIconPath;
     private Drawable mPendingUserIcon;
     private boolean mPendingUserIsAdmin;
 
@@ -570,6 +578,14 @@
             if (resultCode != Activity.RESULT_CANCELED && hasLockscreenSecurity()) {
                 addUserNow(USER_TYPE_RESTRICTED_PROFILE);
             }
+        } else if (Flags.placeAddUserDialogWithinActivity() && requestCode == REQUEST_ADD_USER) {
+            if (resultCode == Activity.RESULT_OK) {
+                mPendingUserName = data.getStringExtra(CreateUserActivity.EXTRA_USER_NAME);
+                mPendingUserIsAdmin = data.getBooleanExtra(CreateUserActivity.EXTRA_IS_ADMIN,
+                        false);
+                mPendingUserIconPath = data.getStringExtra(CreateUserActivity.EXTRA_USER_ICON_PATH);
+                addUserNow(USER_TYPE_USER);
+            }
         } else if (mGuestUserAutoCreated && requestCode == REQUEST_EDIT_GUEST
                 && resultCode == RESULT_GUEST_REMOVED) {
             scheduleGuestCreation();
@@ -921,7 +937,7 @@
                     getActivity(),
                     this::startActivityForResult,
                     canCreateAdminUser(),
-                    (userName, userIcon, isAdmin) -> {
+                    (userName, userIcon, iconPath, isAdmin) -> {
                         mPendingUserIcon = userIcon;
                         mPendingUserName = userName;
                         mPendingUserIsAdmin = isAdmin;
@@ -1040,6 +1056,8 @@
         createUser(userType, mAddingUserName);
     }
 
+    @RequiresPermission(allOf = {Manifest.permission.MANAGE_USERS,
+            Manifest.permission.INTERACT_ACROSS_USERS_FULL})
     @VisibleForTesting
     void createUser(final int userType, String userName) {
         Context context = getContext();
@@ -1065,18 +1083,25 @@
                     mAddingUser = false;
                     mPendingUserIcon = null;
                     mPendingUserName = null;
+                    mPendingUserIconPath = null;
                     onUserCreationFailed();
                     return;
                 }
 
                 Future<?> unusedSettingIconFuture = ThreadUtils.postOnBackgroundThread(() -> {
-                    Drawable newUserIcon = selectedUserIcon;
-                    if (newUserIcon == null) {
-                        newUserIcon = UserIcons.getDefaultUserIcon(resources, user.id, false);
+                    if (Flags.placeAddUserDialogWithinActivity() && mPendingUserIconPath != null) {
+                        Bitmap bitmap = BitmapFactory.decodeFile(mPendingUserIconPath);
+                        mUserManager.setUserIcon(user.id, bitmap);
+                        new File(mPendingUserIconPath).delete();
+                        mPendingUserIconPath = null;
+                    } else {
+                        Drawable newUserIcon = selectedUserIcon;
+                        if (newUserIcon == null) {
+                            newUserIcon = UserIcons.getDefaultUserIcon(resources, user.id, false);
+                        }
+                        mUserManager.setUserIcon(user.id, UserIcons.convertToBitmapAtUserIconSize(
+                                resources, newUserIcon));
                     }
-                    mUserManager.setUserIcon(
-                            user.id, UserIcons.convertToBitmapAtUserIconSize(
-                                    resources, newUserIcon));
                 });
 
                 mPendingUserIcon = null;
@@ -1687,7 +1712,13 @@
             if (mUserCaps.mCanAddRestrictedProfile) {
                 showDialog(DIALOG_CHOOSE_USER_TYPE);
             } else {
-                onAddUserClicked(USER_TYPE_USER);
+                if (Flags.placeAddUserDialogWithinActivity()) {
+                    startActivityForResult(CreateUserActivity.createIntentForStart(getActivity(),
+                                    canCreateAdminUser(), Utils.FILE_PROVIDER_AUTHORITY),
+                            REQUEST_ADD_USER);
+                } else {
+                    onAddUserClicked(USER_TYPE_USER);
+                }
             }
             return true;
         } else if (pref == mAddSupervisedUser) {
diff --git a/src/com/android/settings/wifi/AddNetworkFragment.java b/src/com/android/settings/wifi/AddNetworkFragment.java
index f5bf5ee..38bc0b5 100644
--- a/src/com/android/settings/wifi/AddNetworkFragment.java
+++ b/src/com/android/settings/wifi/AddNetworkFragment.java
@@ -234,6 +234,9 @@
 
             activity.getSystemService(WifiManager.class).save(config, saveListener);
         } else {
+            if (!mUIController.canFinish()) {
+                return;
+            }
             Intent intent = new Intent();
             intent.putExtra(WIFI_CONFIG_KEY, config);
             activity.setResult(Activity.RESULT_OK, intent);
diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java
index 1ea0103..1bf1102 100644
--- a/src/com/android/settings/wifi/WifiConfigController2.java
+++ b/src/com/android/settings/wifi/WifiConfigController2.java
@@ -77,6 +77,7 @@
 import com.android.settings.wifi.details2.WifiPrivacyPreferenceController;
 import com.android.settings.wifi.details2.WifiPrivacyPreferenceController2;
 import com.android.settings.wifi.dpp.WifiDppUtils;
+import com.android.settings.wifi.utils.SsidInputGroup;
 import com.android.settingslib.Utils;
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.wifi.flags.Flags;
@@ -228,7 +229,7 @@
     private final boolean mHideMeteredAndPrivacy;
     private final WifiManager mWifiManager;
     private final AndroidKeystoreAliasLoader mAndroidKeystoreAliasLoader;
-    private TextView mSsidView;
+    private SsidInputGroup mSsidInputGroup;
 
     private final Context mContext;
 
@@ -298,6 +299,7 @@
             wepWarningLayout.setVisibility(View.VISIBLE);
         }
 
+        mSsidInputGroup = new SsidInputGroup(mContext, mView, R.id.ssid_layout, R.id.ssid);
         mSsidScanButton = (ImageButton) mView.findViewById(R.id.ssid_scanner_button);
         mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings);
         mIpSettingsSpinner.setOnItemSelectedListener(this);
@@ -544,13 +546,13 @@
                         && !isValidSaePassword(mPasswordView.getText().toString())))) {
             passwordInvalid = true;
         }
-        if ((mSsidView != null && mSsidView.length() == 0)
-                // If WifiEntry is not saved, apply passwordInvalid check
-                || ((mWifiEntry == null || !mWifiEntry.isSaved()) && passwordInvalid
-                // If WifiEntry is saved (modifying network) and password is changed, apply
-                // Invalid password check
-                || mWifiEntry != null && mWifiEntry.isSaved() && passwordInvalid
-                    && mPasswordView.length() > 0)) {
+        if ((mWifiEntry == null || !mWifiEntry.isSaved()) && passwordInvalid) {
+            // If WifiEntry is not saved, apply passwordInvalid check
+            enabled = false;
+        } else if (mWifiEntry != null && mWifiEntry.isSaved() && passwordInvalid
+                && mPasswordView.length() > 0) {
+            // If WifiEntry is saved (modifying network) and password is changed, apply
+            // Invalid password check
             enabled = false;
         } else {
             enabled = ipAndProxyFieldsAreValid();
@@ -586,16 +588,21 @@
         return enabled;
     }
 
+    boolean canFinish() {
+        if (!mSsidInputGroup.validate()) {
+            Log.w(TAG, "Can't finish because SSID is invalid!");
+            return false;
+        }
+        return true;
+    }
+
     void showWarningMessagesIfAppropriate() {
         mView.findViewById(R.id.no_user_cert_warning).setVisibility(View.GONE);
         mView.findViewById(R.id.no_domain_warning).setVisibility(View.GONE);
         mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.GONE);
 
-        if (mSsidView != null) {
-            final String ssid = mSsidView.getText().toString();
-            if (WifiUtils.isSSIDTooLong(ssid)) {
-                mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE);
-            }
+        if (WifiUtils.isSSIDTooLong(mSsidInputGroup.getText())) {
+            mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE);
         }
         if (mEapCaCertSpinner != null
                 && mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) {
@@ -628,7 +635,7 @@
         WifiConfiguration config;
         if (mWifiEntry == null) {
             config = new WifiConfiguration();
-            config.SSID = "\"" + mSsidView.getText().toString() + "\"";
+            config.SSID = "\"" + mSsidInputGroup.getText() + "\"";
             // If the user adds a network manually, assume that it is hidden.
             config.hiddenSSID = mHiddenSettingsSpinner.getSelectedItemPosition() == HIDDEN_NETWORK;
         } else if (mWifiEntry.isSaved()) {
@@ -1823,8 +1830,7 @@
     private void configureSecuritySpinner() {
         mConfigUi.setTitle(R.string.wifi_add_network);
 
-        mSsidView = (TextView) mView.findViewById(R.id.ssid);
-        mSsidView.addTextChangedListener(this);
+        mSsidInputGroup.addTextChangedListener(this);
         mSecuritySpinner = ((Spinner) mView.findViewById(R.id.security));
         mSecuritySpinner.setOnItemSelectedListener(this);
 
diff --git a/src/com/android/settings/wifi/calling/OWNERS b/src/com/android/settings/wifi/calling/OWNERS
index 87e5fcc..fc903a3 100644
--- a/src/com/android/settings/wifi/calling/OWNERS
+++ b/src/com/android/settings/wifi/calling/OWNERS
@@ -1,7 +1,6 @@
 # Default reviewers for this and subdirectories.
 allenwtsu@google.com
 andychou@google.com
-bonianchen@google.com
 leechou@google.com
 songferngwang@google.com
 tomhsu@google.com
diff --git a/src/com/android/settings/wifi/utils/SsidInputGroup.kt b/src/com/android/settings/wifi/utils/SsidInputGroup.kt
new file mode 100644
index 0000000..5d8f8d4
--- /dev/null
+++ b/src/com/android/settings/wifi/utils/SsidInputGroup.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.utils
+
+import android.content.Context
+import android.view.View
+import com.android.settings.R
+
+/** TextInputGroup for Wi-Fi SSID. */
+class SsidInputGroup(private val context: Context, view: View, layoutId: Int, editTextId: Int) :
+    TextInputGroup(view, layoutId, editTextId) {
+
+    fun validate(): Boolean {
+        if (getText().isEmpty()) {
+            setError(context.getString(R.string.wifi_ssid_hint))
+            return false
+        }
+        return true
+    }
+}
diff --git a/src/com/android/settings/wifi/utils/TextInputGroup.kt b/src/com/android/settings/wifi/utils/TextInputGroup.kt
new file mode 100644
index 0000000..8006dad
--- /dev/null
+++ b/src/com/android/settings/wifi/utils/TextInputGroup.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.utils
+
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.View
+import android.widget.EditText
+import com.google.android.material.textfield.TextInputLayout
+
+/** A widget that wraps the relationship work between a TextInputLayout and an EditText. */
+open class TextInputGroup(
+    private val view: View,
+    private val layoutId: Int,
+    private val editTextId: Int,
+) {
+
+    private val View.layout: TextInputLayout?
+        get() = findViewById(layoutId)
+
+    private val View.editText: EditText?
+        get() = findViewById(editTextId)
+
+    private val textWatcher =
+        object : TextWatcher {
+            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
+
+            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
+
+            override fun afterTextChanged(s: Editable?) {
+                view.layout?.isErrorEnabled = false
+            }
+        }
+
+    init {
+        addTextChangedListener(textWatcher)
+    }
+
+    fun addTextChangedListener(watcher: TextWatcher) {
+        view.editText?.addTextChangedListener(watcher)
+    }
+
+    fun getText(): String {
+        return view.editText?.text?.toString() ?: ""
+    }
+
+    fun setText(text: String) {
+        view.editText?.setText(text)
+    }
+
+    fun setError(errorMessage: String?) {
+        view.layout?.apply { error = errorMessage }
+    }
+}
diff --git a/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java b/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java
index 0cb73c1..eb28dfb 100644
--- a/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java
+++ b/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java
@@ -51,8 +51,8 @@
 import com.android.internal.widget.LockPatternChecker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockscreenCredential;
-import com.android.settings.biometrics.face.FaceEnrollIntroduction;
-import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
+import com.android.settings.biometrics.face.FaceEnroll;
+import com.android.settings.biometrics.fingerprint.FingerprintEnroll;
 import com.android.settings.password.ChooseLockGeneric;
 import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settings.password.ConfirmLockPassword;
@@ -157,8 +157,8 @@
         try (ActivityScenario<BiometricEnrollActivity> scenario =
                      ActivityScenario.launch(intent)) {
             intended(hasComponent(mHasFace && !mHasFingerprint
-                    ? FaceEnrollIntroduction.class.getName()
-                    : FingerprintEnrollIntroduction.class.getName()));
+                    ? FaceEnroll.class.getName()
+                    : FingerprintEnroll.class.getName()));
         }
     }
 
diff --git a/tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java
index 0bc3862..d0d0d37 100644
--- a/tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java
@@ -17,8 +17,6 @@
 package com.android.settings.accessibility;
 
 import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
-import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
-import static com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -37,6 +35,7 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
@@ -44,6 +43,9 @@
 
 import com.android.settings.DialogCreatable;
 import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
+import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
+import com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo;
 import com.android.settings.utils.AnnotationSpan;
 
 import org.junit.Before;
@@ -82,6 +84,8 @@
         mScreen.addPreference(mModePreference);
         MagnificationCapabilities.setCapabilities(mContext, MAGNIFICATION_MODE_DEFAULT);
         mController = new MagnificationModePreferenceController(mContext, PREF_KEY);
+        mController.setDialogHelper(mDialogHelper);
+        mDialogHelper.setDialogDelegate(mController);
         showPreferenceOnTheScreen(null);
     }
 
@@ -107,7 +111,7 @@
         performItemClickWith(MagnificationMode.WINDOW);
 
         reshowPreferenceOnTheScreen();
-        mDialogHelper.showDialog(MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE);
+        mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_MODE);
 
         assertThat(getCheckedModeFromDialog()).isEqualTo(
                 MagnificationMode.WINDOW);
@@ -123,7 +127,7 @@
                 DialogInterface.BUTTON_POSITIVE);
 
         verify(mDialogHelper, never()).showDialog(
-                MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+                DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
     }
 
     @Test
@@ -135,8 +139,7 @@
         mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(),
                 DialogInterface.BUTTON_POSITIVE);
 
-        verify(mDialogHelper).showDialog(
-                MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+        verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
     }
 
     @Test
@@ -148,20 +151,17 @@
         mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(),
                 DialogInterface.BUTTON_POSITIVE);
 
-        verify(mDialogHelper).showDialog(
-                MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+        verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
     }
 
     @Test
     public void onTripleTapWarningDialogNegativeButtonClicked_showModeDialog() {
-        mDialogHelper.showDialog(
-                MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+        mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
 
         mController.onMagnificationTripleTapWarningDialogNegativeButtonClicked(
                 mDialogHelper.getDialog(), DialogInterface.BUTTON_NEGATIVE);
 
-        verify(mDialogHelper).showDialog(
-                MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE);
+        verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_MODE);
     }
 
     @Test
@@ -182,8 +182,7 @@
 
     @Test
     public void checkSpansInTripleTapWarningDialog_existAnnotationSpan() {
-        mDialogHelper.showDialog(
-                MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+        mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
         final View contentView = mDialogHelper.getDialog().findViewById(android.R.id.content);
         final TextView messageView = contentView.findViewById(R.id.message);
         final CharSequence textInTripleTapWarningDialog = messageView.getText();
@@ -256,13 +255,11 @@
     }
 
     private void showPreferenceOnTheScreen(Bundle savedInstanceState) {
-        mController.setDialogHelper(mDialogHelper);
         mController.onCreate(savedInstanceState);
         mController.displayPreference(mScreen);
     }
 
-    private static class TestDialogHelper implements DialogCreatable,
-            MagnificationModePreferenceController.DialogHelper {
+    private static class TestDialogHelper implements DialogCreatable, DialogHelper {
         private DialogCreatable mDialogDelegate;
         private Dialog mDialog;
 
@@ -271,11 +268,11 @@
             mDialog = onCreateDialog(dialogId);
         }
 
-        @Override
-        public void setDialogDelegate(DialogCreatable delegate) {
+        public void setDialogDelegate(@NonNull DialogCreatable delegate) {
             mDialogDelegate = delegate;
         }
 
+        @NonNull
         @Override
         public Dialog onCreateDialog(int dialogId) {
             return mDialogDelegate.onCreateDialog(dialogId);
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
index ae059dd..4b28085 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
@@ -64,6 +64,8 @@
 import com.android.settings.DialogCreatable;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
+import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
 import com.android.settings.testutils.shadow.ShadowAccessibilityManager;
 import com.android.settings.testutils.shadow.ShadowDeviceConfig;
 import com.android.settings.testutils.shadow.ShadowStorageManager;
@@ -550,7 +552,8 @@
         ToggleScreenMagnificationPreferenceFragment fragment = mFragController.create(
                 R.id.main_content, /* bundle= */ null).start().resume().get();
 
-        DialogCreatable dialogDelegate = ReflectionHelpers.getField(fragment, "mDialogDelegate");
+        DialogCreatable dialogDelegate = ReflectionHelpers.getField(fragment,
+                "mMagnificationModeDialogDelegate");
         List<LifecycleObserver> lifecycleObservers = ReflectionHelpers.getField(
                 fragment.getSettingsLifecycle(), "mObservers");
         assertThat(dialogDelegate).isInstanceOf(MagnificationModePreferenceController.class);
@@ -592,19 +595,19 @@
     }
 
     @Test
-    public void onCreateDialog_setDialogDelegate_invokeDialogDelegate() {
+    public void onCreateDialog_setMagnificationModeDialogDelegate_invokeDialogDelegate() {
         ToggleScreenMagnificationPreferenceFragment fragment =
                 mFragController.create(
                         R.id.main_content, /* bundle= */ null).start().resume().get();
         final DialogCreatable dialogDelegate = mock(DialogCreatable.class, RETURNS_DEEP_STUBS);
-        when(dialogDelegate.getDialogMetricsCategory(anyInt())).thenReturn(1);
-        fragment.setDialogDelegate(dialogDelegate);
+        final int dialogId = DialogEnums.DIALOG_MAGNIFICATION_MODE;
+        when(dialogDelegate.getDialogMetricsCategory(anyInt())).thenReturn(dialogId);
+        fragment.setMagnificationModeDialogDelegate(dialogDelegate);
 
-        fragment.onCreateDialog(1);
-        fragment.getDialogMetricsCategory(1);
-
-        verify(dialogDelegate).onCreateDialog(1);
-        verify(dialogDelegate).getDialogMetricsCategory(1);
+        fragment.onCreateDialog(dialogId);
+        fragment.getDialogMetricsCategory(dialogId);
+        verify(dialogDelegate).onCreateDialog(dialogId);
+        verify(dialogDelegate).getDialogMetricsCategory(dialogId);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
index 38a607a..78c771c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
@@ -18,7 +18,6 @@
 
 import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE;
 import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING;
-import static com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -37,7 +36,6 @@
 import android.app.Activity;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothStatusCodes;
 import android.content.Context;
@@ -66,15 +64,9 @@
 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
 import com.android.settings.testutils.shadow.ShadowFragment;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 import com.android.settingslib.flags.Flags;
 
-import com.google.common.collect.ImmutableList;
-
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -122,14 +114,6 @@
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private LocalBluetoothManager mLocalManager;
     @Mock
-    private CachedBluetoothDeviceManager mDeviceManager;
-    @Mock
-    private LocalBluetoothProfileManager mProfileManager;
-    @Mock
-    private LocalBluetoothLeBroadcast mBroadcast;
-    @Mock
-    private LocalBluetoothLeBroadcastAssistant mAssistant;
-    @Mock
     private CachedBluetoothDevice mCachedBluetoothDevice;
     @Mock
     private Drawable mDrawable;
@@ -221,7 +205,6 @@
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         mFragment.mSelectedList.add(mBluetoothDevice);
         setUpFragmentWithShareThenPairIntent(false);
-        setUpAudioSharingStates(/* enabled = */ false, /* needSetTempBondMetadata = */ false);
         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
 
         verify(mFragment).finish();
@@ -236,31 +219,6 @@
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         mFragment.mSelectedList.add(mBluetoothDevice);
         setUpFragmentWithShareThenPairIntent(true);
-        setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
-        mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
-        shadowOf(Looper.getMainLooper()).idle();
-
-        ProgressDialogFragment progressDialog = mFragment.mProgressDialog;
-        assertThat(progressDialog).isNotNull();
-        assertThat(progressDialog.getMessage()).isEqualTo(
-                mContext.getString(R.string.progress_dialog_connect_device_content,
-                        TEST_DEVICE_ADDRESS));
-        assertThat(
-                ShadowDialogFragment.isIsShowing(ProgressDialogFragment.class.getName())).isTrue();
-        verify(mFragment, never()).finish();
-
-        ShadowDialogFragment.reset();
-    }
-
-    @Test
-    @Config(shadows = ShadowDialogFragment.class)
-    @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
-    public void onDeviceBondStateChanged_bonded_pairAfterShare_handle() {
-        ShadowDialogFragment.reset();
-        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
-        mFragment.mSelectedList.add(mBluetoothDevice);
-        setUpFragmentWithShareThenPairIntent(false);
-        setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
         shadowOf(Looper.getMainLooper()).idle();
 
@@ -283,7 +241,6 @@
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         mFragment.mSelectedList.add(mBluetoothDevice);
         setUpFragmentWithShareThenPairIntent(false);
-        setUpAudioSharingStates(/* enabled = */ false, /* needSetTempBondMetadata = */ false);
         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
 
         verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(any(BluetoothDevice.class),
@@ -297,21 +254,6 @@
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         mFragment.mSelectedList.add(mBluetoothDevice);
         setUpFragmentWithShareThenPairIntent(true);
-        setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
-        mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
-
-        verify(mBluetoothAdapter).addOnMetadataChangedListener(eq(mBluetoothDevice),
-                any(Executor.class),
-                any(BluetoothAdapter.OnMetadataChangedListener.class));
-    }
-
-    @Test
-    @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
-    public void onDeviceBondStateChanged_bonding_pairAfterShare_addListener() {
-        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
-        mFragment.mSelectedList.add(mBluetoothDevice);
-        setUpFragmentWithShareThenPairIntent(false);
-        setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
 
         verify(mBluetoothAdapter).addOnMetadataChangedListener(eq(mBluetoothDevice),
@@ -337,21 +279,6 @@
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         mFragment.mSelectedList.add(mBluetoothDevice);
         setUpFragmentWithShareThenPairIntent(true);
-        setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
-        mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
-        mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
-
-        verify(mBluetoothAdapter).removeOnMetadataChangedListener(eq(mBluetoothDevice),
-                any(BluetoothAdapter.OnMetadataChangedListener.class));
-    }
-
-    @Test
-    @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
-    public void onDeviceBondStateChanged_unbonded_pairAfterShare_removeListener() {
-        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
-        mFragment.mSelectedList.add(mBluetoothDevice);
-        setUpFragmentWithShareThenPairIntent(false);
-        setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
 
@@ -387,7 +314,6 @@
         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
         mFragment.mSelectedList.add(device);
         setUpFragmentWithShareThenPairIntent(true);
-        setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
         shadowOf(Looper.getMainLooper()).idle();
 
@@ -400,7 +326,6 @@
                 BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
         shadowOf(Looper.getMainLooper()).idle();
 
-        verify(device).setMetadata(eq(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS), any());
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         verify(mFragment.getActivity()).setResult(eq(Activity.RESULT_OK), captor.capture());
         Intent intent = captor.getValue();
@@ -417,35 +342,6 @@
     }
 
     @Test
-    @Config(shadows = ShadowDialogFragment.class)
-    @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
-    public void
-            onProfileConnectionStateChanged_inSelectedListAndConnected_pairAfterShare_handle() {
-        ShadowDialogFragment.reset();
-        BluetoothDevice device = spy(mBluetoothDevice);
-        when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
-        mFragment.mSelectedList.add(device);
-        setUpFragmentWithShareThenPairIntent(false);
-        setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
-        mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
-        shadowOf(Looper.getMainLooper()).idle();
-
-        when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
-        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
-        when(mCachedBluetoothDevice.isConnectedLeAudioBroadcastAssistantDevice()).thenReturn(true);
-        when(mCachedBluetoothDevice.isConnectedVolumeControlDevice()).thenReturn(true);
-
-        mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
-                BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
-        shadowOf(Looper.getMainLooper()).idle();
-
-        verify(device).setMetadata(eq(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS), any());
-        verify(mFragment).finish();
-
-        ShadowDialogFragment.reset();
-    }
-
-    @Test
     @DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
     public void onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing() {
         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
@@ -537,38 +433,6 @@
         mFragment.mShouldTriggerShareThenPairFlow = mFragment.shouldTriggerShareThenPairFlow();
     }
 
-    private void setUpAudioSharingStates(boolean enabled, boolean needSetTempBondMetadata) {
-        when(mLocalManager.getProfileManager()).thenReturn(mProfileManager);
-        when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
-        when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
-        when(mLocalManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
-        if (!enabled) {
-            when(mBroadcast.isEnabled(null)).thenReturn(false);
-        } else {
-            when(mBroadcast.isEnabled(null)).thenReturn(true);
-            when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
-            BluetoothDevice device1 = mock(BluetoothDevice.class);
-            CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
-            when(mDeviceManager.findDevice(device1)).thenReturn(cachedDevice1);
-            when(cachedDevice1.getGroupId()).thenReturn(1);
-            when(cachedDevice1.getDevice()).thenReturn(device1);
-            BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
-            when(state.getBroadcastId()).thenReturn(1);
-            when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state));
-            if (needSetTempBondMetadata) {
-                when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device1));
-            } else {
-                BluetoothDevice device2 = mock(BluetoothDevice.class);
-                CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
-                when(mDeviceManager.findDevice(device2)).thenReturn(cachedDevice2);
-                when(cachedDevice2.getGroupId()).thenReturn(2);
-                when(cachedDevice2.getDevice()).thenReturn(device2);
-                when(mAssistant.getAllConnectedDevices()).thenReturn(
-                        ImmutableList.of(device1, device2));
-            }
-        }
-    }
-
     private static class TestBluetoothDevicePairingDetailBase extends
             BluetoothDevicePairingDetailBase {
 
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java
index e720038..dfe5171 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java
@@ -16,28 +16,41 @@
 
 package com.android.settings.connecteddevice.audiosharing;
 
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED;
 import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.ACTION_LE_AUDIO_SHARING_STATE_CHANGE;
 import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.BROADCAST_STATE_OFF;
 import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.BROADCAST_STATE_ON;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE;
 import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_LE_AUDIO_SHARING_STATE;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 
+import android.Manifest;
+import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.bluetooth.BluetoothStatusCodes;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 
 import com.android.settings.bluetooth.Utils;
@@ -45,11 +58,16 @@
 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
 import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
 import com.android.settingslib.R;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 import com.android.settingslib.flags.Flags;
 
+import com.google.common.collect.ImmutableList;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -72,6 +90,12 @@
 public class AudioSharingReceiverTest {
     private static final String ACTION_LE_AUDIO_SHARING_STOP =
             "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STOP";
+    private static final String ACTION_LE_AUDIO_SHARING_ADD_SOURCE =
+            "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_ADD_SOURCE";
+    private static final String ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF =
+            "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_CANCEL_NOTIF";
+    private static final String EXTRA_NOTIF_ID = "NOTIF_ID";
+    private static final String TEST_DEVICE_NAME = "test";
 
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -83,12 +107,14 @@
     private FakeFeatureFactory mFeatureFactory;
     @Mock private LocalBluetoothProfileManager mLocalBtProfileManager;
     @Mock private LocalBluetoothLeBroadcast mBroadcast;
+    @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
     @Mock private LocalBluetoothManager mLocalBtManager;
+    @Mock private BluetoothDevice mDevice;
     @Mock private NotificationManager mNm;
 
     @Before
     public void setUp() {
-        mContext = RuntimeEnvironment.getApplication();
+        mContext = spy(RuntimeEnvironment.getApplication());
         mShadowApplication = Shadow.extract(mContext);
         mShadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
         mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
@@ -101,6 +127,8 @@
         mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
         when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
         when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
+        when(mLocalBtProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
+        when(mDevice.getAlias()).thenReturn(TEST_DEVICE_NAME);
         mFeatureFactory = FakeFeatureFactory.setupForTest();
     }
 
@@ -130,9 +158,8 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
     public void broadcastReceiver_receiveAudioSharingStateOn_flagOff_doNothing() {
-        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
         Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
         intent.setPackage(mContext.getPackageName());
         intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, BROADCAST_STATE_ON);
@@ -144,8 +171,8 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
     public void broadcastReceiver_receiveAudioSharingStateOn_broadcastDisabled_doNothing() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
         mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
 
@@ -160,9 +187,8 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
     public void broadcastReceiver_receiveAudioSharingStateChangeIntentNoState_doNothing() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
         Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
         intent.setPackage(mContext.getPackageName());
         AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
@@ -173,9 +199,8 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
     public void broadcastReceiver_receiveAudioSharingStateOn_broadcastEnabled_showNotification() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
         Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
         intent.setPackage(mContext.getPackageName());
         intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, BROADCAST_STATE_ON);
@@ -188,9 +213,9 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
     public void
             broadcastReceiver_receiveAudioSharingStateOff_broadcastDisabled_cancelNotification() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
         mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
 
@@ -207,10 +232,9 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
     public void
             broadcastReceiver_receiveAudioSharingStateOff_broadcastEnabled_cancelNotification() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
         Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
         intent.setPackage(mContext.getPackageName());
         intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, BROADCAST_STATE_OFF);
@@ -224,8 +248,8 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
     public void broadcastReceiver_receiveAudioSharingStop_broadcastDisabled_cancelNotification() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
         mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
 
@@ -242,8 +266,8 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
     public void broadcastReceiver_receiveAudioSharingStop_notInBroadcast_cancelNotification() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
         when(mBroadcast.isEnabled(null)).thenReturn(false);
         int broadcastId = 1;
         when(mBroadcast.getLatestBroadcastId()).thenReturn(broadcastId);
@@ -261,8 +285,8 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
     public void broadcastReceiver_receiveAudioSharingStop_inBroadcast_stopBroadcast() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
         when(mBroadcast.isEnabled(null)).thenReturn(true);
         int broadcastId = 1;
         when(mBroadcast.getLatestBroadcastId()).thenReturn(broadcastId);
@@ -281,6 +305,247 @@
                         ACTION_LE_AUDIO_SHARING_STOP);
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+    public void broadcastReceiver_receiveAudioSharingDeviceConnected_broadcastDisabled_doNothing() {
+        mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
+                BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
+
+        setAppInForeground(false);
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mNm, never()).notify(
+                eq(com.android.settings.R.string.share_audio_notification_title),
+                any(Notification.class));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+    public void broadcastReceiver_receiveAudioSharingDeviceConnected_showDialog() {
+        setAppInForeground(true);
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mNm, never()).notify(
+                eq(com.android.settings.R.string.share_audio_notification_title),
+                any(Notification.class));
+        // TODO: verify show dialog once impl complete
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+    public void broadcastReceiver_receiveAudioSharingDeviceConnected_showNotification() {
+        setAppInForeground(false);
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        // TODO: verify no dialog once impl complete
+        verify(mNm).notify(eq(com.android.settings.R.string.share_audio_notification_title),
+                any(Notification.class));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+    public void broadcastReceiver_receiveAudioSharingAddSource_broadcastDisabled_cancelNotif() {
+        mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
+                BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
+
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+                anyBoolean());
+        verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+    public void broadcastReceiver_receiveAudioSharingAddSource_nullArg_cancelNotif() {
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+        intent.setPackage(mContext.getPackageName());
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mAssistant, never()).addSource(any(BluetoothDevice.class),
+                any(BluetoothLeBroadcastMetadata.class), anyBoolean());
+        verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+    public void broadcastReceiver_receiveAudioSharingAddSource_notInBroadcast_cancelNotif() {
+        when(mBroadcast.isEnabled(null)).thenReturn(false);
+
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+                anyBoolean());
+        verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+    public void broadcastReceiver_receiveAudioSharingAddSource_notConnected_cancelNotif() {
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of());
+
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+                anyBoolean());
+        verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+    public void broadcastReceiver_receiveAudioSharingAddSource_invalidGroupId_cancelNotif() {
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+        CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice);
+        when(cachedDevice.getDevice()).thenReturn(mDevice);
+        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice));
+
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+                anyBoolean());
+        verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+    }
+
+    @Test
+    @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX})
+    public void broadcastReceiver_receiveAudioSharingAddSource_alreadyTwoSinks_cancelNotif() {
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
+        CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+        CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+        when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice1);
+        BluetoothDevice device2 = mock(BluetoothDevice.class);
+        CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+        when(deviceManager.findDevice(device2)).thenReturn(cachedDevice2);
+        when(cachedDevice1.getGroupId()).thenReturn(1);
+        when(cachedDevice1.getDevice()).thenReturn(mDevice);
+        when(cachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME);
+        when(cachedDevice2.getGroupId()).thenReturn(2);
+        when(cachedDevice2.getDevice()).thenReturn(device2);
+        when(cachedDevice2.getName()).thenReturn(TEST_DEVICE_NAME);
+        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice, device2));
+        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+        when(state.getBroadcastId()).thenReturn(1);
+        when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state));
+
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+                anyBoolean());
+        verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+    }
+
+    @Test
+    @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX})
+    public void broadcastReceiver_receiveAudioSharingAddSource_alreadyHasSource_cancelNotif() {
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
+        CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+        CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice);
+        when(cachedDevice.getGroupId()).thenReturn(1);
+        when(cachedDevice.getDevice()).thenReturn(mDevice);
+        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice));
+        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+        when(state.getBroadcastId()).thenReturn(1);
+        when(mAssistant.getAllSources(mDevice)).thenReturn(ImmutableList.of(state));
+
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+                anyBoolean());
+        verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+    }
+
+    @Test
+    @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX})
+    public void broadcastReceiver_receiveAudioSharingAddSource_addSource() {
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
+        BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class);
+        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
+        CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+        CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+        when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice1);
+        BluetoothDevice device2 = mock(BluetoothDevice.class);
+        CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+        when(deviceManager.findDevice(device2)).thenReturn(cachedDevice2);
+        when(cachedDevice1.getGroupId()).thenReturn(1);
+        when(cachedDevice1.getDevice()).thenReturn(mDevice);
+        when(cachedDevice2.getGroupId()).thenReturn(2);
+        when(cachedDevice2.getDevice()).thenReturn(device2);
+        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice, device2));
+        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+        when(state.getBroadcastId()).thenReturn(1);
+        when(mAssistant.getAllSources(device2)).thenReturn(ImmutableList.of(state));
+
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mAssistant).addSource(mDevice, metadata, /* isGroupOp= */ false);
+        verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+    public void broadcastReceiver_receiveAudioSharingCancelNotif_cancel() {
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF);
+        intent.setPackage(mContext.getPackageName());
+        intent.putExtra(EXTRA_NOTIF_ID,
+                com.android.settings.R.string.share_audio_notification_title);
+        AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+        audioSharingReceiver.onReceive(mContext, intent);
+
+        verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+    }
+
     private AudioSharingReceiver getAudioSharingReceiver(Intent intent) {
         assertThat(mShadowApplication.hasReceiverForIntent(intent)).isTrue();
         List<BroadcastReceiver> receiversForIntent =
@@ -290,4 +555,16 @@
         assertThat(broadcastReceiver).isInstanceOf(AudioSharingReceiver.class);
         return (AudioSharingReceiver) broadcastReceiver;
     }
+
+    private void setAppInForeground(boolean foreground) {
+        ActivityManager activityManager = mock(ActivityManager.class);
+        when(mContext.getSystemService(ActivityManager.class)).thenReturn(activityManager);
+        when(activityManager.getPackageImportance(mContext.getPackageName())).thenReturn(
+                foreground ? ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+                        : ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE);
+        PackageManager packageManager = mock(PackageManager.class);
+        when(mContext.getPackageManager()).thenReturn(packageManager);
+        when(packageManager.checkPermission(Manifest.permission.PACKAGE_USAGE_STATS,
+                mContext.getPackageName())).thenReturn(PackageManager.PERMISSION_GRANTED);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
index 6c29036b..d561395 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
@@ -19,6 +19,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -29,30 +31,41 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.os.LocaleList;
+import android.view.View;
 
-import com.android.settings.R;
 import com.android.settings.testutils.BatteryTestUtils;
 import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.widget.TipCardPreference;
+import com.android.settingslib.widget.BannerMessagePreference;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
+import org.robolectric.shadow.api.Shadow;
 
 import java.util.Locale;
 import java.util.TimeZone;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = BatteryTipsControllerTest.ShadowBannerMessagePreference.class)
 public final class BatteryTipsControllerTest {
 
     private Context mContext;
     private FakeFeatureFactory mFeatureFactory;
     private BatteryTipsController mBatteryTipsController;
-    private TipCardPreference mCardPreference;
+    private BannerMessagePreference mCardPreference;
+
+    @Mock Drawable mIconDrawable;
+    @Mock View mView;
 
     @Before
     public void setUp() {
@@ -61,12 +74,13 @@
         TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
 
         mContext = spy(RuntimeEnvironment.application);
+        DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
         final Resources resources = spy(mContext.getResources());
         resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
         doReturn(resources).when(mContext).getResources();
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mBatteryTipsController = spy(new BatteryTipsController(mContext));
-        mCardPreference = new TipCardPreference(mContext);
+        mCardPreference = spy(new BannerMessagePreference(mContext));
         mBatteryTipsController.mCardPreference = mCardPreference;
     }
 
@@ -84,18 +98,16 @@
                         new AnomalyEventWrapper(
                                 mContext,
                                 BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent(true)));
+        when(anomalyEventWrapper.getIconDrawable()).thenReturn(mIconDrawable);
         when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
 
         mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, false);
 
-        assertThat(mCardPreference.getTitle())
-                .isEqualTo("Turn on adaptive brightness to extend battery life");
-        assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
-        assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("View Settings");
-        assertThat(mCardPreference.getIconResId()).isEqualTo(R.drawable.ic_battery_tips_lightbulb);
-        assertThat(mCardPreference.getTintColorResId()).isEqualTo(R.color.color_accent_selector);
-        assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
-        assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
+        assertCardPreference(
+                "Turn on adaptive brightness to extend battery life",
+                "View Settings",
+                "Got it",
+                BannerMessagePreference.AttentionLevel.NORMAL);
         assertCardButtonActionAndMetrics(anomalyEventWrapper);
     }
 
@@ -105,18 +117,16 @@
                 spy(
                         new AnomalyEventWrapper(
                                 mContext, BatteryTestUtils.createScreenTimeoutAnomalyEvent(true)));
+        when(anomalyEventWrapper.getIconDrawable()).thenReturn(mIconDrawable);
         when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
 
         mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, false);
 
-        assertThat(mCardPreference.getTitle())
-                .isEqualTo("Reduce screen timeout to extend battery life");
-        assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
-        assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("View Settings");
-        assertThat(mCardPreference.getIconResId()).isEqualTo(R.drawable.ic_battery_tips_lightbulb);
-        assertThat(mCardPreference.getTintColorResId()).isEqualTo(R.color.color_accent_selector);
-        assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
-        assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
+        assertCardPreference(
+                "Reduce screen timeout to extend battery life",
+                "View Settings",
+                "Got it",
+                BannerMessagePreference.AttentionLevel.NORMAL);
         assertCardButtonActionAndMetrics(anomalyEventWrapper);
     }
 
@@ -133,17 +143,16 @@
                         .build();
         AnomalyEventWrapper anomalyEventWrapper =
                 spy(new AnomalyEventWrapper(mContext, anomalyEvent));
+        when(anomalyEventWrapper.getIconDrawable()).thenReturn(mIconDrawable);
         when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
 
         mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, false);
 
-        assertThat(mCardPreference.getTitle()).isEqualTo(testTitle);
-        assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
-        assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("View Settings");
-        assertThat(mCardPreference.getIconResId()).isEqualTo(R.drawable.ic_battery_tips_lightbulb);
-        assertThat(mCardPreference.getTintColorResId()).isEqualTo(R.color.color_accent_selector);
-        assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
-        assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
+        assertCardPreference(
+                testTitle,
+                "View Settings",
+                "Got it",
+                BannerMessagePreference.AttentionLevel.NORMAL);
         assertCardButtonActionAndMetrics(anomalyEventWrapper);
     }
 
@@ -151,6 +160,7 @@
     public void handleBatteryTipsCardUpdated_appAnomaly_showAnomaly() {
         AnomalyEventWrapper anomalyEventWrapper =
                 spy(new AnomalyEventWrapper(mContext, BatteryTestUtils.createAppAnomalyEvent()));
+        when(anomalyEventWrapper.getIconDrawable()).thenReturn(mIconDrawable);
         when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
 
         anomalyEventWrapper.setRelatedBatteryDiffEntry(
@@ -159,29 +169,41 @@
                 () -> mBatteryTipsController.acceptTipsCard());
         mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, true);
 
-        assertThat(mCardPreference.getTitle()).isEqualTo("Chrome used more battery than usual");
-        assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
-        assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("Check");
-        assertThat(mCardPreference.getIconResId())
-                .isEqualTo(R.drawable.ic_battery_tips_warning_icon);
-        assertThat(mCardPreference.getTintColorResId())
-                .isEqualTo(R.color.color_battery_anomaly_app_warning_selector);
-        assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
-        assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
-        assertThat(mCardPreference.isVisible()).isTrue();
+        assertCardPreference(
+                "Chrome used more battery than usual",
+                "Check",
+                "Got it",
+                BannerMessagePreference.AttentionLevel.MEDIUM);
         assertCardButtonActionAndMetrics(anomalyEventWrapper);
     }
 
+    private void assertCardPreference(
+            final String title,
+            final String positiveBtnText,
+            final String negativeBtnText,
+            BannerMessagePreference.AttentionLevel attentionLevel) {
+        verify(mCardPreference).setTitle(eq(title));
+        verify(mCardPreference).setPositiveButtonText(eq(positiveBtnText));
+        verify(mCardPreference).setNegativeButtonText(eq(negativeBtnText));
+        verify(mCardPreference).setIcon(mIconDrawable);
+        verify(mCardPreference).setAttentionLevel(attentionLevel);
+        verify(mCardPreference).setPositiveButtonVisible(true);
+        verify(mCardPreference).setNegativeButtonVisible(true);
+        assertThat(mCardPreference.isVisible()).isTrue();
+    }
+
     private void assertCardButtonActionAndMetrics(final AnomalyEventWrapper anomalyEventWrapper) {
         when(anomalyEventWrapper.updateSystemSettingsIfAvailable()).thenReturn(true);
 
         final int powerAnomalyKeyNumber = anomalyEventWrapper.getAnomalyKeyNumber();
         assertCardMetrics(SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, powerAnomalyKeyNumber);
         assertThat(mCardPreference.isVisible()).isTrue();
+        final ShadowBannerMessagePreference shadowPreference = Shadow.extract(mCardPreference);
 
         // Check accept button action
         mCardPreference.setVisible(true);
-        mCardPreference.getSecondaryButtonAction().invoke();
+        clearInvocations(mFeatureFactory.metricsFeatureProvider);
+        shadowPreference.getPositiveButtonOnClickListener().onClick(mView);
         assertCardMetrics(SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, powerAnomalyKeyNumber);
         assertThat(mCardPreference.isVisible()).isFalse();
         final boolean isAppAnomalyCard = powerAnomalyKeyNumber > 1;
@@ -190,7 +212,8 @@
 
         // Check reject button action
         mCardPreference.setVisible(true);
-        mCardPreference.getPrimaryButtonAction().invoke();
+        clearInvocations(mFeatureFactory.metricsFeatureProvider);
+        shadowPreference.getNegativeButtonOnClickListener().onClick(mView);
         assertCardMetrics(SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, powerAnomalyKeyNumber);
         assertThat(mCardPreference.isVisible()).isFalse();
     }
@@ -204,4 +227,37 @@
                         BatteryTipsController.ANOMALY_KEY,
                         powerAnomalyKeyNumber);
     }
+
+    @Implements(BannerMessagePreference.class)
+    public static class ShadowBannerMessagePreference {
+
+        @RealObject protected BannerMessagePreference mRealBannerMessagePreference;
+
+        private View.OnClickListener mPositiveButtonOnClickListener;
+        private View.OnClickListener mNegativeButtonOnClickListener;
+
+        /** Shadow implementation of setPositiveButtonOnClickListener */
+        @Implementation
+        public BannerMessagePreference setPositiveButtonOnClickListener(
+                View.OnClickListener listener) {
+            mPositiveButtonOnClickListener = listener;
+            return mRealBannerMessagePreference;
+        }
+
+        /** Shadow implementation of setNegativeButtonOnClickListener */
+        @Implementation
+        public BannerMessagePreference setNegativeButtonOnClickListener(
+                View.OnClickListener listener) {
+            mNegativeButtonOnClickListener = listener;
+            return mRealBannerMessagePreference;
+        }
+
+        View.OnClickListener getPositiveButtonOnClickListener() {
+            return mPositiveButtonOnClickListener;
+        }
+
+        View.OnClickListener getNegativeButtonOnClickListener() {
+            return mNegativeButtonOnClickListener;
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
index 887a324..5149bf4 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
@@ -130,7 +130,7 @@
         verify(mBackend).updateMode(captor.capture());
         assertThat(captor.getValue().getPolicy().getPriorityCategoryAlarms())
                 .isEqualTo(STATE_DISALLOW);
-        assertThat(captor.getValue().getRule().getInterruptionFilter())
+        assertThat(captor.getValue().getInterruptionFilter())
                 .isEqualTo(INTERRUPTION_FILTER_PRIORITY);
     }
 
@@ -162,7 +162,7 @@
         verify(mBackend).updateMode(captor.capture());
         assertThat(captor.getValue().getPolicy().getPriorityCategoryAlarms())
                 .isEqualTo(STATE_DISALLOW);
-        assertThat(captor.getValue().getRule().getInterruptionFilter())
+        assertThat(captor.getValue().getInterruptionFilter())
                 .isEqualTo(INTERRUPTION_FILTER_ALL);
     }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java
index 1140238..ad4112d 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java
@@ -183,7 +183,7 @@
         // NONE is not actually propagated to the backend as an interruption filter;
         // the filter is set to priority, and sounds and visual effects are disallowed.
         // See AbstractZenModePreferenceController.
-        assertThat(captor.getValue().getRule().getInterruptionFilter())
+        assertThat(captor.getValue().getInterruptionFilter())
                 .isEqualTo(INTERRUPTION_FILTER_PRIORITY);
 
         // After screen is refreshed, NONE is now checked; others are unchecked.
@@ -217,7 +217,7 @@
         ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
         verify(mBackend).updateMode(captor.capture());
         // Checks the policy value for PRIORITY is propagated to the backend.
-        assertThat(captor.getValue().getRule().getInterruptionFilter())
+        assertThat(captor.getValue().getInterruptionFilter())
                 .isEqualTo(INTERRUPTION_FILTER_PRIORITY);
 
         // After screen is refreshed, PRIORITY is now checked; others are unchecked.
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentTest.java
index cb853bb..4a0d8d4 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentTest.java
@@ -124,7 +124,7 @@
         verify(mBackend).updateMode(captor.capture());
         ZenMode savedMode = captor.getValue();
         assertThat(savedMode.getName()).isEqualTo("A newer name");
-        assertThat(savedMode.getRule().getIconResId()).isEqualTo(
+        assertThat(savedMode.getIconKey().resId()).isEqualTo(
                 R.drawable.ic_zen_mode_type_theater);
 
         assertThat(mActivity.isFinishing()).isTrue();
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java
index c949fb8..abd0b67 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java
@@ -34,6 +34,7 @@
 
 import com.android.settingslib.notification.modes.TestModeBuilder;
 import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
 import org.junit.Before;
@@ -89,7 +90,7 @@
 
         // Now update state after changing exitAtAlarm
         scheduleInfo.exitAtAlarm = true;
-        mode.getRule().setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo));
+        mode.setCustomModeConditionId(mContext, ZenModeConfig.toScheduleConditionId(scheduleInfo));
 
         // now can just call updateState
         mPrefController.updateState(preference, mode);
@@ -117,8 +118,8 @@
         mPrefController.onPreferenceChange(preference, false);
         ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
         verify(mBackend).updateMode(captor.capture());
-        ZenModeConfig.ScheduleInfo newSchedule = ZenModeConfig.tryParseScheduleConditionId(
-                captor.getValue().getRule().getConditionId());
+        ZenModeConfig.ScheduleInfo newSchedule = ZenModeSchedules.getTimeSchedule(
+                captor.getValue());
         assertThat(newSchedule.exitAtAlarm).isFalse();
 
         // other properties remain the same
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java
index f0c2369..512e8af 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java
@@ -41,6 +41,7 @@
 
 import com.android.settingslib.notification.modes.TestModeBuilder;
 import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
 import org.junit.Before;
@@ -102,10 +103,10 @@
         // apply event mode updater to existing mode
         ZenMode out = mPrefController.updateEventMode(eventInfo).apply(mode);
 
-        assertThat(out.getRule().getOwner()).isEqualTo(ZenModeConfig.getEventConditionProvider());
-        assertThat(out.getRule().getConditionId()).isEqualTo(
-                ZenModeConfig.toEventConditionId(eventInfo));
-        assertThat(out.getRule().getTriggerDescription()).isEqualTo("My events");
+        assertThat(ZenModeSchedules.getCalendarSchedule(out)).isEqualTo(eventInfo);
+        assertThat(out.getOwner().conditionProvider()).isEqualTo(
+                ZenModeConfig.getEventConditionProvider());
+        assertThat(out.getTriggerDescription()).isEqualTo("My events");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java
index b446d71..0ae37b6 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java
@@ -38,6 +38,7 @@
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settingslib.notification.modes.TestModeBuilder;
 import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
 import org.junit.Before;
@@ -92,11 +93,10 @@
         scheduleInfo.endHour = 2;
         ZenMode out = mPrefController.updateScheduleMode(scheduleInfo).apply(mode);
 
-        assertThat(out.getRule().getConditionId())
-                .isEqualTo(ZenModeConfig.toScheduleConditionId(scheduleInfo));
-        assertThat(out.getRule().getTriggerDescription()).isNotEmpty();
-        assertThat(out.getRule().getOwner()).isEqualTo(
+        assertThat(ZenModeSchedules.getTimeSchedule(out)).isEqualTo(scheduleInfo);
+        assertThat(out.getOwner().conditionProvider()).isEqualTo(
                 ZenModeConfig.getScheduleConditionProvider());
+        assertThat(out.getTriggerDescription()).isNotEmpty();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
index 0a8e400..b8f8ff3 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
@@ -44,6 +44,7 @@
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settingslib.notification.modes.TestModeBuilder;
 import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
 import org.junit.Before;
@@ -168,9 +169,9 @@
         verify(mBackend).updateMode(captor.capture());
         ZenMode updatedMode = captor.getValue();
         assertThat(updatedMode.getType()).isEqualTo(TYPE_SCHEDULE_TIME);
-        assertThat(updatedMode.getRule().getConditionId()).isEqualTo(scheduleUri);
-        assertThat(updatedMode.getRule().getTriggerDescription()).isNotEmpty();
-        assertThat(updatedMode.getRule().getOwner()).isEqualTo(
+        assertThat(ZenModeSchedules.getTimeSchedule(updatedMode)).isEqualTo(scheduleInfo);
+        assertThat(updatedMode.getTriggerDescription()).isNotEmpty();
+        assertThat(updatedMode.getOwner().conditionProvider()).isEqualTo(
                 ZenModeConfig.getScheduleConditionProvider());
     }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
index 6e6485e..b5d4203 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
@@ -161,7 +161,7 @@
         assertThat(mPreference.getCheckedState()).isFalse();
 
         // Now with the rule enabled
-        zenMode.getRule().setEnabled(true);
+        zenMode.setEnabled(true);
         mController.updateZenMode(mPreference, zenMode);
         assertThat(mPreference.getCheckedState()).isTrue();
     }
@@ -189,7 +189,7 @@
         // Verify the backend got asked to update the mode to be enabled
         ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
         verify(mBackend).updateMode(captor.capture());
-        assertThat(captor.getValue().getRule().isEnabled()).isTrue();
+        assertThat(captor.getValue().isEnabled()).isTrue();
         assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isFalse();
     }
 
@@ -216,7 +216,7 @@
         // Verify the backend got asked to update the mode to be disabled
         ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
         verify(mBackend).updateMode(captor.capture());
-        assertThat(captor.getValue().getRule().isEnabled()).isFalse();
+        assertThat(captor.getValue().isEnabled()).isFalse();
         assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
index d985ee5..99b3acc 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
@@ -194,15 +194,6 @@
     }
 
     @Test
-    public void isSubmittable_noSSID_shouldReturnFalse() {
-        createController(mWifiEntry, WifiConfigUiBase2.MODE_CONNECT, false);
-        final TextView ssid = mView.findViewById(R.id.ssid);
-        assertThat(ssid).isNotNull();
-        ssid.setText("");
-        assertThat(mController.isSubmittable()).isFalse();
-    }
-
-    @Test
     public void isSubmittable_longPsk_shouldReturnFalse() {
         createController(mWifiEntry, WifiConfigUiBase2.MODE_CONNECT, false);
         final TextView password = mView.findViewById(R.id.password);
@@ -1048,6 +1039,24 @@
         verify(mController.mEapAnonymousView, never()).setText(any(String.class));
     }
 
+    @Test
+    public void canFinish_ssidIsEmpty_returnFalse() {
+        createController(null, WifiConfigUiBase2.MODE_CONNECT, false);
+        TextView ssid = mView.findViewById(R.id.ssid);
+        ssid.setText("");
+
+        assertThat(mController.canFinish()).isFalse();
+    }
+
+    @Test
+    public void canFinish_ssidIsGood_returnTrue() {
+        createController(null, WifiConfigUiBase2.MODE_CONNECT, false);
+        TextView ssid = mView.findViewById(R.id.ssid);
+        ssid.setText(GOOD_SSID);
+
+        assertThat(mController.canFinish()).isTrue();
+    }
+
     private void setUpModifyingSavedCertificateConfigController(String savedCaCertificate,
             String savedUserCertificate) {
         final WifiConfiguration mockWifiConfig = spy(new WifiConfiguration());
diff --git a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceControllerTest.kt
index 5d68f98..67659ba 100644
--- a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceControllerTest.kt
@@ -17,17 +17,23 @@
 package com.android.settings.deviceinfo.simstatus
 
 import android.content.Context
+import android.os.UserManager
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.dx.mockito.inline.extended.ExtendedMockito
 import com.android.settings.core.BasePreferenceController
 import com.android.settings.network.SubscriptionUtil
+import com.android.settingslib.Utils
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.MockitoSession
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
 import org.mockito.kotlin.whenever
 import org.mockito.quality.Strictness
 
@@ -35,7 +41,12 @@
 class SimEidPreferenceControllerTest {
     private lateinit var mockSession: MockitoSession
 
-    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val mockUserManager = mock<UserManager>()
+
+    private val context: Context =
+        spy(ApplicationProvider.getApplicationContext()) {
+            on { getSystemService(UserManager::class.java) } doReturn mockUserManager
+        }
 
     private val controller = SimEidPreferenceController(context, TEST_KEY)
 
@@ -44,8 +55,16 @@
         mockSession = ExtendedMockito.mockitoSession()
             .initMocks(this)
             .mockStatic(SubscriptionUtil::class.java)
+            .mockStatic(Utils::class.java)
             .strictness(Strictness.LENIENT)
             .startMocking()
+
+        // By default, available
+        whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
+        whenever(Utils.isWifiOnly(context)).thenReturn(false)
+        mockUserManager.stub {
+            on { isAdminUser } doReturn true
+        }
     }
 
     @After
@@ -54,20 +73,35 @@
     }
 
     @Test
-    fun getAvailabilityStatus_isSimHardwareVisible() {
-        whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
-
+    fun getAvailabilityStatus_simHardwareVisible_userAdmin_notWifiOnly_displayed() {
+        // Use defaults from setup()
         val availabilityStatus = controller.availabilityStatus
-
         assertThat(availabilityStatus).isEqualTo(BasePreferenceController.AVAILABLE)
     }
 
     @Test
-    fun getAvailabilityStatus_notSimHardwareVisible() {
+    fun getAvailabilityStatus_notSimHardwareVisible_userAdmin_notWifiOnly_notDisplayed() {
         whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(false)
 
         val availabilityStatus = controller.availabilityStatus
+        assertThat(availabilityStatus).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE)
+    }
 
+    @Test
+    fun getAvailabilityStatus_simHardwareVisible_notUserAdmin_notWifiOnly_notDisplayed() {
+        mockUserManager.stub {
+            on { isAdminUser } doReturn false
+        }
+
+        val availabilityStatus = controller.availabilityStatus
+        assertThat(availabilityStatus).isEqualTo(BasePreferenceController.DISABLED_FOR_USER)
+    }
+
+    @Test
+    fun getAvailabilityStatus_simHardwareVisible_userAdmin_wifiOnly_notDisplayed() {
+        whenever(Utils.isWifiOnly(context)).thenReturn(true)
+
+        val availabilityStatus = controller.availabilityStatus
         assertThat(availabilityStatus).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE)
     }
 
diff --git a/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java
index 6318c9c..300d028 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java
@@ -86,7 +86,7 @@
         when(mController.getStorageManagerVolumeProvider())
                 .thenReturn(mStorageManagerVolumeProvider);
         final String percentage = NumberFormat.getPercentInstance().format(1);
-        final String freeSpace = Formatter.formatFileSize(mContext, 0);
+        final String[] freeSpace = Formatter.formatFileSize(mContext, 0).split(" ");
         final Preference preference = new Preference(mContext);
 
         // Wait for asynchronous thread to finish, otherwise test will flake.
@@ -103,6 +103,6 @@
         // the background thread.
         TimeUnit.SECONDS.sleep(5);
         assertThat(preference.getSummary()).isEqualTo(ResourcesUtils.getResourcesString(
-                mContext, "storage_summary", percentage, freeSpace));
+                mContext, "storage_summary", percentage, freeSpace[0], freeSpace[1]));
     }
 }