Merge "Add audio category preference in more settings fragment" into main
diff --git a/Android.bp b/Android.bp
index 0a58ee8..28c3148 100644
--- a/Android.bp
+++ b/Android.bp
@@ -130,6 +130,7 @@
         "ims-common",
     ],
     flags_packages: [
+        "aconfig_settings_flags",
         "android.app.flags-aconfig",
     ],
 }
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cc4d898..5072e67 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -237,6 +237,7 @@
             <intent-filter>
                 <action android:name="android.intent.action.USER_INITIALIZE"/>
                 <action android:name="android.intent.action.PRE_BOOT_COMPLETED"/>
+                <action android:name="com.google.android.setupwizard.SETUP_WIZARD_FINISHED"/>
             </intent-filter>
         </receiver>
 
diff --git a/res-product/values-pt-rPT/strings.xml b/res-product/values-pt-rPT/strings.xml
index 25f8b74..67c7b74 100644
--- a/res-product/values-pt-rPT/strings.xml
+++ b/res-product/values-pt-rPT/strings.xml
@@ -266,7 +266,7 @@
     <string name="ethernet_tethering_subtext" product="default" msgid="8652438909365718644">"Partilhar a ligação à Internet do telemóvel através de Ethernet"</string>
     <string name="ethernet_tethering_subtext" product="tablet" msgid="2227710549796706455">"Partilhar a ligação à Internet do tablet por Ethernet"</string>
     <string name="about_settings" product="tablet" msgid="1471390492111370330">"Acerca do tablet"</string>
-    <string name="about_settings" product="default" msgid="2621311564780208250">"Acerca do telefone"</string>
+    <string name="about_settings" product="default" msgid="2621311564780208250">"Acerca do telemóvel"</string>
     <string name="about_settings" product="device" msgid="7595574154492383452">"Acerca do dispositivo"</string>
     <string name="about_settings" product="emulator" msgid="1099246296173401003">"Acerca do dispositivo emulado"</string>
     <string name="install_all_warning" product="tablet" msgid="1732116924846572063">"O seu tablet e os dados pessoais são mais vulneráveis a ataques de apps desconhecidas. Ao instalar apps desta fonte, aceita ser responsável por quaisquer danos no tablet ou perdas de dados que possam resultar da utilização do mesmo."</string>
diff --git a/res-product/values-zh-rCN/strings.xml b/res-product/values-zh-rCN/strings.xml
index c11fa41..873d35e 100644
--- a/res-product/values-zh-rCN/strings.xml
+++ b/res-product/values-zh-rCN/strings.xml
@@ -297,8 +297,8 @@
     <string name="battery_tip_dialog_summary_message" product="device" msgid="7885502661524685786">"您的应用目前耗电量正常。如果应用耗电量过高,您的设备会为您提供操作建议。\n\n如果电池电量不足,您可以随时开启省电模式。"</string>
     <string name="smart_battery_summary" product="default" msgid="1210637215867635435">"限制不常用的应用的耗电量"</string>
     <string name="battery_usage_screen_footer" product="default" msgid="8872101342490341865">"手机充电时,系统不会衡量电池使用情况和屏幕使用时间"</string>
-    <string name="battery_usage_screen_footer" product="tablet" msgid="1876984641036532124">"平板电脑充电时,系统不会衡量电池用量和设备使用时间"</string>
-    <string name="battery_usage_screen_footer" product="device" msgid="6488857833906266507">"设备充电时,系统不会衡量电池用量和设备使用时间"</string>
+    <string name="battery_usage_screen_footer" product="tablet" msgid="1876984641036532124">"平板电脑充电时,系统不会衡量电池用量和屏幕使用时间"</string>
+    <string name="battery_usage_screen_footer" product="device" msgid="6488857833906266507">"设备充电时,系统不会衡量电池用量和屏幕使用时间"</string>
     <string name="credentials_install_summary" product="nosdcard" msgid="8585932964626513863">"从存储设备安装证书"</string>
     <string name="credentials_install_summary" product="default" msgid="879796378361350092">"从SD卡安装证书"</string>
     <string name="really_remove_account_message" product="tablet" msgid="5134483498496943623">"移除该账号会从平板电脑中删除所有相关的邮件、联系人以及其他数据。"</string>
diff --git a/res/layout/modes_edit_name.xml b/res/layout/modes_edit_name.xml
index 0b086c7..7f1a1e6 100644
--- a/res/layout/modes_edit_name.xml
+++ b/res/layout/modes_edit_name.xml
@@ -20,7 +20,8 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingBottom="8dp">
 
     <EditText
         android:layout_width="match_parent"
diff --git a/res/layout/modes_icon_list.xml b/res/layout/modes_icon_list.xml
index f6f2202..b189ce6 100644
--- a/res/layout/modes_icon_list.xml
+++ b/res/layout/modes_icon_list.xml
@@ -28,8 +28,7 @@
         android:layout_height="wrap_content"
         android:clipToPadding="true"
         android:nestedScrollingEnabled="false"
-        android:paddingStart="12dp"
-        android:paddingEnd="12dp"
+        android:padding="12dp"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent"
diff --git a/res/layout/modes_set_schedule_layout.xml b/res/layout/modes_set_schedule_layout.xml
index e90dc7c..6b7ebc8 100644
--- a/res/layout/modes_set_schedule_layout.xml
+++ b/res/layout/modes_set_schedule_layout.xml
@@ -127,7 +127,8 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:paddingHorizontal="8dp"
-            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Small" />
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Small"
+            android:textColor="?android:attr/textColorSecondary" />
 
         <!-- right side line divider -->
         <View
diff --git a/res/layout/sfps_enroll_finish_base.xml b/res/layout/sfps_enroll_finish_base.xml
index 9e65c83..768fe34 100644
--- a/res/layout/sfps_enroll_finish_base.xml
+++ b/res/layout/sfps_enroll_finish_base.xml
@@ -35,7 +35,7 @@
                 android:id="@+id/sfps_enrollment_finish_content_layout"
                 android:layout_width="@dimen/sfps_enrollment_finished_icon_max_size"
                 android:layout_height="@dimen/sfps_enrollment_finished_icon_max_size"
-                android:layout_marginTop="24dp"
+                android:layout_marginTop="@dimen/sfps_enroll_finish_icon_margin_top"
                 android:paddingTop="0dp"
                 android:paddingBottom="0dp"
                 android:layout_gravity="center">
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c9a67e4..5961b95 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -156,6 +156,7 @@
     <dimen name="sfps_progress_bar_translate_y">2dp</dimen>
     <dimen name="sfps_lottie_translate_x">12dp</dimen>
     <dimen name="sfps_lottie_translate_y">12dp</dimen>
+    <dimen name="sfps_enroll_finish_icon_margin_top">-24dp</dimen>
     <dimen name="udfps_lottie_translate_y">0dp</dimen>
     <dimen name="udfps_lottie_padding_top">20dp</dimen>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4780e52..cf0e112 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -571,11 +571,15 @@
     <string name="roaming_warning">Roaming charges may apply.</string>
 
     <!-- Date & time setting screen setting switch title: whether the system clock (Unix epoch time) should be determined automatically [CHAR LIMIT=100] -->
-    <string name="date_time_auto">Set time automatically</string>
+    <string name="date_time_auto">Automatic date and time</string>
+    <!-- Date & time setting screen setting switch summary: whether the system clock (Unix epoch time) should be determined automatically [CHAR LIMIT=100] -->
+    <string name="date_time_auto_summary">Set automatically using your network and wireless signals</string>
     <!-- Date & time setting screen setting switch title: whether the time zone should be determined automatically [CHAR LIMIT=100]  -->
-    <string name="zone_auto_title">Set automatically</string>
+    <string name="zone_auto_title">Automatic time zone</string>
+    <!-- Date & time setting screen setting switch summary: whether the time zone should be determined automatically [CHAR LIMIT=100]  -->
+    <string name="zone_auto_title_summary">Set automatically based on mobile networks near you</string>
     <!-- Date & time setting screen setting switch summary for non-telephony devices [CHAR LIMIT=100] -->
-    <string name="auto_zone_requires_location_summary">Location will be used for setting the time zone when this toggle is on</string>
+    <string name="auto_zone_requires_location_summary">Set automatically using your device location, if available. An active Wifi connection may also be required.</string>
     <!-- Date & time setting screen setting option summary text for the automatic 24 hour setting checkbox [CHAR LIMIT=100] -->
     <string name="date_time_24hour_auto">Use locale default</string>
     <!-- Date & time setting screen setting check box title -->
@@ -3772,7 +3776,7 @@
     <string name="location_services_screen_title">Location services</string>
 
     <!-- [CHAR LIMIT=60] Date&Time settings screen, toggle button title -->
-    <string name="location_time_zone_detection_toggle_title">Use location</string>
+    <string name="location_time_zone_detection_toggle_title">Use location for time zone</string>
     <!-- [CHAR LIMIT=50] Date&Time settings screen, title of the dialog when AutoTimeZone is degraded -->
     <string name="location_time_zone_detection_status_title">Cannot set the time zone automatically</string>
     <!-- Date&Time settings screen, summary of the dialog when AutoTimeZone is degraded by settings-->
@@ -3800,7 +3804,7 @@
     <!-- [CHAR LIMIT=NONE] Location settings screen, summary when location time zone detection is not
          applicable due to other settings like the "automatic time zone detection enabled" setting
          being set to "off". -->
-    <string name="location_time_zone_detection_auto_is_off">Automatic time zone is off</string>
+    <string name="location_time_zone_detection_auto_is_off">Not available when automatic time zone is off</string>
     <!-- [CHAR LIMIT=NONE] Location settings screen, summary when location time zone detection is not
          applicable for the user for unspecified reasons. More specific messages are used when there
          is a clear reason. -->
@@ -3811,7 +3815,7 @@
          allowed for the user, e.g. because of device policy -->
     <string name="location_time_zone_detection_not_allowed">Location time zone detection changes are not allowed</string>
     <!-- [CHAR LIMIT=NONE] Location settings screen, summary when location time zone detection is enabled. -->
-    <string name="location_time_zone_detection_auto_is_on">Location may be used to set time zone</string>
+    <string name="location_time_zone_detection_auto_is_on">If your device location is available, it may be used to set your time zone</string>
     <!-- Main settings screen, setting summary for the user to go into the About phone screen-->
     <string name="about_settings_summary">View legal info, status, software version</string>
     <!-- About phone settings screen, setting option name to go to dialog that shows legal info -->
@@ -8653,6 +8657,13 @@
     <!-- Configure Notifications: Title for the option controlling notifications for work profile. [CHAR LIMIT=30] -->
     <string name="locked_work_profile_notification_title">When work profile is locked</string>
 
+    <!-- Configure notifications: Title for the option controlling whether or not to minimalize the
+    number of notifications to show on the lock screen[CHAR LIMIT=60] -->
+    <string name="lock_screen_notif_minimalism">Lock screen notification minimalism</string>
+
+    <!-- Configure notifications: Summary for option lock_screen_notif_minimalism. [CHAR LIMIT=100] -->
+    <string name="lock_screen_notif_minimalism_summary">Show fewer notifications on lock screen</string>
+
     <!-- Configure notifications: Title for the option controlling whether only new notifications are displayed to the user
     on the lock screen [CHAR LIMIT=60] -->
     <string name="unseen_notifs_lock_screen">Show only new notifications on lock screen</string>
@@ -9581,6 +9592,9 @@
     <!-- Modes: Hint for the EditText for editing a mode's name [CHAR LIMIT=30] -->
     <string name="zen_mode_edit_name_hint">Mode name</string>
 
+    <!-- Modes: Text shown above the list of icons in the mode editor. [CHAR LIMIT=40] -->
+    <string name="zen_mode_edit_choose_icon_title">Choose an icon</string>
+
     <!-- Modes: Trigger title for modes of type SCHEDULE_CALENDAR. [CHAR LIMIT=30] -->
     <string name="zen_mode_trigger_title_schedule_calendar">Calendar events</string>
     <!-- Modes: Trigger title for modes of type BEDTIME. [CHAR LIMIT=30] -->
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index b673a083..c88b7ba 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -136,8 +136,16 @@
         />
 
         <SwitchPreferenceCompat
-            android:key="lock_screen_show_only_unseen_notifs"
+            android:key="lock_screen_notif_minimalism"
             android:order="19"
+            android:title="@string/lock_screen_notif_minimalism"
+            android:summary="@string/lock_screen_notif_minimalism_summary"
+            settings:controller="com.android.settings.notification.LockscreenNotificationMinimalismPreferenceController"
+            />
+
+        <SwitchPreferenceCompat
+            android:key="lock_screen_show_only_unseen_notifs"
+            android:order="20"
             android:title="@string/unseen_notifs_lock_screen"
             android:summary="@string/unseen_notifs_lock_screen_summary"
             settings:controller="com.android.settings.notification.ShowOnlyUnseenNotificationsOnLockscreenPreferenceController"
@@ -146,7 +154,7 @@
         <Preference
             android:fragment="com.android.settings.accessibility.FlashNotificationsPreferenceFragment"
             android:key="flash_notifications_preference"
-            android:order="20"
+            android:order="21"
             android:persistent="false"
             android:title="@string/flash_notifications_title"
             settings:searchable="false"
@@ -154,7 +162,7 @@
 
         <com.android.settingslib.RestrictedPreference
             android:key="app_and_notif_cell_broadcast_settings"
-            android:order="21"
+            android:order="22"
             android:title="@string/cell_broadcast_settings"
             settings:useAdminDisabledSummary="true">
             <intent
@@ -165,33 +173,33 @@
 
         <SwitchPreferenceCompat
              android:key="silent_icons"
-             android:order="22"
+             android:order="23"
              android:title="@string/silent_notifications_status_bar"
              settings:controller="com.android.settings.notification.SilentStatusBarPreferenceController"/>
 
         <SwitchPreferenceCompat
             android:key="show_snooze_options"
-            android:order="23"
+            android:order="24"
             android:title="@string/snooze_options_title"
             settings:controller="com.android.settings.notification.SnoozeNotificationPreferenceController" />
 
         <!-- Notification badging -->
         <SwitchPreferenceCompat
             android:key="notification_badging"
-            android:order="24"
+            android:order="25"
             android:title="@string/notification_badging_title"
             settings:controller="com.android.settings.notification.BadgingNotificationPreferenceController"/>
 
         <!-- Pulse notification light, on devices that support it -->
         <SwitchPreferenceCompat
             android:key="notification_pulse"
-            android:order="25"
+            android:order="26"
             android:title="@string/notification_pulse_title"
             settings:controller="com.android.settings.notification.PulseNotificationPreferenceController"/>
 
         <SwitchPreferenceCompat
             android:key="notification_assistant"
-            android:order="26"
+            android:order="27"
             android:title="@string/notification_assistant_title"
             android:summary="@string/notification_assistant_summary"
             settings:controller="com.android.settings.notification.NotificationAssistantPreferenceController"/>
diff --git a/res/xml/date_time_prefs.xml b/res/xml/date_time_prefs.xml
index 3fb4a06..d8643be 100644
--- a/res/xml/date_time_prefs.xml
+++ b/res/xml/date_time_prefs.xml
@@ -23,7 +23,7 @@
     <com.android.settingslib.RestrictedSwitchPreference
         android:key="auto_time"
         android:title="@string/date_time_auto"
-        settings:useAdditionalSummary="true"
+        android:summary="@string/summary_placeholder"
         settings:userRestriction="no_config_date_time"
         settings:controller="com.android.settings.datetime.AutoTimePreferenceController" />
 
@@ -48,6 +48,7 @@
         <com.android.settingslib.RestrictedSwitchPreference
             android:key="auto_zone"
             android:title="@string/zone_auto_title"
+            android:summary="@string/summary_placeholder"
             settings:userRestriction="no_config_date_time"
             settings:controller="com.android.settings.datetime.AutoTimeZonePreferenceController" />
 
@@ -60,6 +61,7 @@
         <SwitchPreferenceCompat
             android:key="location_time_zone_detection"
             android:title="@string/location_time_zone_detection_toggle_title"
+            android:summary="@string/summary_placeholder"
             settings:controller="com.android.settings.datetime.LocationTimeZoneDetectionPreferenceController"/>
 
         <com.android.settingslib.RestrictedPreference
diff --git a/res/xml/modes_edit_name_icon.xml b/res/xml/modes_edit_name_icon.xml
index 2109c77..4bcf67d 100644
--- a/res/xml/modes_edit_name_icon.xml
+++ b/res/xml/modes_edit_name_icon.xml
@@ -33,13 +33,15 @@
         android:key="name"
         android:layout="@layout/modes_edit_name" />
 
-    <com.android.settings.applications.SpacePreference
-        android:layout_height="32dp" />
+    <PreferenceCategory
+        android:title="@string/zen_mode_edit_choose_icon_title"
+        android:key="modes_filters">
 
-    <com.android.settingslib.widget.LayoutPreference
-        android:key="icon_list"
-        android:selectable="false"
-        android:layout="@layout/modes_icon_list"/>
+        <com.android.settingslib.widget.LayoutPreference
+            android:key="icon_list"
+            android:selectable="false"
+            android:layout="@layout/modes_icon_list" />
+    </PreferenceCategory>
 
     <com.android.settingslib.widget.LayoutPreference
         android:key="done"
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index 7e8969d..d0fe980 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -60,7 +60,7 @@
 
     <Preference
         android:key="zen_access"
-        android:title="@string/manage_zen_access_title"
+        android:title="@string/manage_zen_modes_access_title"
         android:order="-1500"
         android:fragment="com.android.settings.notification.zen.ZenAccessSettings"
         settings:controller="com.android.settings.applications.specialaccess.zenaccess.ZenAccessController" />
diff --git a/src/com/android/settings/SettingsInitialize.java b/src/com/android/settings/SettingsInitialize.java
index 4887e26..254ef8c 100644
--- a/src/com/android/settings/SettingsInitialize.java
+++ b/src/com/android/settings/SettingsInitialize.java
@@ -39,6 +39,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.activityembedding.ActivityEmbeddingUtils;
+import com.android.settings.core.instrumentation.ElapsedTimeUtils;
 import com.android.settings.homepage.DeepLinkHomepageActivity;
 import com.android.settings.search.SearchStateReceiver;
 import com.android.settingslib.utils.ThreadUtils;
@@ -69,6 +70,7 @@
         webviewSettingSetup(context, pm, userInfo);
         ThreadUtils.postOnBackgroundThread(() -> refreshExistingShortcuts(context));
         enableTwoPaneDeepLinkActivityIfNecessary(pm, context);
+        storeSuwCompleteTimestamp(context, broadcast);
     }
 
     private void managedProfileSetup(Context context, final PackageManager pm, Intent broadcast,
@@ -161,4 +163,10 @@
         pm.setComponentEnabledSetting(searchStateReceiver, enableState,
                 PackageManager.DONT_KILL_APP);
     }
+
+    private void storeSuwCompleteTimestamp(Context context, Intent broadcast) {
+        if (SetupWizardUtils.ACTION_SETUP_WIZARD_FINISHED.equals(broadcast.getAction())) {
+            ElapsedTimeUtils.storeSuwFinishedTimestamp(context, System.currentTimeMillis());
+        }
+    }
 }
diff --git a/src/com/android/settings/SetupWizardUtils.java b/src/com/android/settings/SetupWizardUtils.java
index 25e9159..57adeee 100644
--- a/src/com/android/settings/SetupWizardUtils.java
+++ b/src/com/android/settings/SetupWizardUtils.java
@@ -32,6 +32,9 @@
 
 public class SetupWizardUtils {
 
+    public static final String ACTION_SETUP_WIZARD_FINISHED =
+            "com.google.android.setupwizard.SETUP_WIZARD_FINISHED";
+
     public static String getThemeString(Intent intent) {
         String theme = intent.getStringExtra(WizardManagerHelper.EXTRA_THEME);
         if (theme == null) {
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 90d733e..1712e85 100644
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -715,7 +715,7 @@
         if (mPackageName == null) {
             final Intent intent = args == null ?
                     getActivity().getIntent() : (Intent) args.getParcelable("intent");
-            if (intent != null) {
+            if (intent != null && intent.getData() != null) {
                 mPackageName = intent.getData().getSchemeSpecificPart();
             }
         }
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 6c16d94..b837e1e 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -1034,6 +1034,9 @@
     }
 
     private void autoSetCollapsingToolbarLayoutScrolling() {
+        if (mAppBarLayout == null) {
+            return;
+        }
         final CoordinatorLayout.LayoutParams params =
                 (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
         final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
diff --git a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
index e3233ed..761a9c3 100644
--- a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
@@ -58,6 +58,7 @@
 import com.android.settings.biometrics.fingerprint2.domain.interactor.TouchEventInteractor
 import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor
 import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractorImpl
+import com.android.settings.biometrics.fingerprint2.domain.interactor.UserInteractorImpl
 import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
 import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractorImpl
 import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.AuthenitcateInteractor
@@ -67,6 +68,7 @@
 import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RemoveFingerprintInteractor
 import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RenameFingerprintInteractor
 import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor
+import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.UserInteractor
 import com.android.settings.biometrics.fingerprint2.lib.model.Settings
 import java.util.concurrent.Executors
 import kotlinx.coroutines.MainScope
@@ -97,11 +99,11 @@
         com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser
       )
     )
-  private val fingerprintEnrollmentRepository =
-    FingerprintEnrollmentRepositoryImpl(fingerprintManager, userRepo, fingerprintSettingsRepository,
-      backgroundDispatcher, applicationScope)
   private val fingerprintSensorRepository: FingerprintSensorRepository =
     FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, applicationScope)
+  private val fingerprintEnrollmentRepository =
+    FingerprintEnrollmentRepositoryImpl(fingerprintManager, userRepo, fingerprintSettingsRepository,
+      backgroundDispatcher, applicationScope, fingerprintSensorRepository)
   private val debuggingRepository: DebuggingRepository = DebuggingRepositoryImpl()
   private val udfpsDebugRepo = UdfpsEnrollDebugRepositoryImpl()
 
@@ -118,11 +120,13 @@
     EnrollFingerprintInteractorImpl(context.userId, fingerprintManager, Settings)
 
   fun createFingerprintsEnrolledInteractor(): EnrolledFingerprintsInteractorImpl =
-    EnrolledFingerprintsInteractorImpl(fingerprintManager, context.userId)
+    EnrolledFingerprintsInteractorImpl(fingerprintEnrollmentRepository)
 
   fun createAuthenticateInteractor(): AuthenitcateInteractor =
     AuthenticateInteractorImpl(fingerprintManager, context.userId)
 
+  fun createUserInteractor(): UserInteractor = UserInteractorImpl(userRepo)
+
   fun createRemoveFingerprintInteractor(): RemoveFingerprintInteractor =
     RemoveFingerprintsInteractorImpl(fingerprintManager, context.userId)
 
diff --git a/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt
index 22904e9..0bb4eea 100644
--- a/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt
@@ -23,14 +23,16 @@
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filterNotNull
-import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.withContext
 
 /** Repository that contains information about fingerprint enrollments. */
@@ -38,20 +40,31 @@
   /** The current enrollments of the user */
   val currentEnrollments: Flow<List<FingerprintData>?>
 
+  /** Indicates the maximum fingerprints that are enrollable * */
+  val maxFingerprintsEnrollable: Flow<Int>
+
   /** Indicates if a user can enroll another fingerprint */
   val canEnrollUser: Flow<Boolean>
 
-  fun maxFingerprintsEnrollable(): Int
+  /**
+   * Indicates if we should use the default settings for maximum enrollments or the sensor props
+   * from the fingerprint sensor
+   */
+  fun setShouldUseSettingsMaxFingerprints(useSettings: Boolean)
 }
 
 class FingerprintEnrollmentRepositoryImpl(
-  fingerprintManager: FingerprintManager,
+  private val fingerprintManager: FingerprintManager,
   userRepo: UserRepo,
-  private val settingsRepository: FingerprintSettingsRepository,
+  settingsRepository: FingerprintSettingsRepository,
   backgroundDispatcher: CoroutineDispatcher,
   applicationScope: CoroutineScope,
+  sensorRepo: FingerprintSensorRepository,
 ) : FingerprintEnrollmentRepository {
 
+  private val _shouldUseSettingsMaxFingerprints = MutableStateFlow(false)
+  val shouldUseSettingsMaxFingerprints = _shouldUseSettingsMaxFingerprints.asStateFlow()
+
   private val enrollmentChangedFlow: Flow<Int?> =
     callbackFlow {
         val callback =
@@ -72,27 +85,34 @@
   override val currentEnrollments: Flow<List<FingerprintData>> =
     userRepo.currentUser
       .distinctUntilChanged()
-      .flatMapLatest { currentUser ->
-        enrollmentChangedFlow.map { enrollmentChanged ->
-          if (enrollmentChanged == null || enrollmentChanged == currentUser) {
-            fingerprintManager
-              .getEnrolledFingerprints(currentUser)
-              ?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }
-              ?.toList()
-          } else {
-            null
-          }
-        }
-      }
+      .combine(enrollmentChangedFlow) { currentUser, _ -> getFingerprintsForUser(currentUser) }
       .filterNotNull()
       .flowOn(backgroundDispatcher)
 
-  override val canEnrollUser: Flow<Boolean> =
-    currentEnrollments.map {
-      it?.size?.let { it < settingsRepository.maxEnrollableFingerprints() } ?: false
+  override val maxFingerprintsEnrollable: Flow<Int> =
+    shouldUseSettingsMaxFingerprints.combine(sensorRepo.fingerprintSensor) {
+      shouldUseSettings,
+      sensor ->
+      if (shouldUseSettings) {
+        settingsRepository.maxEnrollableFingerprints()
+      } else {
+        sensor.maxEnrollmentsPerUser
+      }
     }
 
-  override fun maxFingerprintsEnrollable(): Int {
-    return settingsRepository.maxEnrollableFingerprints()
+  override val canEnrollUser: Flow<Boolean> =
+    currentEnrollments.combine(maxFingerprintsEnrollable) { enrollments, maxFingerprints ->
+      enrollments.size < maxFingerprints
+    }
+
+  override fun setShouldUseSettingsMaxFingerprints(useSettings: Boolean) {
+    _shouldUseSettingsMaxFingerprints.update { useSettings }
+  }
+
+  private fun getFingerprintsForUser(userId: Int): List<FingerprintData>? {
+    return fingerprintManager
+      .getEnrolledFingerprints(userId)
+      ?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }
+      ?.toList()
   }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint2/data/repository/UserRepo.kt b/src/com/android/settings/biometrics/fingerprint2/data/repository/UserRepo.kt
index 720e778..9126043 100644
--- a/src/com/android/settings/biometrics/fingerprint2/data/repository/UserRepo.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/data/repository/UserRepo.kt
@@ -17,7 +17,10 @@
 package com.android.settings.biometrics.fingerprint2.data.repository
 
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.update
 
 /**
  * A repository responsible for indicating the current user.
@@ -27,8 +30,18 @@
      * This flow indicates the current user.
      */
     val currentUser: Flow<Int>
+
+    /**
+     * Updates the current user.
+     */
+    fun updateUser(user: Int)
 }
 
-class UserRepoImpl(val currUser: Int): UserRepo {
-    override val currentUser: Flow<Int> = flowOf(currUser)
+class UserRepoImpl(currUser: Int): UserRepo {
+    private val _currentUser = MutableStateFlow(currUser)
+    override val currentUser = _currentUser.asStateFlow()
+
+    override fun updateUser(user: Int) {
+        _currentUser.update { user }
+    }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/CanEnrollFingerprintsInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/CanEnrollFingerprintsInteractorImpl.kt
index caeea4e..cfdfbe2 100644
--- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/CanEnrollFingerprintsInteractorImpl.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/CanEnrollFingerprintsInteractorImpl.kt
@@ -21,11 +21,14 @@
 import kotlinx.coroutines.flow.Flow
 
 class CanEnrollFingerprintsInteractorImpl(
-  val fingerprintEnrollmentRepository: FingerprintEnrollmentRepository
+  private val fingerprintEnrollmentRepository: FingerprintEnrollmentRepository
 ) : CanEnrollFingerprintsInteractor {
   override val canEnrollFingerprints: Flow<Boolean> = fingerprintEnrollmentRepository.canEnrollUser
   /** Indicates the maximum fingerprints enrollable for a given user */
-  override fun maxFingerprintsEnrollable(): Int {
-    return fingerprintEnrollmentRepository.maxFingerprintsEnrollable()
+  override val maxFingerprintsEnrollable: Flow<Int> =
+    fingerprintEnrollmentRepository.maxFingerprintsEnrollable
+
+  override fun setShouldUseSettingsMaxFingerprints(useSettings: Boolean) {
+    fingerprintEnrollmentRepository.setShouldUseSettingsMaxFingerprints(useSettings)
   }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrolledFingerprintsInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrolledFingerprintsInteractorImpl.kt
index 83b532e..f8bcaf7 100644
--- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrolledFingerprintsInteractorImpl.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrolledFingerprintsInteractorImpl.kt
@@ -16,22 +16,14 @@
 
 package com.android.settings.biometrics.fingerprint2.domain.interactor
 
-import android.hardware.fingerprint.FingerprintManager
+import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintEnrollmentRepository
 import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrolledFingerprintsInteractor
 import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
 
 class EnrolledFingerprintsInteractorImpl(
-  private val fingerprintManager: FingerprintManager,
-  userId: Int,
+  private val fingerprintEnrollmentRepository: FingerprintEnrollmentRepository
 ) : EnrolledFingerprintsInteractor {
-  override val enrolledFingerprints: Flow<List<FingerprintData>?> = flow {
-    emit(
-      fingerprintManager
-        .getEnrolledFingerprints(userId)
-        ?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }
-        ?.toList()
-    )
-  }
+  override val enrolledFingerprints: Flow<List<FingerprintData>?> =
+    fingerprintEnrollmentRepository.currentEnrollments
 }
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/UserInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/UserInteractorImpl.kt
new file mode 100644
index 0000000..506006e
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/UserInteractorImpl.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.fingerprint2.domain.interactor
+
+import com.android.settings.biometrics.fingerprint2.data.repository.UserRepo
+import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.UserInteractor
+import kotlinx.coroutines.flow.Flow
+
+class UserInteractorImpl(private val userRepo: UserRepo) : UserInteractor {
+  override val currentUser: Flow<Int> = userRepo.currentUser
+
+  override fun updateUser(user: Int) = userRepo.updateUser(user)
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/CanEnrollFingerprintsInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/CanEnrollFingerprintsInteractor.kt
index 11a9258..a5277a5 100644
--- a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/CanEnrollFingerprintsInteractor.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/CanEnrollFingerprintsInteractor.kt
@@ -23,5 +23,17 @@
   /** Returns true if a user can enroll a fingerprint false otherwise. */
   val canEnrollFingerprints: Flow<Boolean>
   /** Indicates the maximum fingerprints enrollable for a given user */
-  fun maxFingerprintsEnrollable(): Int
+  val maxFingerprintsEnrollable: Flow<Int>
+
+  /**
+   * Indicates if we should use the default settings for maximum enrollments or the sensor props
+   * from the fingerprint sensor. This can be useful if you are supporting HIDL & AIDL enrollment
+   * types from one code base. Prior to AIDL there was no way to determine how many
+   * fingerprints were enrollable, Settings relied on
+   * com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser.
+   *
+   * Typically Fingerprints with AIDL HAL's should not use this
+   * (setShouldUseSettingsMaxFingerprints(false))
+   */
+  fun setShouldUseSettingsMaxFingerprints(useSettings: Boolean)
 }
diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/UserInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/UserInteractor.kt
new file mode 100644
index 0000000..17b147a
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/UserInteractor.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.fingerprint2.lib.domain.interactor
+
+import kotlinx.coroutines.flow.Flow
+
+interface UserInteractor {
+    /**
+     * This flow indicates the current user.
+     */
+    val currentUser: Flow<Int>
+
+    /**
+     * Updates the current user.
+     */
+    fun updateUser(user: Int)
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt
index c306c78..7aad16d 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt
@@ -43,7 +43,6 @@
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.sample
-import kotlinx.coroutines.flow.transform
 import kotlinx.coroutines.flow.transformLatest
 import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
@@ -72,10 +71,12 @@
 
   /** Represents the stream of the information of "Add Fingerprint" preference. */
   val addFingerprintPrefInfo: Flow<Pair<Boolean, Int>> =
-    _enrolledFingerprints.filterOnlyWhenSettingsIsShown().combine(
-      canEnrollFingerprintsInteractor.canEnrollFingerprints
-    ) { _, canEnrollFingerprints ->
-      Pair(canEnrollFingerprints, canEnrollFingerprintsInteractor.maxFingerprintsEnrollable())
+    combine(
+      _enrolledFingerprints.filterOnlyWhenSettingsIsShown(),
+      canEnrollFingerprintsInteractor.canEnrollFingerprints,
+      canEnrollFingerprintsInteractor.maxFingerprintsEnrollable,
+    ) { _, canEnrollFingerprints, maxFingerprints ->
+      Pair(canEnrollFingerprints, maxFingerprints)
     }
 
   /** Represents the stream of visibility of sfps preference. */
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
index 2c65934..387bf83 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
@@ -31,15 +31,12 @@
 import android.os.Looper;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.TextView;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
-import androidx.appcompat.app.AlertDialog;
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
@@ -71,8 +68,9 @@
     private volatile BluetoothDevice mJustBonded = null;
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+    @VisibleForTesting
     @Nullable
-    private AlertDialog mProgressDialog = null;
+    ProgressDialogFragment mProgressDialog = null;
     @VisibleForTesting
     boolean mShouldTriggerAudioSharingShareThenPairFlow = false;
     private CopyOnWriteArrayList<BluetoothDevice> mDevicesWithMetadataChangedListener =
@@ -384,41 +382,24 @@
         finish();
     }
 
-    // TODO: use DialogFragment
     private void showConnectingDialog(@NonNull String deviceName) {
         postOnMainThread(() -> {
             String message = getContext().getString(R.string.progress_dialog_connect_device_content,
                     deviceName);
+            if (mProgressDialog == null) {
+                mProgressDialog = ProgressDialogFragment.newInstance(this);
+            }
             if (mProgressDialog != null) {
-                Log.d(getLogTag(), "showConnectingDialog, is already showing");
-                TextView textView = mProgressDialog.findViewById(R.id.message);
-                if (textView != null && !message.equals(textView.getText().toString())) {
-                    Log.d(getLogTag(), "showConnectingDialog, update message");
-                    textView.setText(message);
-                }
-                return;
+                mProgressDialog.show(message);
             }
-            Log.d(getLogTag(), "showConnectingDialog, show dialog");
-            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-            LayoutInflater inflater = LayoutInflater.from(builder.getContext());
-            View customView = inflater.inflate(
-                    R.layout.dialog_audio_sharing_progress, /* root= */
-                    null);
-            TextView textView = customView.findViewById(R.id.message);
-            if (textView != null) {
-                textView.setText(message);
-            }
-            AlertDialog dialog = builder.setView(customView).setCancelable(false).create();
-            dialog.setCanceledOnTouchOutside(false);
-            mProgressDialog = dialog;
-            dialog.show();
         });
     }
 
     private void dismissConnectingDialog() {
         postOnMainThread(() -> {
             if (mProgressDialog != null) {
-                mProgressDialog.dismiss();
+                Log.d(getLogTag(), "Dismiss connecting dialog.");
+                mProgressDialog.dismissAllowingStateLoss();
             }
         });
     }
diff --git a/src/com/android/settings/bluetooth/ProgressDialogFragment.java b/src/com/android/settings/bluetooth/ProgressDialogFragment.java
new file mode 100644
index 0000000..15d5329
--- /dev/null
+++ b/src/com/android/settings/bluetooth/ProgressDialogFragment.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.Lifecycle;
+
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+import com.google.common.base.Strings;
+
+public class ProgressDialogFragment extends InstrumentedDialogFragment {
+    private static final String TAG = "BTProgressDialog";
+
+    private static final String BUNDLE_KEY_MESSAGE = "bundle_key_message";
+
+    @Nullable private static FragmentManager sManager;
+    @Nullable private static Lifecycle sLifecycle;
+    private String mMessage = "";
+    @Nullable private AlertDialog mAlertDialog;
+
+    @Override
+    public int getMetricsCategory() {
+        // TODO: add metrics
+        return 0;
+    }
+
+    /**
+     * Returns a new instance of {@link ProgressDialogFragment} dialog.
+     *
+     * @param host The Fragment this dialog will be hosted.
+     */
+    @Nullable
+    public static ProgressDialogFragment newInstance(@Nullable Fragment host) {
+        if (host == null) return null;
+        try {
+            sManager = host.getChildFragmentManager();
+            sLifecycle = host.getLifecycle();
+        } catch (IllegalStateException e) {
+            Log.d(TAG, "Fail to create new instance: " + e.getMessage());
+            return null;
+        }
+        return new ProgressDialogFragment();
+    }
+
+    /**
+     * Display {@link ProgressDialogFragment} dialog.
+     *
+     * @param message The message to be shown on the dialog
+     */
+    public void show(@NonNull String message) {
+        if (sManager == null) return;
+        Lifecycle.State currentState = sLifecycle == null ? null : sLifecycle.getCurrentState();
+        if (currentState == null || !currentState.isAtLeast(Lifecycle.State.STARTED)) {
+            Log.d(TAG, "Fail to show dialog with state: " + currentState);
+            return;
+        }
+        if (mAlertDialog != null && mAlertDialog.isShowing()) {
+            if (!mMessage.equals(message)) {
+                Log.d(TAG, "Update dialog message.");
+                TextView messageView = mAlertDialog.findViewById(R.id.message);
+                if (messageView != null) {
+                    messageView.setText(message);
+                }
+                mMessage = message;
+            }
+            Log.d(TAG, "Dialog is showing, return.");
+            return;
+        }
+        mMessage = message;
+        Log.d(TAG, "Show up the progress dialog.");
+        Bundle args = new Bundle();
+        args.putString(BUNDLE_KEY_MESSAGE, message);
+        setArguments(args);
+        show(sManager, TAG);
+    }
+
+    /** Returns the current message on the dialog. */
+    @VisibleForTesting
+    @NonNull
+    public String getMessage() {
+        return mMessage;
+    }
+
+    private ProgressDialogFragment() {
+    }
+
+    @Override
+    @NonNull
+    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+        Bundle args = requireArguments();
+        String message = args.getString(BUNDLE_KEY_MESSAGE, "");
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        LayoutInflater inflater = LayoutInflater.from(builder.getContext());
+        View customView = inflater.inflate(
+                R.layout.dialog_audio_sharing_progress, /* root= */ null);
+        TextView textView = customView.findViewById(R.id.message);
+        if (textView != null && !Strings.isNullOrEmpty(message)) {
+            textView.setText(message);
+        }
+        AlertDialog dialog = builder.setView(customView).setCancelable(false).create();
+        dialog.setCanceledOnTouchOutside(false);
+        mAlertDialog = dialog;
+        return dialog;
+    }
+}
diff --git a/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt b/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt
index f6e6f16..b16bff1 100644
--- a/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt
+++ b/src/com/android/settings/bluetooth/ui/model/DeviceSettingPreferenceModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.settings.bluetooth.ui.model
 
+import android.content.Intent
 import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
 import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
 import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
@@ -31,7 +32,7 @@
         val title: String,
         val summary: String? = null,
         val icon: DeviceSettingIcon? = null,
-        val onClick: (() -> Unit)? = null,
+        val intent: Intent? = null,
     ) : DeviceSettingPreferenceModel
 
     /** Models a switch preference. */
@@ -42,7 +43,7 @@
         val icon: DeviceSettingIcon? = null,
         val checked: Boolean,
         val onCheckedChange: ((Boolean) -> Unit),
-        val onPrimaryClick: (() -> Unit)? = null,
+        val intent: Intent? = null,
     ) : DeviceSettingPreferenceModel
 
     /** Models a multi-toggle preference. */
@@ -71,6 +72,6 @@
     data class HelpPreference(
         @DeviceSettingId override val id: Int,
         val icon: DeviceSettingIcon,
-        val onClick: (() -> Unit),
+        val intent: Intent,
     ) : DeviceSettingPreferenceModel
 }
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
index a5997e7..ecd700b 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothAdapter
 import android.content.Context
+import android.content.Intent
 import android.media.AudioManager
 import android.os.Bundle
 import androidx.compose.animation.AnimatedVisibility
@@ -101,13 +102,13 @@
 ) : DeviceDetailsFragmentFormatter {
     private val repository =
         featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
-            context,
+            fragment.requireActivity().application,
             bluetoothAdapter,
             fragment.lifecycleScope,
         )
     private val spatialAudioInteractor =
         featureFactory.bluetoothFeatureProvider.getSpatialAudioInteractor(
-            context,
+            fragment.requireActivity().application,
             context.getSystemService(AudioManager::class.java),
             fragment.lifecycleScope,
         )
@@ -312,10 +313,10 @@
                         return { deviceSettingIcon(model.icon) }
                     }
             }
-        if (model.onPrimaryClick != null) {
+        if (model.intent != null) {
             TwoTargetSwitchPreference(
                 switchPrefModel,
-                primaryOnClick = model.onPrimaryClick::invoke,
+                primaryOnClick = { startActivity(model.intent) },
             )
         } else {
             SwitchPreference(switchPrefModel)
@@ -329,7 +330,7 @@
                 override val title = model.title
                 override val summary = { model.summary ?: "" }
                 override val onClick = {
-                    model.onClick?.invoke()
+                    model.intent?.let { startActivity(it) }
                     Unit
                 }
                 override val icon: (@Composable () -> Unit)?
@@ -361,7 +362,12 @@
                         )
                         .launch()
                 }
-                override val icon = @Composable { deviceSettingIcon(null) }
+                override val icon =
+                    @Composable {
+                        deviceSettingIcon(
+                            DeviceSettingIcon.ResourceIcon(R.drawable.ic_chevron_right_24dp)
+                        )
+                    }
             }
         )
     }
@@ -376,6 +382,11 @@
         icon?.let { Icon(it, modifier = Modifier.size(SettingsDimension.itemIconSize)) }
     }
 
+    private fun startActivity(intent: Intent) {
+        intent.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+        context.startActivity(intent)
+    }
+
     private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"
 
     companion object {
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
index 885516e..7cb1c0d 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
@@ -16,9 +16,11 @@
 
 package com.android.settings.bluetooth.ui.view
 
+import android.app.settings.SettingsEnums
 import android.bluetooth.BluetoothDevice
 import android.bluetooth.BluetoothManager
 import android.content.Context
+import android.content.Intent
 import android.graphics.PorterDuff
 import android.os.Bundle
 import android.view.Menu
@@ -49,8 +51,7 @@
     private lateinit var cachedDevice: CachedBluetoothDevice
     private lateinit var helpItem: StateFlow<DeviceSettingPreferenceModel.HelpPreference?>
 
-    // TODO(b/343317785): add metrics category
-    override fun getMetricsCategory(): Int = 0
+    override fun getMetricsCategory(): Int = SettingsEnums.BLUETOOTH_DEVICE_DETAILS_MORE_SETTINGS
 
     override fun onPrepareOptionsMenu(menu: Menu) {
         super.onPrepareOptionsMenu(menu)
@@ -74,7 +75,10 @@
 
     override fun onOptionsItemSelected(menuItem: MenuItem): Boolean {
         if (menuItem.itemId == MENU_HELP_ITEM_ID) {
-            helpItem.value?.let { it.onClick() }
+            helpItem.value?.intent?.let {
+                it.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                requireContext().startActivity(it)
+            }
             return true
         }
         return super.onOptionsItemSelected(menuItem)
diff --git a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
index 67a0ebc..fe66cb5 100644
--- a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
+++ b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
@@ -101,7 +101,7 @@
                                 DeviceSettingStateModel.ActionSwitchPreferenceState(newState)
                             )
                         },
-                        onPrimaryClick = { intent?.let { application.startActivity(it) } },
+                        intent = intent,
                     )
                 } else {
                     DeviceSettingPreferenceModel.PlainPreference(
@@ -109,7 +109,7 @@
                         title = title,
                         summary = summary,
                         icon = icon,
-                        onClick = { intent?.let { application.startActivity(it) } },
+                        intent = intent,
                     )
                 }
             }
@@ -119,7 +119,7 @@
                 DeviceSettingPreferenceModel.HelpPreference(
                     id = id,
                     icon = DeviceSettingIcon.ResourceIcon(R.drawable.ic_help),
-                    onClick = { application.startActivity(intent) },
+                    intent = intent,
                 )
             is DeviceSettingModel.MultiTogglePreference ->
                 DeviceSettingPreferenceModel.MultiTogglePreference(
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
index 1b68eac..54a758c 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFragment.java
@@ -31,6 +31,7 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.Lifecycle;
 
 import com.android.settings.R;
 import com.android.settings.bluetooth.BluetoothPairingDetail;
@@ -95,6 +96,11 @@
             Log.d(TAG, "Fail to show dialog: " + e.getMessage());
             return;
         }
+        Lifecycle.State currentState = host.getLifecycle().getCurrentState();
+        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+            Log.d(TAG, "Fail to show dialog with state: " + currentState);
+            return;
+        }
         sHost = host;
         sListener = listener;
         sEventData = eventData;
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
index 7d91644..fbd2e63 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
@@ -28,6 +28,7 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.Lifecycle;
 
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
@@ -92,6 +93,11 @@
             Log.d(TAG, "Fail to show dialog: " + e.getMessage());
             return;
         }
+        Lifecycle.State currentState = host.getLifecycle().getCurrentState();
+        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+            Log.d(TAG, "Fail to show dialog with state: " + currentState);
+            return;
+        }
         AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
         if (dialog != null) {
             int newGroupId = BluetoothUtils.getGroupId(newDevice);
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java
index e842b37..94d4a69 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingErrorDialogFragment.java
@@ -25,6 +25,7 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.Lifecycle;
 
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
@@ -53,6 +54,11 @@
             Log.d(TAG, "Fail to show dialog: " + e.getMessage());
             return;
         }
+        Lifecycle.State currentState = host.getLifecycle().getCurrentState();
+        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+            Log.d(TAG, "Fail to show dialog with state: " + currentState);
+            return;
+        }
         AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
         if (dialog != null) {
             Log.d(TAG, "Dialog is showing, return.");
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragment.java
index a8ad70b..e8ab716 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingIncompatibleDialogFragment.java
@@ -26,6 +26,7 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.Lifecycle;
 
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
@@ -69,6 +70,11 @@
             Log.d(TAG, "Fail to show dialog: " + e.getMessage());
             return;
         }
+        Lifecycle.State currentState = host.getLifecycle().getCurrentState();
+        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+            Log.d(TAG, "Fail to show dialog with state: " + currentState);
+            return;
+        }
         sListener = listener;
         AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
         if (dialog != null) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
index ef461eb..a952c48 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
@@ -28,6 +28,7 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.Lifecycle;
 
 import com.android.settings.R;
 import com.android.settings.bluetooth.Utils;
@@ -89,6 +90,11 @@
             Log.d(TAG, "Fail to show dialog: " + e.getMessage());
             return;
         }
+        Lifecycle.State currentState = host.getLifecycle().getCurrentState();
+        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+            Log.d(TAG, "Fail to show dialog with state: " + currentState);
+            return;
+        }
         sListener = listener;
         sNewDevice = newDevice;
         sEventData = eventData;
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragment.java
index 53bfcf8..840c7bb 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingProgressDialogFragment.java
@@ -31,6 +31,7 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.Lifecycle;
 
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
@@ -72,6 +73,11 @@
             Log.d(TAG, "Fail to show dialog: " + e.getMessage());
             return;
         }
+        Lifecycle.State currentState = host.getLifecycle().getCurrentState();
+        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+            Log.d(TAG, "Fail to show dialog with state: " + currentState);
+            return;
+        }
         AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
         if (dialog != null) {
             if (!sMessage.equals(message)) {
@@ -80,6 +86,7 @@
                 if (messageView != null) {
                     messageView.setText(message);
                 }
+                sMessage = message;
             }
             Log.d(TAG, "Dialog is showing, return.");
             return;
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
index 5b71f51..2bd79c9 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
@@ -28,6 +28,7 @@
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.Lifecycle;
 
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
@@ -89,6 +90,11 @@
             Log.d(TAG, "Fail to show dialog: " + e.getMessage());
             return;
         }
+        Lifecycle.State currentState = host.getLifecycle().getCurrentState();
+        if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+            Log.d(TAG, "Fail to show dialog with state: " + currentState);
+            return;
+        }
         AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
         if (dialog != null) {
             int newGroupId = BluetoothUtils.getGroupId(newDevice);
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
index b91a1f1..14da750 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
@@ -767,7 +767,7 @@
                     && !(fragment instanceof AudioSharingErrorDialogFragment)
                     && ((DialogFragment) fragment).getDialog() != null) {
                 Log.d(TAG, "Remove stale dialog = " + fragment.getTag());
-                ((DialogFragment) fragment).dismiss();
+                ((DialogFragment) fragment).dismissAllowingStateLoss();
             }
         }
     }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java
index d5be2bb..d1af8d9 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaService.java
@@ -106,7 +106,7 @@
     // If the initial volume from `onDeviceVolumeChanged` is larger than zero (not muted), we will
     // override this value. Otherwise, we raise the volume to 25 when the play button is clicked.
     private final AtomicInteger mLatestPositiveVolume = new AtomicInteger(25);
-    private final AtomicBoolean mHasStopped = new AtomicBoolean(false);
+    private final Object mLocalSessionLock = new Object();
     private int mBroadcastId;
     @Nullable private List<BluetoothDevice> mDevices;
     @Nullable private LocalBluetoothManager mLocalBtManager;
@@ -125,7 +125,7 @@
         if (!BluetoothUtils.isAudioSharingEnabled()) {
             return;
         }
-
+        Log.d(TAG, "onCreate()");
         super.onCreate();
         mLocalBtManager = Utils.getLocalBtManager(this);
         if (mLocalBtManager == null) {
@@ -146,26 +146,35 @@
             return;
         }
 
-        if (mNotificationManager.getNotificationChannel(CHANNEL_ID) == null) {
-            NotificationChannel notificationChannel =
-                    new NotificationChannel(
-                            CHANNEL_ID,
-                            getString(com.android.settings.R.string.bluetooth),
-                            NotificationManager.IMPORTANCE_HIGH);
-            mNotificationManager.createNotificationChannel(notificationChannel);
-        }
+        mExecutor.execute(
+                () -> {
+                    if (mLocalBtManager == null
+                            || mLeBroadcastAssistant == null
+                            || mNotificationManager == null) {
+                        return;
+                    }
+                    if (mNotificationManager.getNotificationChannel(CHANNEL_ID) == null) {
+                        NotificationChannel notificationChannel =
+                                new NotificationChannel(
+                                        CHANNEL_ID,
+                                        getString(com.android.settings.R.string.bluetooth),
+                                        NotificationManager.IMPORTANCE_HIGH);
+                        mNotificationManager.createNotificationChannel(notificationChannel);
+                    }
 
-        mBluetoothCallback = new BtCallback();
-        mLocalBtManager.getEventManager().registerCallback(mBluetoothCallback);
+                    mBluetoothCallback = new BtCallback();
+                    mLocalBtManager.getEventManager().registerCallback(mBluetoothCallback);
 
-        mVolumeControl = mLocalBtManager.getProfileManager().getVolumeControlProfile();
-        if (mVolumeControl != null) {
-            mVolumeControlCallback = new VolumeControlCallback();
-            mVolumeControl.registerCallback(mExecutor, mVolumeControlCallback);
-        }
+                    mVolumeControl = mLocalBtManager.getProfileManager().getVolumeControlProfile();
+                    if (mVolumeControl != null) {
+                        mVolumeControlCallback = new VolumeControlCallback();
+                        mVolumeControl.registerCallback(mExecutor, mVolumeControlCallback);
+                    }
 
-        mBroadcastAssistantCallback = new AssistantCallback();
-        mLeBroadcastAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
+                    mBroadcastAssistantCallback = new AssistantCallback();
+                    mLeBroadcastAssistant.registerServiceCallBack(
+                            mExecutor, mBroadcastAssistantCallback);
+                });
     }
 
     @Override
@@ -175,19 +184,29 @@
         if (!BluetoothUtils.isAudioSharingEnabled()) {
             return;
         }
-        if (mLocalBtManager != null) {
-            mLocalBtManager.getEventManager().unregisterCallback(mBluetoothCallback);
+        if (mDevices != null) {
+            mDevices.clear();
+            mDevices = null;
         }
-        if (mLeBroadcastAssistant != null && mBroadcastAssistantCallback != null) {
-            mLeBroadcastAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
+        synchronized (mLocalSessionLock) {
+            if (mLocalSession != null) {
+                mLocalSession.release();
+                mLocalSession = null;
+            }
         }
-        if (mVolumeControl != null && mVolumeControlCallback != null) {
-            mVolumeControl.unregisterCallback(mVolumeControlCallback);
-        }
-        if (mLocalSession != null) {
-            mLocalSession.release();
-            mLocalSession = null;
-        }
+        mExecutor.execute(
+                () -> {
+                    if (mLocalBtManager != null) {
+                        mLocalBtManager.getEventManager().unregisterCallback(mBluetoothCallback);
+                    }
+                    if (mLeBroadcastAssistant != null && mBroadcastAssistantCallback != null) {
+                        mLeBroadcastAssistant.unregisterServiceCallBack(
+                                mBroadcastAssistantCallback);
+                    }
+                    if (mVolumeControl != null && mVolumeControlCallback != null) {
+                        mVolumeControl.unregisterCallback(mVolumeControlCallback);
+                    }
+                });
     }
 
     @Override
@@ -195,43 +214,45 @@
         Log.d(TAG, "onStartCommand()");
         if (intent == null) {
             Log.w(TAG, "Intent is null. Service will not start.");
-            mHasStopped.set(true);
             stopSelf();
             return START_NOT_STICKY;
         }
         mBroadcastId = intent.getIntExtra(BROADCAST_ID, -1);
         if (mBroadcastId == -1) {
             Log.w(TAG, "Invalid broadcast ID. Service will not start.");
-            mHasStopped.set(true);
             stopSelf();
             return START_NOT_STICKY;
         }
         var extra = intent.getParcelableArrayListExtra(DEVICES, BluetoothDevice.class);
         if (extra == null || extra.isEmpty()) {
             Log.w(TAG, "No device. Service will not start.");
-            mHasStopped.set(true);
             stopSelf();
             return START_NOT_STICKY;
         }
         mDevices = Collections.synchronizedList(extra);
-        createLocalMediaSession(intent.getStringExtra(BROADCAST_TITLE));
-        startForeground(NOTIFICATION_ID, buildNotification());
-        // Reset in case the service is previously stopped but not yet destroyed.
-        mHasStopped.set(false);
+        MediaSession.Token token =
+                getOrCreateLocalMediaSession(intent.getStringExtra(BROADCAST_TITLE));
+        startForeground(NOTIFICATION_ID, buildNotification(token));
         return START_NOT_STICKY;
     }
 
-    private void createLocalMediaSession(String title) {
-        mLocalSession = new MediaSession(this, TAG);
-        mLocalSession.setMetadata(
-                new MediaMetadata.Builder()
-                        .putString(MediaMetadata.METADATA_KEY_TITLE, title)
-                        .putLong(MediaMetadata.METADATA_KEY_DURATION, STATIC_PLAYBACK_DURATION)
-                        .build());
-        mLocalSession.setActive(true);
-        mLocalSession.setPlaybackState(getPlaybackState());
-        mMediaSessionCallback = new MediaSessionCallback();
-        mLocalSession.setCallback(mMediaSessionCallback);
+    private MediaSession.Token getOrCreateLocalMediaSession(String title) {
+        synchronized (mLocalSessionLock) {
+            if (mLocalSession != null) {
+                return mLocalSession.getSessionToken();
+            }
+            mLocalSession = new MediaSession(this, TAG);
+            mLocalSession.setMetadata(
+                    new MediaMetadata.Builder()
+                            .putString(MediaMetadata.METADATA_KEY_TITLE, title)
+                            .putLong(MediaMetadata.METADATA_KEY_DURATION, STATIC_PLAYBACK_DURATION)
+                            .build());
+            mLocalSession.setActive(true);
+            mLocalSession.setPlaybackState(getPlaybackState());
+            mMediaSessionCallback = new MediaSessionCallback();
+            mLocalSession.setCallback(mMediaSessionCallback);
+            return mLocalSession.getSessionToken();
+        }
     }
 
     private PlaybackState getPlaybackState() {
@@ -252,12 +273,9 @@
         return device != null ? device.getName() : DEFAULT_DEVICE_NAME;
     }
 
-    private Notification buildNotification() {
+    private Notification buildNotification(MediaSession.Token token) {
         String deviceName = getDeviceName();
-        Notification.MediaStyle mediaStyle =
-                new Notification.MediaStyle()
-                        .setMediaSession(
-                                mLocalSession != null ? mLocalSession.getSessionToken() : null);
+        Notification.MediaStyle mediaStyle = new Notification.MediaStyle().setMediaSession(token);
         if (deviceName != null && !deviceName.isEmpty()) {
             mediaStyle.setRemotePlaybackInfo(
                     deviceName, com.android.settingslib.R.drawable.ic_bt_le_audio, null);
@@ -291,20 +309,15 @@
         }
 
         private void handleRemoveSource() {
-            var unused =
-                    ThreadUtils.postOnBackgroundThread(
-                            () -> {
-                                List<BluetoothLeBroadcastReceiveState> connected =
-                                        mAudioStreamsHelper == null
-                                                ? emptyList()
-                                                : mAudioStreamsHelper.getAllConnectedSources();
-                                if (connected.stream()
-                                        .map(BluetoothLeBroadcastReceiveState::getBroadcastId)
-                                        .noneMatch(id -> id == mBroadcastId)) {
-                                    mHasStopped.set(true);
-                                    stopSelf();
-                                }
-                            });
+            List<BluetoothLeBroadcastReceiveState> connected =
+                    mAudioStreamsHelper == null
+                            ? emptyList()
+                            : mAudioStreamsHelper.getAllConnectedSources();
+            if (connected.stream()
+                    .map(BluetoothLeBroadcastReceiveState::getBroadcastId)
+                    .noneMatch(id -> id == mBroadcastId)) {
+                stopSelf();
+            }
         }
     }
 
@@ -326,7 +339,11 @@
                     mIsMuted.set(false);
                     mLatestPositiveVolume.set(volume);
                 }
-                updateNotification(getPlaybackState());
+                synchronized (mLocalSessionLock) {
+                    if (mLocalSession != null) {
+                        mLocalSession.setPlaybackState(getPlaybackState());
+                    }
+                }
             }
         }
     }
@@ -336,7 +353,6 @@
         public void onBluetoothStateChanged(int bluetoothState) {
             if (BluetoothAdapter.STATE_OFF == bluetoothState) {
                 Log.d(TAG, "onBluetoothStateChanged() : stopSelf");
-                mHasStopped.set(true);
                 stopSelf();
             }
         }
@@ -362,7 +378,6 @@
             }
             if (mDevices == null || mDevices.isEmpty()) {
                 Log.d(TAG, "onProfileConnectionStateChanged() : stopSelf");
-                mHasStopped.set(true);
                 stopSelf();
             }
         }
@@ -371,7 +386,11 @@
     private class MediaSessionCallback extends MediaSession.Callback {
         public void onSeekTo(long pos) {
             Log.d(TAG, "onSeekTo: " + pos);
-            updateNotification(getPlaybackState());
+            synchronized (mLocalSessionLock) {
+                if (mLocalSession != null) {
+                    mLocalSession.setPlaybackState(getPlaybackState());
+                }
+            }
         }
 
         @Override
@@ -425,18 +444,4 @@
                             });
         }
     }
-
-    private void updateNotification(PlaybackState playbackState) {
-        var unused =
-                ThreadUtils.postOnBackgroundThread(
-                        () -> {
-                            if (mLocalSession != null) {
-                                mLocalSession.setPlaybackState(playbackState);
-                                if (mNotificationManager != null && !mHasStopped.get()) {
-                                    mNotificationManager.notify(
-                                            NOTIFICATION_ID, buildNotification());
-                                }
-                            }
-                        });
-    }
 }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java
index c0d9162..7c1281f 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java
@@ -139,7 +139,6 @@
     }
 
     /** Retrieves a list of all LE broadcast receive states from active sinks. */
-    @VisibleForTesting
     public List<BluetoothLeBroadcastReceiveState> getAllConnectedSources() {
         if (mLeBroadcastAssistant == null) {
             Log.w(TAG, "getAllSources(): LeBroadcastAssistant is null!");
@@ -165,7 +164,6 @@
     }
 
     /** Retrieves LocalBluetoothLeBroadcastAssistant. */
-    @VisibleForTesting
     @Nullable
     public LocalBluetoothLeBroadcastAssistant getLeBroadcastAssistant() {
         return mLeBroadcastAssistant;
diff --git a/src/com/android/settings/datetime/AutoTimePreferenceController.java b/src/com/android/settings/datetime/AutoTimePreferenceController.java
index 2942acb..5b17e7e 100644
--- a/src/com/android/settings/datetime/AutoTimePreferenceController.java
+++ b/src/com/android/settings/datetime/AutoTimePreferenceController.java
@@ -27,6 +27,8 @@
 import android.app.time.TimeManager;
 import android.content.Context;
 
+import androidx.preference.Preference;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.core.TogglePreferenceController;
@@ -77,6 +79,17 @@
     }
 
     @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        refreshSummary(preference);
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return mContext.getString(R.string.date_time_auto_summary);
+    }
+
+    @Override
     public boolean isChecked() {
         return isEnabled();
     }
diff --git a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
index 8eccf31..2f06289 100644
--- a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
+++ b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
@@ -129,11 +129,11 @@
         // time zone must use location.
         if (LocationProviderStatusPreferenceController.hasLocationTimeZoneNoTelephonyFallback(
                 mTimeManager.getTimeZoneCapabilitiesAndConfig().getDetectorStatus())) {
-            return mContext.getResources().getString(R.string.auto_zone_requires_location_summary);
+            return mContext.getString(R.string.auto_zone_requires_location_summary);
         }
-        // If the user has a dedicated toggle to control location use, the summary can
-        // be empty because the use of location is explicit.
-        return "";
+
+        // If the user has a dedicated toggle to control location use, explain what it does.
+        return mContext.getString(R.string.zone_auto_title_summary);
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
index 3cb3025..c93b450 100644
--- a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
+++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
@@ -15,13 +15,16 @@
 
 import static android.Manifest.permission_group.LOCATION;
 
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.icu.text.RelativeDateTimeFormatter;
+import android.location.LocationManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
@@ -43,6 +46,8 @@
  * Preference controller that handles the display of apps that access locations.
  */
 public class RecentLocationAccessPreferenceController extends LocationBasePreferenceController {
+    private static final String TAG = RecentLocationAccessPreferenceController.class
+            .getSimpleName();
     public static final int MAX_APPS = 3;
     @VisibleForTesting
     RecentAppOpsAccess mRecentLocationApps;
@@ -51,7 +56,8 @@
     private boolean mShowSystem = false;
     private boolean mSystemSettingChanged = false;
 
-    private static class PackageEntryClickedListener implements
+    @VisibleForTesting
+    static class PackageEntryClickedListener implements
             Preference.OnPreferenceClickListener {
         private final Context mContext;
         private final String mPackage;
@@ -66,12 +72,28 @@
 
         @Override
         public boolean onPreferenceClick(Preference preference) {
-            final Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION);
-            intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
-            intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, LOCATION);
-            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackage);
-            intent.putExtra(Intent.EXTRA_USER, mUserHandle);
-            mContext.startActivity(intent);
+            if (mPackage.equals(mContext.getSystemService(LocationManager.class)
+                    .getExtraLocationControllerPackage())) {
+                try {
+                    mContext.startActivityAsUser(
+                            new Intent(Settings.ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS),
+                            mUserHandle);
+                } catch (ActivityNotFoundException e) {
+                    // In rare cases where location controller extra package is set, but
+                    // no activity exists to handle the location controller extra package settings
+                    // intent, log an error instead of crashing.
+                    Log.e(TAG, "No activity to handle "
+                            + "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS");
+                }
+            } else {
+                final Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION);
+                intent.setPackage(mContext.getPackageManager()
+                        .getPermissionControllerPackageName());
+                intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, LOCATION);
+                intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackage);
+                intent.putExtra(Intent.EXTRA_USER, mUserHandle);
+                mContext.startActivity(intent);
+            }
             return true;
         }
     }
diff --git a/src/com/android/settings/network/apn/ApnEditor.java b/src/com/android/settings/network/apn/ApnEditor.java
index d1b2f2f..dc9741d 100644
--- a/src/com/android/settings/network/apn/ApnEditor.java
+++ b/src/com/android/settings/network/apn/ApnEditor.java
@@ -198,6 +198,10 @@
     public static final String APN_TYPE_MCX = "mcx";
     /** APN type for XCAP */
     public static final String APN_TYPE_XCAP = "xcap";
+    /** APN type for OEM_PAID networks (Automotive PANS) */
+    public static final String APN_TYPE_OEM_PAID = "oem_paid";
+    /** APN type for OEM_PRIVATE networks (Automotive PANS) */
+    public static final String APN_TYPE_OEM_PRIVATE = "oem_private";
     /** Array of all APN types */
     public static final String[] APN_TYPES = {APN_TYPE_DEFAULT,
             APN_TYPE_MMS,
@@ -211,6 +215,14 @@
             APN_TYPE_EMERGENCY,
             APN_TYPE_MCX,
             APN_TYPE_XCAP,
+            APN_TYPE_OEM_PAID,
+            APN_TYPE_OEM_PRIVATE,
+    };
+
+    /** Array of APN types that are never user-editable */
+    private static final String[] ALWAYS_READ_ONLY_APN_TYPES = new String[] {
+        APN_TYPE_OEM_PAID,
+        APN_TYPE_OEM_PRIVATE,
     };
 
     /**
@@ -361,6 +373,18 @@
     }
 
     /**
+     * Fetch complete list of read only APN types.
+     *
+     * The list primarily comes from carrier config, but is also supplied by APN types which are
+     * always read only.
+     */
+    static String[] getReadOnlyApnTypes(PersistableBundle b) {
+        String[] carrierReadOnlyApnTypes = b.getStringArray(
+                CarrierConfigManager.KEY_READ_ONLY_APN_TYPES_STRING_ARRAY);
+        return ArrayUtils.concat(String.class, carrierReadOnlyApnTypes, ALWAYS_READ_ONLY_APN_TYPES);
+    }
+
+    /**
      * Enable ProxySubscriptionMgr with Lifecycle support for all controllers
      * live within this fragment
      */
@@ -1355,8 +1379,7 @@
         if (configManager != null) {
             final PersistableBundle b = configManager.getConfigForSubId(mSubId);
             if (b != null) {
-                mReadOnlyApnTypes = b.getStringArray(
-                        CarrierConfigManager.KEY_READ_ONLY_APN_TYPES_STRING_ARRAY);
+                mReadOnlyApnTypes = getReadOnlyApnTypes(b);
                 if (!ArrayUtils.isEmpty(mReadOnlyApnTypes)) {
                     Log.d(TAG,
                             "onCreate: read only APN type: " + Arrays.toString(mReadOnlyApnTypes));
diff --git a/src/com/android/settings/network/apn/ApnSettings.java b/src/com/android/settings/network/apn/ApnSettings.java
index 2debba1..0e3c3a4 100644
--- a/src/com/android/settings/network/apn/ApnSettings.java
+++ b/src/com/android/settings/network/apn/ApnSettings.java
@@ -135,8 +135,7 @@
         mHideImsApn = b.getBoolean(CarrierConfigManager.KEY_HIDE_IMS_APN_BOOL);
         mAllowAddingApns = b.getBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL);
         if (mAllowAddingApns) {
-            final String[] readOnlyApnTypes = b.getStringArray(
-                    CarrierConfigManager.KEY_READ_ONLY_APN_TYPES_STRING_ARRAY);
+            final String[] readOnlyApnTypes = ApnEditor.getReadOnlyApnTypes(b);
             // if no apn type can be edited, do not allow adding APNs
             if (ApnEditor.hasAllApns(readOnlyApnTypes)) {
                 Log.d(TAG, "not allowing adding APN because all APN types are read only");
diff --git a/src/com/android/settings/network/apn/ApnStatus.kt b/src/com/android/settings/network/apn/ApnStatus.kt
index 6492d39..68588bb 100644
--- a/src/com/android/settings/network/apn/ApnStatus.kt
+++ b/src/com/android/settings/network/apn/ApnStatus.kt
@@ -204,9 +204,7 @@
         CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL
     )
     val customizedConfig = CustomizedConfig(
-        readOnlyApnTypes = b.getStringArray(
-            CarrierConfigManager.KEY_READ_ONLY_APN_TYPES_STRING_ARRAY
-        )?.toList() ?: emptyList(),
+        readOnlyApnTypes = ApnEditor.getReadOnlyApnTypes(b)?.toList() ?: emptyList(),
         readOnlyApnFields = b.getStringArray(
             CarrierConfigManager.KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY
         )?.toList() ?: emptyList(),
diff --git a/src/com/android/settings/network/apn/ApnTypes.kt b/src/com/android/settings/network/apn/ApnTypes.kt
index b9bc480..4f84ac7 100644
--- a/src/com/android/settings/network/apn/ApnTypes.kt
+++ b/src/com/android/settings/network/apn/ApnTypes.kt
@@ -45,6 +45,8 @@
         ApnSetting.TYPE_VSIM_STRING,
         ApnSetting.TYPE_BIP_STRING,
         ApnSetting.TYPE_ENTERPRISE_STRING,
+        ApnSetting.TYPE_OEM_PAID_STRING,
+        ApnSetting.TYPE_OEM_PRIVATE_STRING,
     )
 
     private fun splitToList(apnType: String): List<String> {
diff --git a/src/com/android/settings/network/telephony/SubscriptionRepository.kt b/src/com/android/settings/network/telephony/SubscriptionRepository.kt
index 6b5b4cb..43bba07 100644
--- a/src/com/android/settings/network/telephony/SubscriptionRepository.kt
+++ b/src/com/android/settings/network/telephony/SubscriptionRepository.kt
@@ -23,11 +23,13 @@
 import androidx.lifecycle.LifecycleOwner
 import com.android.settings.network.SubscriptionUtil
 import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.callbackFlow
 import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -36,6 +38,8 @@
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.shareIn
 
 private const val TAG = "SubscriptionRepository"
 
@@ -132,20 +136,7 @@
     fun canDisablePhysicalSubscription() = subscriptionManager.canDisablePhysicalSubscription()
 
     /** Flow for subscriptions changes. */
-    fun subscriptionsChangedFlow() = callbackFlow {
-        val listener = object : SubscriptionManager.OnSubscriptionsChangedListener() {
-            override fun onSubscriptionsChanged() {
-                trySend(Unit)
-            }
-        }
-
-        subscriptionManager.addOnSubscriptionsChangedListener(
-            Dispatchers.Default.asExecutor(),
-            listener,
-        )
-
-        awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(listener) }
-    }.conflate().onEach { Log.d(TAG, "subscriptions changed") }.flowOn(Dispatchers.Default)
+    fun subscriptionsChangedFlow() = getSharedSubscriptionsChangedFlow(context)
 
     /** Flow of active subscription ids. */
     fun activeSubscriptionIdListFlow(): Flow<List<Int>> =
@@ -172,6 +163,57 @@
                 flowOf(null)
             }
         }
+
+    companion object {
+        private lateinit var SharedSubscriptionsChangedFlow: Flow<Unit>
+
+        private fun getSharedSubscriptionsChangedFlow(context: Context): Flow<Unit> {
+            if (!this::SharedSubscriptionsChangedFlow.isInitialized) {
+                SharedSubscriptionsChangedFlow =
+                    context.applicationContext
+                        .requireSubscriptionManager()
+                        .subscriptionsChangedFlow()
+                        .shareIn(
+                            scope = CoroutineScope(Dispatchers.Default),
+                            started = SharingStarted.WhileSubscribed(),
+                            replay = 1,
+                        )
+            }
+            return SharedSubscriptionsChangedFlow
+        }
+
+        /**
+         * Flow for subscriptions changes.
+         *
+         * Note: Even the SubscriptionManager.addOnSubscriptionsChangedListener's doc says the
+         * SubscriptionManager.OnSubscriptionsChangedListener.onSubscriptionsChanged() method will
+         * also be invoked once initially when calling it, there still case that the
+         * onSubscriptionsChanged() method is not invoked initially. For example, when the
+         * onSubscriptionsChanged event never happens before, on a device never ever has any
+         * subscriptions.
+         */
+        private fun SubscriptionManager.subscriptionsChangedFlow() =
+            callbackFlow {
+                    val listener =
+                        object : SubscriptionManager.OnSubscriptionsChangedListener() {
+                            override fun onSubscriptionsChanged() {
+                                trySend(Unit)
+                            }
+
+                            override fun onAddListenerFailed() {
+                                close()
+                            }
+                        }
+
+                    addOnSubscriptionsChangedListener(Dispatchers.Default.asExecutor(), listener)
+
+                    awaitClose { removeOnSubscriptionsChangedListener(listener) }
+                }
+                .onStart { emit(Unit) } // Ensure this flow is never empty
+                .conflate()
+                .onEach { Log.d(TAG, "subscriptions changed") }
+                .flowOn(Dispatchers.Default)
+    }
 }
 
 val Context.subscriptionManager: SubscriptionManager?
diff --git a/src/com/android/settings/notification/LockscreenNotificationMinimalismPreferenceController.java b/src/com/android/settings/notification/LockscreenNotificationMinimalismPreferenceController.java
new file mode 100644
index 0000000..7b48ba7
--- /dev/null
+++ b/src/com/android/settings/notification/LockscreenNotificationMinimalismPreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static android.provider.Settings.Secure.LOCK_SCREEN_NOTIFICATION_MINIMALISM;
+import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.server.notification.Flags;
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+public class LockscreenNotificationMinimalismPreferenceController
+        extends TogglePreferenceController {
+
+    @VisibleForTesting
+    static final int ON = 1;
+    @VisibleForTesting
+    static final int OFF = 0;
+
+    public LockscreenNotificationMinimalismPreferenceController(
+            Context context,
+            String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public boolean isChecked() {
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                LOCK_SCREEN_NOTIFICATION_MINIMALISM, ON) == ON;
+    }
+
+    @Override
+    public boolean setChecked(boolean isChecked) {
+        return Settings.Secure.putInt(mContext.getContentResolver(),
+                LOCK_SCREEN_NOTIFICATION_MINIMALISM, isChecked ? ON : OFF);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (!Flags.notificationMinimalism()) {
+            return CONDITIONALLY_UNAVAILABLE;
+        }
+        int lockScreenNotif = Settings.Secure.getInt(mContext.getContentResolver(),
+                LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
+        if (lockScreenNotif == 0) {
+            return DISABLED_DEPENDENT_SETTING;
+        }
+        return AVAILABLE;
+    }
+
+    @Override
+    public int getSliceHighlightMenuRes() {
+        return R.string.menu_key_notifications;
+    }
+}
diff --git a/src/com/android/settings/notification/ShowOnlyUnseenNotificationsOnLockscreenPreferenceController.java b/src/com/android/settings/notification/ShowOnlyUnseenNotificationsOnLockscreenPreferenceController.java
index a37e29d..9534483 100644
--- a/src/com/android/settings/notification/ShowOnlyUnseenNotificationsOnLockscreenPreferenceController.java
+++ b/src/com/android/settings/notification/ShowOnlyUnseenNotificationsOnLockscreenPreferenceController.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.notification;
 
+import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS;
 import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS;
 
 import android.content.Context;
@@ -23,6 +24,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.server.notification.Flags;
 import com.android.settings.R;
 import com.android.settings.core.TogglePreferenceController;
 
@@ -55,6 +57,13 @@
 
     @Override
     public int getAvailabilityStatus() {
+        if (Flags.notificationMinimalism()) {
+            if (!isNotifOnLockScreenEnabled()) {
+                return DISABLED_DEPENDENT_SETTING;
+            }
+            // We want to show the switch when the lock screen notification minimalism flag is on.
+            return AVAILABLE;
+        }
         int setting = Settings.Secure.getInt(mContext.getContentResolver(),
                 LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, UNSET);
         if (setting == UNSET) {
@@ -68,4 +77,9 @@
     public int getSliceHighlightMenuRes() {
         return R.string.menu_key_notifications;
     }
+
+    private boolean isNotifOnLockScreenEnabled() {
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) == 1;
+    }
 }
diff --git a/src/com/android/settings/sim/PreferredSimDialogFragment.java b/src/com/android/settings/sim/PreferredSimDialogFragment.java
index 96c0eb6..aa42f3c 100644
--- a/src/com/android/settings/sim/PreferredSimDialogFragment.java
+++ b/src/com/android/settings/sim/PreferredSimDialogFragment.java
@@ -21,10 +21,12 @@
 import android.app.Activity;
 import android.app.Dialog;
 import android.app.settings.SettingsEnums;
+import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Bundle;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -91,8 +93,12 @@
         }
 
         if (dialog == null) {
-            Log.d(TAG, "Dialog is null.");
-            dismiss();
+            dismiss("Dialog is null.");
+            return;
+        }
+        Context context = getContext();
+        if (context == null) {
+            dismiss("getContext is null.");
             return;
         }
 
@@ -100,24 +106,44 @@
         if (info == null || (info.isEmbedded()
             && (info.getProfileClass() == PROFILE_CLASS_PROVISIONING
                 || (Flags.oemEnabledSatelliteFlag() && info.isOnlyNonTerrestrialNetwork())))) {
-            dismiss();
+            dismiss("SubscriptionInfo is null or other esim's cases.");
             return;
         }
         Log.d(TAG, "SubscriptionInfo: " + info);
+        TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+        if (telephonyManager == null) {
+            dismiss("TelephonyManager is null.");
+            return;
+        }
+        telephonyManager = telephonyManager.createForSubscriptionId(info.getSubscriptionId());
+        if (telephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)) {
+            dismiss("mobile data is on.");
+            final SimDialogActivity activity = (SimDialogActivity) getActivity();
+            if (activity != null) {
+                activity.finish();
+            }
+            return;
+        }
+
         final CharSequence simName =
-                SubscriptionUtil.getUniqueSubscriptionDisplayName(info, getContext());
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(info, context);
         final String title =
-                getContext().getString(
+                context.getString(
                         getTitleResId(),
                         simName);
         final String message =
-                getContext().getString(
+                context.getString(
                         R.string.sim_preferred_message,
                         simName);
         dialog.setTitle(title);
         dialog.setMessage(message);
     }
 
+    private void dismiss(String log) {
+        Log.d(TAG, log);
+        dismiss();
+    }
+
     @Override
     public void updateDialog() {
         updateDialog((AlertDialog) getDialog());
diff --git a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
index 4dc2e9e..b601eb3 100644
--- a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
+++ b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
@@ -356,10 +356,11 @@
                 log("setSpeedType(), setBand(BAND_2GHZ)");
                 configBuilder.setBand(BAND_2GHZ);
             }
-            // Set the security type back to WPA2/WPA3 if we're moving from 6GHz to something else.
-            if ((config.getBand() & BAND_6GHZ) != 0) {
-                configBuilder.setPassphrase(
-                        generatePassword(config), SECURITY_TYPE_WPA3_SAE_TRANSITION);
+            // Set the security type back to WPA2/WPA3 if the password is at least 8 characters and
+            // we're moving from 6GHz to something else.
+            String passphrase = generatePassword(config);
+            if ((passphrase.length() >= 8) && (config.getBand() & BAND_6GHZ) != 0) {
+                configBuilder.setPassphrase(passphrase, SECURITY_TYPE_WPA3_SAE_TRANSITION);
             }
         }
         setSoftApConfiguration(configBuilder.build());
diff --git a/tests/robotests/src/com/android/settings/SettingsInitializeTest.java b/tests/robotests/src/com/android/settings/SettingsInitializeTest.java
index a8f42c2..467436b 100644
--- a/tests/robotests/src/com/android/settings/SettingsInitializeTest.java
+++ b/tests/robotests/src/com/android/settings/SettingsInitializeTest.java
@@ -24,6 +24,7 @@
 
 import android.content.pm.ShortcutManager;
 
+import com.android.settings.core.instrumentation.ElapsedTimeUtils;
 import java.util.Collections;
 import org.junit.Before;
 import org.junit.Test;
@@ -96,4 +97,12 @@
         assertThat(updatedShortcuts).hasSize(1);
         assertThat(updatedShortcuts.get(0)).isSameInstanceAs(info);
     }
+
+    @Test
+    public void onReceive_suwFinished_shouldHaveElapsedTime() {
+        mSettingsInitialize.onReceive(mContext, new Intent(SetupWizardUtils.ACTION_SETUP_WIZARD_FINISHED));
+
+        final long elapsedTime = ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis());
+        assertThat(elapsedTime).isNotEqualTo(-1L);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
index 9f0cb6e..949b3d8 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
@@ -46,17 +46,21 @@
 import android.os.Looper;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.Pair;
-import android.widget.TextView;
 
-import androidx.appcompat.app.AlertDialog;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
 import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.lifecycle.Lifecycle;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
 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.LocalBluetoothManager;
 import com.android.settingslib.flags.Flags;
@@ -73,8 +77,14 @@
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
+import org.robolectric.annotation.Resetter;
 import org.robolectric.shadow.api.Shadow;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.Executor;
 
 /** Tests for {@link BluetoothDevicePairingDetailBase}. */
@@ -82,7 +92,7 @@
 @Config(shadows = {
         ShadowBluetoothAdapter.class,
         ShadowAlertDialogCompat.class,
-        com.android.settings.testutils.shadow.ShadowFragment.class,
+        ShadowFragment.class,
 })
 public class BluetoothDevicePairingDetailBaseTest {
 
@@ -133,7 +143,6 @@
         mFragment.mLocalManager = mLocalManager;
         mFragment.mBluetoothAdapter = mBluetoothAdapter;
         mFragment.initPreferencesFromPreferenceScreen();
-
     }
 
     @Test
@@ -199,22 +208,26 @@
     }
 
     @Test
+    @Config(shadows = ShadowDialogFragment.class)
     public void onDeviceBondStateChanged_bonded_pairAndJoinSharingEnabled_handle() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        ShadowDialogFragment.reset();
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         mFragment.mSelectedList.add(mBluetoothDevice);
         setUpFragmentWithPairAndJoinSharingIntent(true);
         mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
         shadowOf(Looper.getMainLooper()).idle();
 
-        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
-        assertThat(dialog).isNotNull();
-        TextView message = dialog.findViewById(R.id.message);
-        assertThat(message).isNotNull();
-        assertThat(message.getText().toString()).isEqualTo(
+        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
@@ -283,9 +296,11 @@
     }
 
     @Test
+    @Config(shadows = ShadowDialogFragment.class)
     public void
             onProfileConnectionStateChanged_deviceInSelectedListAndConnected_pairAndJoinSharing() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        ShadowDialogFragment.reset();
         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
         mFragment.mSelectedList.add(mBluetoothDevice);
         setUpFragmentWithPairAndJoinSharingIntent(true);
@@ -309,6 +324,8 @@
         assertThat(btDevice).isNotNull();
         assertThat(btDevice).isEqualTo(mBluetoothDevice);
         verify(mFragment).finish();
+
+        ShadowDialogFragment.reset();
     }
 
     @Test
@@ -393,7 +410,13 @@
         doReturn(intent).when(activity).getIntent();
         doReturn(activity).when(mFragment).getActivity();
         FragmentManager fragmentManager = mock(FragmentManager.class);
+        FragmentTransaction fragmentTransaction = mock(FragmentTransaction.class);
+        doReturn(fragmentTransaction).when(fragmentManager).beginTransaction();
         doReturn(fragmentManager).when(mFragment).getFragmentManager();
+        doReturn(fragmentManager).when(mFragment).getChildFragmentManager();
+        Lifecycle lifecycle = mock(Lifecycle.class);
+        when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED);
+        doReturn(lifecycle).when(mFragment).getLifecycle();
         mFragment.mShouldTriggerAudioSharingShareThenPairFlow =
                 mFragment.shouldTriggerAudioSharingShareThenPairFlow();
     }
@@ -425,4 +448,41 @@
             return "test_tag";
         }
     }
+
+    /** Shadow of DialogFragment. */
+    @Implements(value = DialogFragment.class)
+    public static class ShadowDialogFragment {
+        @RealObject
+        private DialogFragment mDialogFragment;
+        private static Map<String, Boolean> sDialogStatus = new HashMap<>();
+
+        /** Resetter of the shadow. */
+        @Resetter
+        public static void reset() {
+            sDialogStatus.clear();
+        }
+
+        /** Implementation for DialogFragment#show. */
+        @Implementation
+        public void show(@NonNull FragmentManager manager, @Nullable String tag) {
+            sDialogStatus.put(mDialogFragment.getClass().getName(), true);
+        }
+
+        /** Implementation for DialogFragment#dismissAllowingStateLoss. */
+        @Implementation
+        public void dismissAllowingStateLoss() {
+            sDialogStatus.put(mDialogFragment.getClass().getName(), false);
+        }
+
+        /** Implementation for DialogFragment#dismiss. */
+        @Implementation
+        public void dismiss() {
+            sDialogStatus.put(mDialogFragment.getClass().getName(), false);
+        }
+
+        /** Check if DialogFragment is showing. */
+        public static boolean isIsShowing(String clazzName) {
+            return sDialogStatus.getOrDefault(clazzName, false);
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ProgressDialogFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/ProgressDialogFragmentTest.java
new file mode 100644
index 0000000..7468776
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/ProgressDialogFragmentTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
+
+import android.widget.TextView;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.settings.R;
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.androidx.fragment.FragmentController;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowAlertDialogCompat.class})
+public class ProgressDialogFragmentTest {
+    @Rule public final MockitoRule mocks = MockitoJUnit.rule();
+
+    private static final String TEST_MESSAGE1 = "message1";
+    private static final String TEST_MESSAGE2 = "message2";
+
+    private Fragment mParent;
+
+    @Before
+    public void setUp() {
+        ShadowAlertDialogCompat.reset();
+        mParent = new Fragment();
+        FragmentController.setupFragment(
+                mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowAlertDialogCompat.reset();
+    }
+
+    @Test
+    public void getMetricsCategory_correctValue() {
+        ProgressDialogFragment fragment = ProgressDialogFragment.newInstance(mParent);
+        // TODO: update real metric
+        assertThat(fragment.getMetricsCategory()).isEqualTo(0);
+    }
+
+    @Test
+    public void onCreateDialog_unattachedFragment_nullDialogFragment() {
+        ProgressDialogFragment fragment = ProgressDialogFragment.newInstance(new Fragment());
+        assertThat(fragment).isNull();
+    }
+
+    @Test
+    public void onCreateDialog_showDialog() {
+        ProgressDialogFragment fragment = ProgressDialogFragment.newInstance(mParent);
+        fragment.show(TEST_MESSAGE1);
+        shadowMainLooper().idle();
+        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+        assertThat(dialog).isNotNull();
+        assertThat(dialog.isShowing()).isTrue();
+        TextView view = dialog.findViewById(R.id.message);
+        assertThat(view).isNotNull();
+        assertThat(view.getText().toString()).isEqualTo(TEST_MESSAGE1);
+    }
+
+    @Test
+    public void dismissDialog_succeed() {
+        ProgressDialogFragment fragment = ProgressDialogFragment.newInstance(mParent);
+        fragment.show(TEST_MESSAGE1);
+        shadowMainLooper().idle();
+        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+        assertThat(dialog).isNotNull();
+        assertThat(dialog.isShowing()).isTrue();
+
+        fragment.dismissAllowingStateLoss();
+        shadowMainLooper().idle();
+        assertThat(dialog.isShowing()).isFalse();
+    }
+
+    @Test
+    public void showDialog_sameMessage_keepExistingDialog() {
+        ProgressDialogFragment fragment = ProgressDialogFragment.newInstance(mParent);
+        fragment.show(TEST_MESSAGE1);
+        shadowMainLooper().idle();
+        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+        assertThat(dialog).isNotNull();
+        assertThat(dialog.isShowing()).isTrue();
+
+        fragment.show(TEST_MESSAGE1);
+        shadowMainLooper().idle();
+        assertThat(dialog.isShowing()).isTrue();
+        TextView view = dialog.findViewById(R.id.message);
+        assertThat(view).isNotNull();
+        assertThat(view.getText().toString()).isEqualTo(TEST_MESSAGE1);
+    }
+
+    @Test
+    public void showDialog_newMessage_keepAndUpdateDialog() {
+        ProgressDialogFragment fragment = ProgressDialogFragment.newInstance(mParent);
+        fragment.show(TEST_MESSAGE1);
+        shadowMainLooper().idle();
+        AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+        assertThat(dialog).isNotNull();
+        assertThat(dialog.isShowing()).isTrue();
+        TextView view = dialog.findViewById(R.id.message);
+        assertThat(view).isNotNull();
+        assertThat(view.getText().toString()).isEqualTo(TEST_MESSAGE1);
+
+        fragment.show(TEST_MESSAGE2);
+        shadowMainLooper().idle();
+        assertThat(dialog.isShowing()).isTrue();
+        assertThat(view.getText().toString()).isEqualTo(TEST_MESSAGE2);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
index 51c0c30..1ea8044 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
@@ -178,11 +178,9 @@
             }.launchIn(testScope.backgroundScope)
             delay(100)
             runCurrent()
-            helpPreference!!.onClick()
             ShadowLooper.idleMainLooper()
 
-            val shadowActivity = Shadows.shadowOf(fragmentActivity)
-            assertThat(shadowActivity.nextStartedActivity).isSameInstanceAs(intent)
+            assertThat(helpPreference?.intent).isSameInstanceAs(intent)
         }
     }
 
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java
index abdd743..bfb474b 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamMediaServiceTest.java
@@ -80,6 +80,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.util.concurrent.InlineExecutorService;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
 import org.robolectric.util.ReflectionHelpers;
@@ -143,6 +144,8 @@
 
         mAudioStreamMediaService = spy(new AudioStreamMediaService());
         ReflectionHelpers.setField(mAudioStreamMediaService, "mBase", mContext);
+        ReflectionHelpers.setField(
+                mAudioStreamMediaService, "mExecutor", new InlineExecutorService());
         when(mAudioStreamMediaService.getSystemService(anyString()))
                 .thenReturn(mMediaSessionManager);
         when(mMediaSessionManager.createSession(any(), anyString(), any())).thenReturn(mISession);
@@ -353,18 +356,6 @@
     }
 
     @Test
-    public void mediaSessionCallback_onSeekTo_updateNotification() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
-        mAudioStreamMediaService.onCreate();
-        mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
-        assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
-        mAudioStreamMediaService.mMediaSessionCallback.onSeekTo(100);
-
-        verify(mNotificationManager).notify(anyInt(), any());
-    }
-
-    @Test
     public void mediaSessionCallback_onPause_setVolume() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
 
@@ -416,19 +407,6 @@
     }
 
     @Test
-    public void volumeControlCallback_onDeviceVolumeChanged_updateNotification() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
-        mAudioStreamMediaService.onCreate();
-        assertThat(mAudioStreamMediaService.mVolumeControlCallback).isNotNull();
-        mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
-        mAudioStreamMediaService.mVolumeControlCallback.onDeviceVolumeChanged(
-                mDevice, /* volume= */ 0);
-
-        verify(mNotificationManager).notify(anyInt(), any());
-    }
-
-    @Test
     public void onBind_returnNull() {
         IBinder binder = mAudioStreamMediaService.onBind(new Intent());
 
diff --git a/tests/robotests/src/com/android/settings/datetime/AutoTimePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/AutoTimePreferenceControllerTest.java
index 9ac318a..ffb5141 100644
--- a/tests/robotests/src/com/android/settings/datetime/AutoTimePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/AutoTimePreferenceControllerTest.java
@@ -34,6 +34,8 @@
 
 import androidx.preference.Preference;
 
+import com.android.settings.R;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -153,6 +155,12 @@
         assertThat(mController.isEnabled()).isFalse();
     }
 
+    @Test
+    public void getSummary() {
+        assertThat(mController.getSummary().toString()).isEqualTo(
+                mContext.getString(R.string.date_time_auto_summary));
+    }
+
     private static TimeCapabilitiesAndConfig createCapabilitiesAndConfig(boolean autoSupported,
             boolean autoEnabled) {
         int configureAutoDetectionEnabledCapability =
diff --git a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
index c2d0445..651915b 100644
--- a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
@@ -225,7 +225,8 @@
         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
         when(mTimeManager.updateTimeZoneConfiguration(Mockito.any())).thenReturn(true);
 
-        assertThat(mController.getSummary()).isEqualTo("");
+        assertThat(mController.getSummary().toString()).isEqualTo(
+                mContext.getString(R.string.zone_auto_title_summary));
 
         capabilitiesAndConfig = createCapabilitiesAndConfig(
                 /* autoSupported= */true, /* autoEnabled= */true, /* telephonySupported= */
@@ -233,7 +234,7 @@
         when(mTimeManager.getTimeZoneCapabilitiesAndConfig()).thenReturn(capabilitiesAndConfig);
         when(mTimeManager.updateTimeZoneConfiguration(Mockito.any())).thenReturn(true);
 
-        assertThat(mController.getSummary()).isEqualTo(
+        assertThat(mController.getSummary().toString()).isEqualTo(
                 mContext.getString(R.string.auto_zone_requires_location_summary));
     }
 
diff --git a/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
index e9284ee..7673f38 100644
--- a/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
@@ -17,12 +17,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.Intent;
+import android.location.LocationManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.view.LayoutInflater;
@@ -65,7 +68,8 @@
     private DashboardFragment mDashboardFragment;
     @Mock
     private RecentAppOpsAccess mRecentLocationApps;
-
+    @Mock
+    private LocationManager mLocationManager;
     private Context mContext;
     private RecentLocationAccessPreferenceController mController;
     private View mAppEntitiesHeaderView;
@@ -130,4 +134,23 @@
                 mContext.getContentResolver(), Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 1);
         verify(mLayoutPreference, Mockito.times(1)).addPreference(Mockito.any());
     }
+
+    @Test
+    public void testPreferenceClick_onExtraLocationPackage_startsExtraLocationActivity() {
+        String extraLocationPkgName = "extraLocationPkgName";
+        when(mContext.getSystemService(LocationManager.class)).thenReturn(mLocationManager);
+        when(mLocationManager.getExtraLocationControllerPackage()).thenReturn(extraLocationPkgName);
+        RecentLocationAccessPreferenceController.PackageEntryClickedListener listener =
+                new RecentLocationAccessPreferenceController.PackageEntryClickedListener(
+                        mContext, extraLocationPkgName, UserHandle.CURRENT);
+        doNothing().when(mContext).startActivityAsUser(Mockito.refEq(new Intent(
+                Settings.ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS)),
+                Mockito.eq(UserHandle.CURRENT));
+
+        listener.onPreferenceClick(mLayoutPreference);
+
+        verify(mContext).startActivityAsUser(Mockito.refEq(new Intent(
+                Settings.ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS)),
+                Mockito.eq(UserHandle.CURRENT));
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/LockscreenNotificationMinimalismPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/LockscreenNotificationMinimalismPreferenceControllerTest.java
new file mode 100644
index 0000000..86dc06f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/LockscreenNotificationMinimalismPreferenceControllerTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static android.provider.Settings.Secure.LOCK_SCREEN_NOTIFICATION_MINIMALISM;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class LockscreenNotificationMinimalismPreferenceControllerTest {
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private PreferenceScreen mScreen;
+
+    private LockscreenNotificationMinimalismPreferenceController mController;
+    private Preference mPreference;
+    static final int ON = 1;
+    static final int OFF = 0;
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        doReturn(mock(DevicePolicyManager.class)).when(mContext)
+                .getSystemService(Context.DEVICE_POLICY_SERVICE);
+        mController = new LockscreenNotificationMinimalismPreferenceController(mContext,
+                "key");
+        mPreference = new Preference(RuntimeEnvironment.application);
+        mPreference.setKey(mController.getPreferenceKey());
+        when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference);
+    }
+
+    @Test
+    @DisableFlags(com.android.server.notification.Flags.FLAG_NOTIFICATION_MINIMALISM)
+    public void display_featureFlagOff_shouldNotDisplay() {
+        mController.displayPreference(mScreen);
+        assertThat(mPreference.isVisible()).isFalse();
+    }
+
+    @Test
+    @EnableFlags(com.android.server.notification.Flags.FLAG_NOTIFICATION_MINIMALISM)
+    public void display_featureFlagOn_shouldDisplay() {
+        mController.displayPreference(mScreen);
+        assertThat(mPreference.isVisible()).isTrue();
+    }
+
+    @Test
+    @EnableFlags(com.android.server.notification.Flags.FLAG_NOTIFICATION_MINIMALISM)
+    public void isChecked_settingIsOff_shouldReturnFalse() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                LOCK_SCREEN_NOTIFICATION_MINIMALISM, OFF);
+
+        assertThat(mController.isChecked()).isFalse();
+    }
+
+    @Test
+    @EnableFlags(com.android.server.notification.Flags.FLAG_NOTIFICATION_MINIMALISM)
+    public void isChecked_settingIsOn_shouldReturnTrue() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                LOCK_SCREEN_NOTIFICATION_MINIMALISM, ON);
+
+        assertThat(mController.isChecked()).isTrue();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ShowOnlyUnseenNotificationsOnLockscreenPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ShowOnlyUnseenNotificationsOnLockscreenPreferenceControllerTest.java
index cc26e54..8877f30 100644
--- a/tests/robotests/src/com/android/settings/notification/ShowOnlyUnseenNotificationsOnLockscreenPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ShowOnlyUnseenNotificationsOnLockscreenPreferenceControllerTest.java
@@ -29,12 +29,16 @@
 
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
@@ -53,6 +57,8 @@
 
     private ShowOnlyUnseenNotificationsOnLockscreenPreferenceController mController;
     private Preference mPreference;
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     @Before
     public void setUp() {
@@ -67,12 +73,14 @@
     }
 
     @Test
+    @DisableFlags(com.android.server.notification.Flags.FLAG_NOTIFICATION_MINIMALISM)
     public void display_configUnset_shouldNotDisplay() {
         mController.displayPreference(mScreen);
         assertThat(mPreference.isVisible()).isFalse();
     }
 
     @Test
+    @DisableFlags(com.android.server.notification.Flags.FLAG_NOTIFICATION_MINIMALISM)
     public void display_configSet_showDisplay() {
         Settings.Secure.putInt(mContext.getContentResolver(),
                 LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, OFF);
@@ -81,6 +89,15 @@
     }
 
     @Test
+    @EnableFlags(com.android.server.notification.Flags.FLAG_NOTIFICATION_MINIMALISM)
+    public void display_configUnset_minimalismEnabled_shouldDisplay() {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, ON);
+        mController.displayPreference(mScreen);
+        assertThat(mPreference.isVisible()).isTrue();
+    }
+
+    @Test
     public void isChecked_settingIsOff_shouldReturnFalse() {
         Settings.Secure.putInt(mContext.getContentResolver(),
                 LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, OFF);
diff --git a/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt b/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt
index f61a3d3..32ca2cd 100644
--- a/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt
+++ b/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt
@@ -38,8 +38,12 @@
 import com.android.systemui.biometrics.shared.model.FingerprintSensorType
 import com.android.systemui.biometrics.shared.model.toFingerprintSensor
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.transform
+import kotlinx.coroutines.flow.update
 
 /** Fake to be used by other classes to easily fake the FingerprintManager implementation. */
 class FakeFingerprintManagerInteractor :
@@ -52,7 +56,7 @@
   RenameFingerprintInteractor,
   SensorInteractor {
 
-  var enrollableFingerprints: Int = 5
+  private val enrollableFingerprints = MutableStateFlow(5)
   var enrolledFingerprintsInternal: MutableList<FingerprintData> = mutableListOf()
   var challengeToGenerate: Pair<Long, ByteArray> = Pair(-1L, byteArrayOf())
   var authenticateAttempt = FingerprintAuthAttemptModel.Success(1)
@@ -82,13 +86,13 @@
   override val enrolledFingerprints: Flow<List<FingerprintData>> = flow {
     emit(enrolledFingerprintsInternal)
   }
-  override val canEnrollFingerprints: Flow<Boolean> = flow {
-    emit(enrolledFingerprintsInternal.size < enrollableFingerprints)
+  override val canEnrollFingerprints: Flow<Boolean> = enrollableFingerprints.transform {
+     emit(enrolledFingerprintsInternal.size < it)
   }
 
-  override fun maxFingerprintsEnrollable(): Int {
-    return enrollableFingerprints
-  }
+  override val maxFingerprintsEnrollable: Flow<Int> = enrollableFingerprints.asStateFlow()
+
+  override fun setShouldUseSettingsMaxFingerprints(useSettings: Boolean) {}
 
   override val sensorPropertiesInternal: Flow<FingerprintSensor?> = flow { emit(sensorProp) }
   override val hasSideFps: Flow<Boolean> =
@@ -110,4 +114,7 @@
     }
   }
 
+  fun setMaxEnrollableFingerprints(fingerprints: Int) {
+    enrollableFingerprints.update { fingerprints }
+  }
 }
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.kt
index ca37082..f47c635 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.kt
@@ -62,10 +62,15 @@
         on { isSubscriptionEnabledFlow(SUB_ID) } doReturn flowOf(false)
     }
 
+    private val mockSubscriptionActivationRepository = mock<SubscriptionActivationRepository> {
+        on { isActivationChangeableFlow() } doReturn flowOf(true)
+    }
+
     private val controller = MobileNetworkSwitchController(
         context = context,
         preferenceKey = TEST_KEY,
         subscriptionRepository = mockSubscriptionRepository,
+        subscriptionActivationRepository = mockSubscriptionActivationRepository,
     ).apply { init(SUB_ID) }
 
     @Test
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt
index 5052f57..ba5142e 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt
@@ -91,7 +91,23 @@
 
         subInfoListener?.onSubscriptionsChanged()
 
-        assertThat(listDeferred.await()).hasSize(2)
+        assertThat(listDeferred.await().size).isAtLeast(2)
+    }
+
+    @Test
+    fun subscriptionsChangedFlow_managerNotCallOnSubscriptionsChangedInitially() = runBlocking {
+        mockSubscriptionManager.stub {
+            on { addOnSubscriptionsChangedListener(any(), any()) } doAnswer
+                {
+                    subInfoListener =
+                        it.arguments[1] as SubscriptionManager.OnSubscriptionsChangedListener
+                    // not call onSubscriptionsChanged here
+                }
+        }
+
+        val initialValue = repository.subscriptionsChangedFlow().firstWithTimeoutOrNull()
+
+        assertThat(initialValue).isSameInstanceAs(Unit)
     }
 
     @Test
diff --git a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt
index 691b611..2623206 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt
@@ -30,6 +30,7 @@
 import android.os.CancellationSignal
 import android.os.Handler
 import com.android.settings.biometrics.GatekeeperPasswordProvider
+import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintEnrollmentRepository
 import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintEnrollmentRepositoryImpl
 import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
 import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSettingsRepositoryImpl
@@ -61,7 +62,7 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.last
+import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
@@ -106,9 +107,14 @@
   private val flow: FingerprintFlow = Default
   private val maxFingerprints = 5
   private val currUser = MutableStateFlow(0)
+  private lateinit var fingerprintEnrollRepo: FingerprintEnrollmentRepository
   private val userRepo =
     object : UserRepo {
       override val currentUser: Flow<Int> = currUser
+
+      override fun updateUser(user: Int) {
+        currUser.update { user }
+      }
     }
 
   @Before
@@ -133,17 +139,18 @@
       }
 
     val settingsRepository = FingerprintSettingsRepositoryImpl(maxFingerprints)
-    val fingerprintEnrollmentRepository =
+    fingerprintEnrollRepo =
       FingerprintEnrollmentRepositoryImpl(
         fingerprintManager,
         userRepo,
         settingsRepository,
         backgroundDispatcher,
         backgroundScope,
+        fingerprintSensorRepository,
       )
 
     enrolledFingerprintsInteractorUnderTest =
-      EnrolledFingerprintsInteractorImpl(fingerprintManager, userId)
+      EnrolledFingerprintsInteractorImpl(fingerprintEnrollRepo)
     generateChallengeInteractorUnderTest =
       GenerateChallengeInteractorImpl(fingerprintManager, userId, gateKeeperPasswordProvider)
     removeFingerprintsInteractorUnderTest =
@@ -153,7 +160,7 @@
     authenticateInteractorImplUnderTest = AuthenticateInteractorImpl(fingerprintManager, userId)
 
     canEnrollFingerprintsInteractorUnderTest =
-      CanEnrollFingerprintsInteractorImpl(fingerprintEnrollmentRepository)
+      CanEnrollFingerprintsInteractorImpl(fingerprintEnrollRepo)
 
     enrollInteractorUnderTest = EnrollFingerprintInteractorImpl(userId, fingerprintManager, flow)
   }
@@ -163,9 +170,16 @@
     testScope.runTest {
       whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(emptyList())
 
-      val emptyFingerprintList: List<Fingerprint> = emptyList()
-      assertThat(enrolledFingerprintsInteractorUnderTest.enrolledFingerprints.last())
-        .isEqualTo(emptyFingerprintList)
+      var list: List<FingerprintData>? = null
+      val job =
+        testScope.launch {
+          enrolledFingerprintsInteractorUnderTest.enrolledFingerprints.collect { list = it }
+        }
+
+      runCurrent()
+      job.cancelAndJoin()
+
+      assertThat(list!!.isEmpty())
     }
 
   @Test
@@ -174,10 +188,19 @@
       val expected = Fingerprint("Finger 1,", 2, 3L)
       val fingerprintList: List<Fingerprint> = listOf(expected)
       whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList)
+      // This causes the enrolled fingerprints to be updated
 
-      val list = enrolledFingerprintsInteractorUnderTest.enrolledFingerprints.last()
+      var list: List<FingerprintData>? = null
+      val job =
+        testScope.launch {
+          enrolledFingerprintsInteractorUnderTest.enrolledFingerprints.collect { list = it }
+        }
+
+      runCurrent()
+      job.cancelAndJoin()
+
       assertThat(list!!.size).isEqualTo(fingerprintList.size)
-      val actual = list[0]
+      val actual = list!![0]
       assertThat(actual.name).isEqualTo(expected.name)
       assertThat(actual.fingerId).isEqualTo(expected.biometricId)
       assertThat(actual.deviceId).isEqualTo(expected.deviceId)
@@ -220,11 +243,7 @@
       whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList)
 
       var result: Boolean? = null
-      val job =
-        testScope.launch {
-          canEnrollFingerprintsInteractorUnderTest.canEnrollFingerprints.collect { result = it }
-        }
-
+      val job = testScope.launch { fingerprintEnrollRepo.canEnrollUser.collect { result = it } }
       runCurrent()
       job.cancelAndJoin()
 
diff --git a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModelTest.kt
index f59d1fc..a9ab589 100644
--- a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModelTest.kt
+++ b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModelTest.kt
@@ -112,7 +112,7 @@
           .toFingerprintSensor()
 
       fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
-      fakeFingerprintManagerInteractor.enrollableFingerprints = 5
+      fakeFingerprintManagerInteractor.setMaxEnrollableFingerprints(5)
 
       var canEnrollFingerprints: Boolean = false
       val job = launch {
diff --git a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
index 4765d18..510ce39 100644
--- a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
+++ b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java
@@ -78,6 +78,7 @@
 public class WifiHotspotRepositoryTest {
     static final String WIFI_SSID = "wifi_ssid";
     static final String WIFI_PASSWORD = "wifi_password";
+    static final String WIFI_PASSWORD_SHORT = "wifi";
 
     static final int WIFI_5GHZ_BAND_PREFERRED = BAND_2GHZ_5GHZ;
     static final int WIFI_6GHZ_BAND_PREFERRED = BAND_2GHZ_5GHZ_6GHZ;
@@ -477,7 +478,7 @@
 
     @Test
     public void setSpeedType_2g5ghzTo6ghz_setConfigSecurityToWpa3() {
-        mockConfig(SPEED_2GHZ_5GHZ, SECURITY_TYPE_WPA3_SAE_TRANSITION);
+        mockConfig(SPEED_2GHZ_5GHZ, SECURITY_TYPE_WPA3_SAE_TRANSITION, WIFI_PASSWORD);
 
         mRepository.setSpeedType(SPEED_6GHZ);
 
@@ -497,11 +498,33 @@
         SparseIntArray channels = mSoftApConfigCaptor.getValue().getChannels();
         assertThat(channels.get(BAND_2GHZ, CHANNEL_NOT_FOUND)).isNotEqualTo(CHANNEL_NOT_FOUND);
         assertThat(channels.get(BAND_2GHZ_5GHZ, CHANNEL_NOT_FOUND)).isNotEqualTo(CHANNEL_NOT_FOUND);
+    }
+
+    @Test
+    public void setSpeedType_6ghzTo2g5ghzWith8CharPassphrase_changesSecurityToWpa3Transition() {
+        mockConfigSpeedType(SPEED_6GHZ);
+        mRepository.mIsDualBand = true;
+
+        mRepository.setSpeedType(SPEED_2GHZ_5GHZ);
+
+        verify(mWifiManager).setSoftApConfiguration(mSoftApConfigCaptor.capture());
         assertThat(mSoftApConfigCaptor.getValue().getSecurityType())
                 .isEqualTo(SECURITY_TYPE_WPA3_SAE_TRANSITION);
     }
 
     @Test
+    public void setSpeedType_6ghzTo2g5ghzWithLessThan8CharPassphrase_doesNotChangeSecurity() {
+        mockConfig(SECURITY_TYPE_WPA3_SAE, SPEED_6GHZ, WIFI_PASSWORD_SHORT);
+        mRepository.mIsDualBand = true;
+
+        mRepository.setSpeedType(SPEED_2GHZ_5GHZ);
+
+        verify(mWifiManager).setSoftApConfiguration(mSoftApConfigCaptor.capture());
+        assertThat(mSoftApConfigCaptor.getValue().getSecurityType())
+                .isEqualTo(SECURITY_TYPE_WPA3_SAE);
+    }
+
+    @Test
     public void setSpeedType_2ghzTo5ghz_setConfigBandTo5ghzPreferred() {
         mockConfigSpeedType(SPEED_2GHZ);
 
@@ -784,18 +807,18 @@
     }
 
     private void mockConfigSecurityType(int securityType) {
-        mockConfig(securityType, SPEED_2GHZ);
+        mockConfig(securityType, SPEED_2GHZ,
+                (securityType == SECURITY_TYPE_OPEN) ? null : WIFI_PASSWORD);
     }
 
     private void mockConfigSpeedType(int speedType) {
-        mockConfig(SECURITY_TYPE_WPA3_SAE, speedType);
+        mockConfig(SECURITY_TYPE_WPA3_SAE, speedType, WIFI_PASSWORD);
     }
 
-    private void mockConfig(int securityType, int speedType) {
+    private void mockConfig(int securityType, int speedType, String passphrase) {
         SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
         // Security Type
         doReturn(securityType).when(mSecurityType).getValue();
-        String passphrase = (securityType == SECURITY_TYPE_OPEN) ? null : WIFI_PASSWORD;
         configBuilder.setPassphrase(passphrase, securityType).build();
 
         // Speed Type