Merge "Revert^2 "Prevent notif flicker during entirety of swipe to unlock"" into main
diff --git a/apex/jobscheduler/framework/aconfig/job.aconfig b/apex/jobscheduler/framework/aconfig/job.aconfig
index 788e824..2c1a853 100644
--- a/apex/jobscheduler/framework/aconfig/job.aconfig
+++ b/apex/jobscheduler/framework/aconfig/job.aconfig
@@ -9,6 +9,7 @@
 
 flag {
     name: "job_debug_info_apis"
+    is_exported: true
     namespace: "backstage_power"
     description: "Add APIs to let apps attach debug information to jobs"
     bug: "293491637"
@@ -16,6 +17,7 @@
 
 flag {
     name: "backup_jobs_exemption"
+    is_exported: true
     namespace: "backstage_power"
     description: "Introduce a new RUN_BACKUP_JOBS permission and exemption logic allowing for longer running jobs for apps whose primary purpose is to backup or sync content."
     bug: "318731461"
diff --git a/core/api/current.txt b/core/api/current.txt
index 8a61f4a..93c34cd 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10731,6 +10731,7 @@
     field public static final String DROPBOX_SERVICE = "dropbox";
     field public static final String EUICC_SERVICE = "euicc";
     field public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
+    field public static final String FINGERPRINT_SERVICE = "fingerprint";
     field public static final String GAME_SERVICE = "game";
     field public static final String GRAMMATICAL_INFLECTION_SERVICE = "grammatical_inflection";
     field public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
@@ -20387,6 +20388,54 @@
 
 }
 
+package android.hardware.fingerprint {
+
+  @Deprecated public class FingerprintManager {
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+    field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+    field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
+    field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+    field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+    field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
+    field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
+    field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
+    field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
+    field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+    field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
+    field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+    field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
+    field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+    field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+    field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+    field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
+    field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
+  }
+
+  @Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
+    ctor @Deprecated public FingerprintManager.AuthenticationCallback();
+    method @Deprecated public void onAuthenticationError(int, CharSequence);
+    method @Deprecated public void onAuthenticationFailed();
+    method @Deprecated public void onAuthenticationHelp(int, CharSequence);
+    method @Deprecated public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
+  }
+
+  @Deprecated public static class FingerprintManager.AuthenticationResult {
+    method @Deprecated public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
+  }
+
+  @Deprecated public static final class FingerprintManager.CryptoObject {
+    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
+    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
+    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
+    method @Deprecated public javax.crypto.Cipher getCipher();
+    method @Deprecated public javax.crypto.Mac getMac();
+    method @Deprecated public java.security.Signature getSignature();
+  }
+
+}
+
 package android.hardware.input {
 
   public final class HostUsiVersion implements android.os.Parcelable {
diff --git a/core/api/removed.txt b/core/api/removed.txt
index c61f163..3c7c0d6 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -35,7 +35,6 @@
     method @Deprecated @Nullable public String getFeatureId();
     method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
     method public abstract java.io.File getSharedPreferencesPath(String);
-    field public static final String FINGERPRINT_SERVICE = "fingerprint";
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -146,54 +145,6 @@
 
 }
 
-package android.hardware.fingerprint {
-
-  @Deprecated public class FingerprintManager {
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
-    field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
-    field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
-    field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
-    field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
-    field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
-    field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
-    field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
-    field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
-    field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
-    field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
-    field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
-    field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
-    field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
-    field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
-    field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
-    field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
-    field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
-  }
-
-  @Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
-    ctor public FingerprintManager.AuthenticationCallback();
-    method public void onAuthenticationError(int, CharSequence);
-    method public void onAuthenticationFailed();
-    method public void onAuthenticationHelp(int, CharSequence);
-    method public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
-  }
-
-  @Deprecated public static class FingerprintManager.AuthenticationResult {
-    method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
-  }
-
-  @Deprecated public static final class FingerprintManager.CryptoObject {
-    ctor public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
-    ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
-    ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
-    method public javax.crypto.Cipher getCipher();
-    method public javax.crypto.Mac getMac();
-    method public java.security.Signature getSignature();
-  }
-
-}
-
 package android.media {
 
   public final class AudioFormat implements android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index a2b847e..a76aa67 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1721,6 +1721,15 @@
 
 }
 
+package android.hardware.fingerprint {
+
+  @Deprecated public class FingerprintManager {
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
+  }
+
+}
+
 package android.hardware.hdmi {
 
   public final class HdmiControlServiceWrapper {
diff --git a/core/api/test-removed.txt b/core/api/test-removed.txt
index 2e44176..d802177 100644
--- a/core/api/test-removed.txt
+++ b/core/api/test-removed.txt
@@ -1,10 +1 @@
 // Signature format: 2.0
-package android.hardware.fingerprint {
-
-  @Deprecated public class FingerprintManager {
-    method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
-  }
-
-}
-
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index 350b1ed..b9aa18c 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -3,6 +3,7 @@
 flag {
      namespace: "system_performance"
      name: "app_start_info"
+     is_exported: true
      description: "Control collecting of ApplicationStartInfo records and APIs."
      bug: "247814855"
 }
@@ -10,6 +11,7 @@
 flag {
      namespace: "backstage_power"
      name: "get_binding_uid_importance"
+     is_exported: true
      description: "API to get importance of UID that's binding to the caller"
      bug: "292533010"
 }
@@ -17,6 +19,7 @@
 flag {
     namespace: "backstage_power"
     name: "app_restrictions_api"
+    is_exported: true
     description: "API to track and query restrictions applied to apps"
     bug: "320150834"
 }
@@ -24,6 +27,7 @@
 flag {
      namespace: "backstage_power"
      name: "uid_importance_listener_for_uids"
+     is_exported: true
      description: "API to add OnUidImportanceListener with targetted UIDs"
      bug: "286258140"
 }
@@ -31,12 +35,14 @@
 flag {
      namespace: "backstage_power"
      name: "introduce_new_service_ontimeout_callback"
+     is_exported: true
      description: "Add a new callback in Service to indicate a FGS has reached its timeout."
      bug: "317799821"
 }
 
 flag {
     name: "bcast_event_timestamps"
+    is_exported: true
     namespace: "backstage_power"
     description: "Add APIs for clients to provide broadcast event trigger timestamps"
     bug: "325136414"
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 3ec6fe7..4fa45be 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -5,6 +5,7 @@
 
 flag {
   name: "policy_engine_migration_v2_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "V2 of the policy engine migrations for Android V"
   bug: "289520697"
@@ -12,6 +13,7 @@
 
 flag {
   name: "device_policy_size_tracking_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Add feature to track the total policy size and have a max threshold - public API changes"
   bug: "281543351"
@@ -26,6 +28,7 @@
 
 flag {
   name: "onboarding_bugreport_v2_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Add feature to track required changes for enabled V2 of auto-capturing of onboarding bug reports."
   bug: "302517677"
@@ -47,6 +50,7 @@
 
 flag {
   name: "dedicated_device_control_api_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "(API) Allow the device management role holder to control which platform features are available on dedicated devices."
   bug: "281964214"
@@ -54,6 +58,7 @@
 
 flag {
   name: "permission_migration_for_zero_trust_api_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "(API) Migrate existing APIs to permission based, and enable DMRH to call them to collect Zero Trust signals."
   bug: "289520697"
@@ -68,6 +73,7 @@
 
 flag {
   name: "device_theft_api_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Add new API for theft detection."
   bug: "325073410"
@@ -89,6 +95,7 @@
 
 flag {
   name: "security_log_v2_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Improve access to security logging in the context of Zero Trust."
   bug: "295324350"
@@ -103,6 +110,7 @@
 
 flag {
     name: "allow_querying_profile_type"
+    is_exported: true
     namespace: "enterprise"
     description: "Public APIs to query if a user is a profile and what kind of profile type it is."
     bug: "323001115"
@@ -117,6 +125,7 @@
 
 flag {
   name: "assist_content_user_restriction_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Prevent work data leakage by sending assist content to privileged apps."
   bug: "322975406"
@@ -134,6 +143,7 @@
 
 flag {
   name: "backup_service_security_log_event_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Emit a security log event when DPM.setBackupServiceEnabled is called"
   bug: "304999634"
@@ -141,6 +151,7 @@
 
 flag {
   name: "esim_management_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Enable APIs to provision and manage eSIMs"
   bug: "295301164"
@@ -148,6 +159,7 @@
 
 flag {
   name: "headless_device_owner_single_user_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Add Headless DO support."
   bug: "289515470"
@@ -155,6 +167,7 @@
 
 flag {
   name: "is_mte_policy_enforced"
+  is_exported: true
   namespace: "enterprise"
   description: "Allow to query whether MTE is enabled or not to check for compliance for enterprise policy"
   bug: "322777918"
diff --git a/core/java/android/app/background_install_control_manager.aconfig b/core/java/android/app/background_install_control_manager.aconfig
index 4473b95..5f3bb07 100644
--- a/core/java/android/app/background_install_control_manager.aconfig
+++ b/core/java/android/app/background_install_control_manager.aconfig
@@ -3,6 +3,7 @@
 flag {
      namespace: "preload_safety"
      name: "bic_client"
+     is_exported: true
      description: "System API for background install control."
      is_fixed_read_only: true
      bug: "287507984"
diff --git a/core/java/android/app/grammatical_inflection_manager.aconfig b/core/java/android/app/grammatical_inflection_manager.aconfig
index 68d12ba..0d7bf65 100644
--- a/core/java/android/app/grammatical_inflection_manager.aconfig
+++ b/core/java/android/app/grammatical_inflection_manager.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "system_terms_of_address_enabled"
+    is_exported: true
     namespace: "globalintl"
     description: "Feature flag for System Terms of Address"
     bug: "297798866"
diff --git a/core/java/android/app/multitasking.aconfig b/core/java/android/app/multitasking.aconfig
index ab00891..dbf3173 100644
--- a/core/java/android/app/multitasking.aconfig
+++ b/core/java/android/app/multitasking.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "enable_pip_ui_state_callback_on_entering"
+    is_exported: true
     namespace: "multitasking"
     description: "Enables PiP UI state callback on entering"
     bug: "303718131"
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 274d02a..e9a7460 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -2,6 +2,7 @@
 
 flag {
   name: "modes_api"
+  is_exported: true
   namespace: "systemui"
   description: "This flag controls new and updated DND apis"
   bug: "300477976"
@@ -16,6 +17,7 @@
 
 flag {
   name: "api_tvextender"
+  is_exported: true
   namespace: "systemui"
   description: "Guards new android.app.Notification.TvExtender api"
   bug: "308164892"
@@ -24,6 +26,7 @@
 
 flag {
   name: "lifetime_extension_refactor"
+  is_exported: true
   namespace: "systemui"
   description: "Enables moving notification lifetime extension management from SystemUI to "
       "Notification Manager Service"
@@ -46,6 +49,7 @@
 
 flag {
   name: "category_voicemail"
+  is_exported: true
   namespace: "wear_sysui"
   description: "Adds a new voicemail category for notifications"
   bug: "322806700"
@@ -53,6 +57,7 @@
 
 flag {
   name: "notification_channel_vibration_effect_api"
+  is_exported: true
   namespace: "systemui"
   description: "This flag enables the API to allow setting VibrationEffect for NotificationChannels"
   bug: "241732519"
diff --git a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
index 44f3329..dd9210f 100644
--- a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
+++ b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "enable_on_device_intelligence"
+    is_exported: true
     namespace: "ondeviceintelligence"
     description: "Make methods on OnDeviceIntelligenceManager available for local inference."
     bug: "304755128"
diff --git a/core/java/android/app/pinner-client.aconfig b/core/java/android/app/pinner-client.aconfig
index b60ad9e..0f7fa14 100644
--- a/core/java/android/app/pinner-client.aconfig
+++ b/core/java/android/app/pinner-client.aconfig
@@ -3,6 +3,7 @@
 flag {
      namespace: "system_performance"
      name: "pinner_service_client_api"
+     is_exported: true
      description: "Control exposing PinnerService APIs."
      bug: "307594624"
 }
\ No newline at end of file
diff --git a/core/java/android/app/smartspace/flags.aconfig b/core/java/android/app/smartspace/flags.aconfig
index 12af888..e90ba67 100644
--- a/core/java/android/app/smartspace/flags.aconfig
+++ b/core/java/android/app/smartspace/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
   name: "remote_views"
+  is_exported: true
   namespace: "sysui_integrations"
   description: "Flag to enable the FlaggedApi to include RemoteViews in SmartspaceTarget"
   bug: "300157758"
@@ -9,6 +10,7 @@
 
 flag {
   name: "access_smartspace"
+  is_exported: true
   namespace: "sysui_integrations"
   description: "Flag to enable the ACCESS_SMARTSPACE check in SmartspaceManagerService"
   bug: "297207196"
diff --git a/core/java/android/app/usage/flags.aconfig b/core/java/android/app/usage/flags.aconfig
index 4d9d911..9a2d2e5 100644
--- a/core/java/android/app/usage/flags.aconfig
+++ b/core/java/android/app/usage/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "user_interaction_type_api"
+    is_exported: true
     namespace: "backstage_power"
     description: "Feature flag for user interaction event report/query API"
     bug: "296061232"
@@ -9,6 +10,7 @@
 
 flag {
     name: "report_usage_stats_permission"
+    is_exported: true
     namespace: "backstage_power"
     description: "Feature flag for the new REPORT_USAGE_STATS permission."
     bug: "296056771"
@@ -31,6 +33,7 @@
 
 flag {
     name: "filter_based_event_query_api"
+    is_exported: true
     namespace: "backstage_power"
     description: " Feature flag to support filter based event query API"
     bug: "194321117"
@@ -38,6 +41,7 @@
 
 flag {
     name: "get_app_bytes_by_data_type_api"
+    is_exported: true
     namespace: "system_performance"
     description: "Feature flag for collecting app data size by file type API"
     bug: "294088945"
diff --git a/core/java/android/app/wearable/flags.aconfig b/core/java/android/app/wearable/flags.aconfig
index b4f628f..d1d7b5d 100644
--- a/core/java/android/app/wearable/flags.aconfig
+++ b/core/java/android/app/wearable/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "enable_unsupported_operation_status_code"
+    is_exported: true
     namespace: "machine_learning"
     description: "This flag enables the WearableSensingManager#STATUS_UNSUPPORTED_OPERATION status code API."
     bug: "301427767"
@@ -9,6 +10,7 @@
 
 flag {
     name: "enable_data_request_observer_api"
+    is_exported: true
     namespace: "machine_learning"
     description: "This flag enables the API to register a data request observer on WearableSensingManager."
     bug: "301427767"
@@ -16,6 +18,7 @@
 
 flag {
     name: "enable_provide_wearable_connection_api"
+    is_exported: true
     namespace: "machine_learning"
     description: "This flag enables the WearableSensingManager#provideWearableConnection API."
     bug: "301427767"
@@ -30,6 +33,7 @@
 
 flag {
     name: "enable_hotword_wearable_sensing_api"
+    is_exported: true
     namespace: "machine_learning"
     description: "This flag enables the APIs related to hotword in WearableSensingManager and WearableSensingService."
     bug: "310055381"
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index 822f02f..4511954 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
   name: "generated_previews"
+  is_exported: true
   namespace: "app_widgets"
   description: "Enable support for generated previews in AppWidgetManager"
   bug: "306546610"
@@ -26,6 +27,7 @@
 
 flag {
   name: "draw_data_parcel"
+  is_exported: true
   namespace: "app_widgets"
   description: "Enable support for transporting draw instructions as data parcel"
   bug: "286130467"
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
index d634b64..ecc5e1b 100644
--- a/core/java/android/companion/flags.aconfig
+++ b/core/java/android/companion/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "new_association_builder"
+    is_exported: true
     namespace: "companion"
     description: "Controls if the new Builder is exposed to test apis."
     bug: "296251481"
@@ -16,6 +17,7 @@
 
 flag {
     name: "association_tag"
+    is_exported: true
     namespace: "companion"
     description: "Enable Association tag APIs "
     bug: "289241123"
@@ -23,6 +25,7 @@
 
 flag {
     name: "device_presence"
+    is_exported: true
     namespace: "companion"
     description: "Enable device presence APIs"
     bug: "283000075"
@@ -30,6 +33,7 @@
 
 flag {
     name: "perm_sync_user_consent"
+    is_exported: true
     namespace: "companion"
     description: "Expose perm sync user consent API"
     bug: "309528663"
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 588e4fc..a6a4f5e 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -19,6 +19,7 @@
 
 flag {
   name: "dynamic_policy"
+  is_exported: true
   namespace: "virtual_devices"
   description: "Enable dynamic policy API"
   bug: "298401780"
@@ -26,6 +27,7 @@
 
 flag {
   name: "cross_device_clipboard"
+  is_exported: true
   namespace: "virtual_devices"
   description: "Enable cross-device clipboard API"
   bug: "306622082"
@@ -40,6 +42,7 @@
 
 flag {
   name: "vdm_custom_ime"
+  is_exported: true
   namespace: "virtual_devices"
   description: "Enable custom IME API"
   bug: "287269288"
@@ -47,6 +50,7 @@
 
 flag {
   name: "vdm_custom_home"
+  is_exported: true
   namespace: "virtual_devices"
   description: "Enable custom home API"
   bug: "297168328"
@@ -54,6 +58,7 @@
 
 flag {
   name: "vdm_public_apis"
+  is_exported: true
   namespace: "virtual_devices"
   description: "Enable public VDM API for device capabilities"
   bug: "297253526"
@@ -61,6 +66,7 @@
 
 flag {
   name: "virtual_camera"
+  is_exported: true
   namespace: "virtual_devices"
   description: "Enable Virtual Camera"
   bug: "270352264"
@@ -82,6 +88,7 @@
 
 flag {
   name: "persistent_device_id_api"
+  is_exported: true
   namespace: "virtual_devices"
   description: "Enable persistent device ID notification API"
   bug: "295258915"
@@ -96,6 +103,7 @@
 
 flag {
   name: "interactive_screen_mirror"
+  is_exported: true
   namespace: "virtual_devices"
   description: "Enable interactive screen mirroring using Virtual Devices"
   bug: "292212199"
@@ -103,6 +111,7 @@
 
 flag {
   name: "virtual_stylus"
+  is_exported: true
   namespace: "virtual_devices"
   description: "Enable virtual stylus input"
   bug: "304829446"
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 284e318..c0c91cb 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5067,7 +5067,6 @@
      * {@link android.hardware.fingerprint.FingerprintManager} for handling management
      * of fingerprints.
      *
-     * @removed See {@link android.hardware.biometrics.BiometricPrompt}
      * @see #getSystemService(String)
      * @see android.hardware.fingerprint.FingerprintManager
      */
diff --git a/core/java/android/content/flags/flags.aconfig b/core/java/android/content/flags/flags.aconfig
index 3445fb5..27bce5b 100644
--- a/core/java/android/content/flags/flags.aconfig
+++ b/core/java/android/content/flags/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "enable_bind_package_isolated_process"
+    is_exported: true
     namespace: "machine_learning"
     description: "This flag enables the newly added flag for binding package-private isolated processes."
     bug: "312706530"
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 92cb9cc..cde565b 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "quarantined_enabled"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag for Quarantined state"
     bug: "269127435"
@@ -9,6 +10,7 @@
 
 flag {
     name: "archiving"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to enable the archiving feature."
     bug: "278553670"
@@ -24,6 +26,7 @@
 
 flag {
     name: "stay_stopped"
+    is_exported: true
     namespace: "backstage_power"
     description: "Feature flag to improve stopped state enforcement"
     bug: "296644915"
@@ -39,6 +42,7 @@
 
 flag {
     name: "get_package_info"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to enable the feature to retrieve package info without installation."
     bug: "269149275"
@@ -54,6 +58,7 @@
 
 flag {
     name: "sdk_lib_independence"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to keep app working even if its declared sdk-library dependency is unavailable."
     bug: "295827951"
@@ -78,6 +83,7 @@
 
 flag {
     name: "get_resolved_apk_path"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to retrieve resolved path of the base APK during an app install."
     bug: "269728874"
@@ -92,6 +98,7 @@
 
 flag {
     name: "read_install_info"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to read install related information from an APK."
     bug: "275658500"
@@ -113,6 +120,7 @@
 
 flag {
     name: "relative_reference_intent_filters"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to enable relative reference intent filters"
     bug: "307556883"
@@ -121,6 +129,7 @@
 
 flag {
     name: "fix_duplicated_flags"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to fix duplicated PackageManager flag values"
     bug: "314815969"
@@ -128,6 +137,7 @@
 
 flag {
     name: "provide_info_of_apk_in_apex"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to provide the information of APK-in-APEX"
     bug: "306329516"
@@ -144,6 +154,7 @@
 
 flag {
     name: "introduce_media_processing_type"
+    is_exported: true
     namespace: "backstage_power"
     description: "Add a new FGS type for media processing use cases."
     bug: "317788011"
@@ -182,6 +193,7 @@
 
 flag {
     name: "emergency_install_permission"
+    is_exported: true
     namespace: "permissions"
     description: "Feature flag to enable permission EMERGENCY_INSTALL_PACKAGES"
     bug: "321080601"
@@ -189,6 +201,7 @@
 
 flag {
     name: "asl_in_apk_app_metadata_source"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to allow to know if the Android Safety Label (ASL) of an app is provided by the app's APK itself, or provided by an installer."
     bug: "287487923"
@@ -205,6 +218,7 @@
 
 flag {
     name: "set_pre_verified_domains"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Feature flag to enable pre-verified domains"
     bug: "307327678"
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 2d32aed..4963a4f 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -24,6 +24,7 @@
 
 flag {
     name: "support_communal_profile"
+    is_exported: true
     namespace: "multiuser"
     description: "Framework support for communal profile."
     bug: "285426179"
@@ -31,6 +32,7 @@
 
 flag {
     name: "support_communal_profile_nextgen"
+    is_exported: true
     namespace: "multiuser"
     description: "Further framework support for communal profile, beyond the basics, for later releases."
     bug: "285426179"
@@ -59,6 +61,7 @@
 
 flag {
     name: "enable_biometrics_to_unlock_private_space"
+    is_exported: true
     namespace: "profile_experiences"
     description: "Add support to unlock the private space using biometrics"
     bug: "312184187"
@@ -102,6 +105,7 @@
 
 flag {
     name: "enable_system_user_only_for_services_and_providers"
+    is_exported: true
     namespace: "multiuser"
     description: "Enable systemUserOnly manifest attribute for services and providers."
     bug: "302354856"
@@ -118,6 +122,7 @@
 
 flag {
     name: "enable_permission_to_access_hidden_profiles"
+    is_exported: true
     namespace: "profile_experiences"
     description: "Add permission to access API hidden users data via system APIs"
     bug: "321988638"
diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig
index 7fd0b03..8f5c912 100644
--- a/core/java/android/content/res/flags.aconfig
+++ b/core/java/android/content/res/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "default_locale"
+    is_exported: true
     namespace: "resource_manager"
     description: "Feature flag for default locale in LocaleConfig"
     bug: "117306409"
@@ -11,6 +12,7 @@
 
 flag {
     name: "font_scale_converter_public"
+    is_exported: true
     namespace: "accessibility"
     description: "Enables the public API for FontScaleConverter, including enabling thread-safe caching."
     bug: "239736383"
@@ -20,6 +22,7 @@
 
 flag {
     name: "asset_file_descriptor_frro"
+    is_exported: true
     namespace: "resource_manager"
     description: "Feature flag for passing in an AssetFileDescriptor to create an frro"
     bug: "304478666"
@@ -27,6 +30,7 @@
 
 flag {
     name: "manifest_flagging"
+    is_exported: true
     namespace: "resource_manager"
     description: "Feature flag for flagging manifest entries"
     bug: "297373084"
@@ -36,6 +40,7 @@
 
 flag {
     name: "nine_patch_frro"
+    is_exported: true
     namespace: "resource_manager"
     description: "Feature flag for creating an frro from a 9-patch"
     bug: "296324826"
@@ -43,6 +48,7 @@
 
 flag {
     name: "register_resource_paths"
+    is_exported: true
     namespace: "resource_manager"
     description: "Feature flag for register resource paths for shared library"
     bug: "306202569"
diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig
index 16ca31f..d077329 100644
--- a/core/java/android/credentials/flags.aconfig
+++ b/core/java/android/credentials/flags.aconfig
@@ -3,6 +3,7 @@
 flag {
     namespace: "credential_manager"
     name: "settings_activity_enabled"
+    is_exported: true
     description: "Enable the Credential Manager Settings Activity APIs"
     bug: "300014059"
 }
@@ -24,6 +25,7 @@
 flag {
     namespace: "credential_manager"
     name: "new_settings_intents"
+    is_exported: true
     description: "Enables settings intents to redirect to new settings page"
     bug: "307587989"
 }
@@ -45,6 +47,7 @@
 flag {
     namespace: "credential_manager"
     name: "configurable_selector_ui_enabled"
+    is_exported: true
     description: "Enables OEM configurable Credential Selector UI"
     bug: "319448437"
     is_exported: true
diff --git a/core/java/android/database/sqlite/flags.aconfig b/core/java/android/database/sqlite/flags.aconfig
index 92ef9c2..7ecffaf 100644
--- a/core/java/android/database/sqlite/flags.aconfig
+++ b/core/java/android/database/sqlite/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
      name: "sqlite_apis_35"
+     is_exported: true
      namespace: "system_performance"
      is_fixed_read_only: true
      description: "SQLite APIs held back for Android 15"
diff --git a/core/java/android/hardware/biometrics/flags.aconfig b/core/java/android/hardware/biometrics/flags.aconfig
index ff07498..9836eec 100644
--- a/core/java/android/hardware/biometrics/flags.aconfig
+++ b/core/java/android/hardware/biometrics/flags.aconfig
@@ -18,6 +18,7 @@
 
 flag {
   name: "get_op_id_crypto_object"
+  is_exported: true
   namespace: "biometrics_framework"
   description: "Feature flag for adding a get operation id api to CryptoObject."
   bug: "307601768"
@@ -25,8 +26,8 @@
 
 flag {
   name: "custom_biometric_prompt"
+  is_exported: true
   namespace: "biometrics_framework"
   description: "Feature flag for adding a custom content view API to BiometricPrompt.Builder."
   bug: "302735104"
 }
-
diff --git a/core/java/android/hardware/devicestate/feature/flags.aconfig b/core/java/android/hardware/devicestate/feature/flags.aconfig
index 73a9e34..e474603 100644
--- a/core/java/android/hardware/devicestate/feature/flags.aconfig
+++ b/core/java/android/hardware/devicestate/feature/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "device_state_property_api"
+    is_exported: true
     namespace: "windowing_sdk"
     description: "Updated DeviceState hasProperty API"
     bug: "293636629"
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index b0f69f5..81e321d 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -83,8 +83,7 @@
 
 /**
  * A class that coordinates access to the fingerprint hardware.
- *
- * @removed See {@link BiometricPrompt} which shows a system-provided dialog upon starting
+ * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting
  * authentication. In a world where devices may have different types of biometric authentication,
  * it's much more realistic to have a system-provided authentication dialog since the method may
  * vary by vendor/device.
@@ -95,6 +94,7 @@
 @RequiresFeature(PackageManager.FEATURE_FINGERPRINT)
 public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {
     private static final String TAG = "FingerprintManager";
+    private static final boolean DEBUG = true;
     private static final int MSG_ENROLL_RESULT = 100;
     private static final int MSG_ACQUIRED = 101;
     private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
@@ -196,7 +196,6 @@
 
     /**
      * Retrieves a test session for FingerprintManager.
-     *
      * @hide
      */
     @TestApi
@@ -255,10 +254,9 @@
     }
 
     /**
-     * A wrapper class for the crypto objects supported by FingerprintManager. Currently, the
+     * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
      * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
-     *
-     * @removed See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
+     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
      */
     @Deprecated
     public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
@@ -332,8 +330,7 @@
     /**
      * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
      *     CancellationSignal, int, AuthenticationCallback, Handler)}.
-     *
-     * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
+     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
      */
     @Deprecated
     public static class AuthenticationResult {
@@ -395,8 +392,7 @@
      * FingerprintManager#authenticate(CryptoObject, CancellationSignal,
      * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
      * fingerprint events.
-     *
-     * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
+     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
      */
     @Deprecated
     public static abstract class AuthenticationCallback
@@ -459,7 +455,6 @@
     /**
      * Callback structure provided for {@link #detectFingerprint(CancellationSignal,
      * FingerprintDetectionCallback, int, Surface)}.
-     *
      * @hide
      */
     public interface FingerprintDetectionCallback {
@@ -613,8 +608,7 @@
      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
      *         facility</a>.
      * @throws IllegalStateException if the crypto primitive is not initialized.
-     *
-     * @removed See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
+     * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
      * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate(
      * BiometricPrompt.CryptoObject, CancellationSignal, Executor,
      * BiometricPrompt.AuthenticationCallback)}
@@ -629,7 +623,6 @@
     /**
      * Per-user version of authenticate.
      * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
-     *
      * @hide
      */
     @Deprecated
@@ -642,7 +635,6 @@
     /**
      * Per-user and per-sensor version of authenticate.
      * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
-     *
      * @hide
      */
     @Deprecated
@@ -659,7 +651,6 @@
 
     /**
      * Version of authenticate with additional options.
-     *
      * @hide
      */
     @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
@@ -707,7 +698,6 @@
     /**
      * Uses the fingerprint hardware to detect for the presence of a finger, without giving details
      * about accept/reject/lockout.
-     *
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -750,7 +740,6 @@
      * @param callback an object to receive enrollment events
      * @param shouldLogMetrics a flag that indicates if enrollment failure/success metrics
      * should be logged.
-     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -821,7 +810,6 @@
     /**
      * Same as {@link #generateChallenge(int, GenerateChallengeCallback)}, but assumes the first
      * enumerated sensor.
-     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -836,7 +824,6 @@
 
     /**
      * Revokes the specified challenge.
-     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -862,7 +849,6 @@
      * @param sensorId Sensor ID that this operation takes effect for
      * @param userId User ID that this operation takes effect for.
      * @param hardwareAuthToken An opaque token returned by password confirmation.
-     *
      * @hide
      */
     @RequiresPermission(RESET_FINGERPRINT_LOCKOUT)
@@ -900,7 +886,6 @@
 
     /**
      * Removes all fingerprint templates for the given user.
-     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -1020,7 +1005,6 @@
     /**
      * Forwards BiometricStateListener to FingerprintService
      * @param listener new BiometricStateListener being added
-     *
      * @hide
      */
     public void registerBiometricStateListener(@NonNull BiometricStateListener listener) {
@@ -1172,8 +1156,7 @@
     }
 
     /**
-     * This is triggered by SideFpsEventHandler.
-     *
+     * This is triggered by SideFpsEventHandler
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -1186,8 +1169,7 @@
      * Determine if there is at least one fingerprint enrolled.
      *
      * @return true if at least one fingerprint is enrolled, false otherwise
-     *
-     * @removed See {@link BiometricPrompt} and
+     * @deprecated See {@link BiometricPrompt} and
      * {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS}
      */
     @Deprecated
@@ -1221,8 +1203,7 @@
      * Determine if fingerprint hardware is present and functional.
      *
      * @return true if hardware is present and functional, false otherwise.
-     *
-     * @removed See {@link BiometricPrompt} and
+     * @deprecated See {@link BiometricPrompt} and
      * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE}
      */
     @Deprecated
@@ -1248,7 +1229,6 @@
 
     /**
      * Get statically configured sensor properties.
-     *
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -1267,7 +1247,6 @@
     /**
      * Returns whether the device has a power button fingerprint sensor.
      * @return boolean indicating whether power button is fingerprint sensor
-     *
      * @hide
      */
     public boolean isPowerbuttonFps() {
diff --git a/core/java/android/hardware/flags/overlayproperties_flags.aconfig b/core/java/android/hardware/flags/overlayproperties_flags.aconfig
index c6a352e..1165e65 100644
--- a/core/java/android/hardware/flags/overlayproperties_flags.aconfig
+++ b/core/java/android/hardware/flags/overlayproperties_flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "overlayproperties_class_api"
+    is_exported: true
     namespace: "core_graphics"
     description: "public OverlayProperties class, OverlayProperties#supportMixedColorSpaces and Display#getOverlaySupport API"
     bug: "267234573"
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index e070fe5..9684e64 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -27,6 +27,7 @@
 flag {
     namespace: "input_native"
     name: "pointer_coords_is_resampled_api"
+    is_exported: true
     description: "Makes MotionEvent.PointerCoords#isResampled() a public API"
     bug: "298197511"
 }
@@ -34,6 +35,7 @@
 flag {
     namespace: "input_native"
     name: "emoji_and_screenshot_keycodes_available"
+    is_exported: true
     description: "Add new KeyEvent keycodes for opening Emoji Picker and Taking Screenshots"
     bug: "315307777"
 }
diff --git a/core/java/android/hardware/radio/flags.aconfig b/core/java/android/hardware/radio/flags.aconfig
index dbc1a4b..d0d10c1 100644
--- a/core/java/android/hardware/radio/flags.aconfig
+++ b/core/java/android/hardware/radio/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "hd_radio_improved"
+    is_exported: true
     namespace: "car_framework"
     description: "Feature flag for improved HD radio support with less vendor extensions"
     bug: "280300929"
diff --git a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
index 9e487e1..fac02ce 100644
--- a/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
+++ b/core/java/android/hardware/usb/flags/system_sw_usb_flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "enable_usb_data_compliance_warning"
+    is_exported: true
     namespace: "system_sw_usb"
     description: "Enable USB data compliance warnings when set"
     bug: "296119135"
diff --git a/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig b/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
index a495631..3dd746c 100644
--- a/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
+++ b/core/java/android/hardware/usb/flags/usb_framework_flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "enable_is_pd_compliant_api"
+    is_exported: true
     namespace: "usb"
     description: "Feature flag for the api to check if a port is PD compliant"
     bug: "323470419"
@@ -9,6 +10,7 @@
 
 flag {
     name: "enable_is_mode_change_supported_api"
+    is_exported: true
     namespace: "usb"
     description: "Feature flag for the api to check if a port supports mode change"
     bug: "323470419"
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 375d729..311e991 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -26,6 +26,7 @@
 
 flag {
     name: "remove_app_profiler_pss_collection"
+    is_exported: true
     namespace: "backstage_power"
     description: "Replaces background PSS collection in AppProfiler with RSS"
     bug: "297542292"
@@ -33,6 +34,7 @@
 
 flag {
     name: "allow_thermal_headroom_thresholds"
+    is_exported: true
     namespace: "game"
     description: "Enable thermal headroom thresholds API"
     bug: "288119641"
@@ -41,6 +43,7 @@
 # This flag guards the private space feature, its APIs, and some of the feature implementations. The flag android.multiuser.Flags.enable_private_space_features exclusively guards all the implementations.
 flag {
     name: "allow_private_profile"
+    is_exported: true
     namespace: "profile_experiences"
     description: "Guards a new Private Profile type in UserManager - everything from its setup to config to deletion."
     bug: "299069460"
@@ -49,6 +52,7 @@
 
 flag {
     name: "bugreport_mode_max_value"
+    is_exported: true
     namespace: "telephony"
     description: "Introduce a constant as maximum value of bugreport mode."
     bug: "305067125"
@@ -56,6 +60,7 @@
 
 flag {
     name: "adpf_prefer_power_efficiency"
+    is_exported: true
     namespace: "game"
     description: "Guards the ADPF power efficiency API"
     bug: "288117936"
@@ -63,6 +68,7 @@
 
 flag {
     name: "security_state_service"
+    is_exported: true
     namespace: "dynamic_spl"
     description: "Guards the Security State API."
     bug: "302189431"
@@ -70,6 +76,7 @@
 
 flag {
     name: "battery_saver_supported_check_api"
+    is_exported: true
     namespace: "backstage_power"
     description: "Guards a new API in PowerManager to check if battery saver is supported or not."
     bug: "305067031"
@@ -77,6 +84,7 @@
 
 flag {
     name: "adpf_gpu_report_actual_work_duration"
+    is_exported: true
     namespace: "game"
     description: "Guards the ADPF GPU APIs."
     bug: "284324521"
@@ -114,6 +122,7 @@
 
 flag {
     name: "battery_part_status_api"
+    is_exported: true
     namespace: "phoenix"
     description: "Feature flag for adding Health HAL v3 APIs."
     is_fixed_read_only: true
@@ -122,6 +131,7 @@
 
 flag {
     name: "storage_lifetime_api"
+    is_exported: true
     namespace: "phoenix"
     description: "Feature flag for adding storage component health APIs."
     is_fixed_read_only: true
@@ -131,6 +141,7 @@
 flag {
      namespace: "system_performance"
      name: "telemetry_apis_framework_initialization"
+     is_exported: true
      description: "Control framework initialization APIs of telemetry APIs feature."
      is_fixed_read_only: true
      bug: "324241334"
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index d485eca..bb0498e 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -10,6 +10,7 @@
 flag {
     namespace: "haptics"
     name: "haptics_customization_enabled"
+    is_exported: true
     description: "Enables the haptics customization feature"
     bug: "241918098"
 }
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 999bc99..2710df2 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
   name: "device_aware_permission_apis_enabled"
+  is_exported: true
   is_fixed_read_only: true
   namespace: "permissions"
   description: "enable device aware permission APIs"
@@ -10,6 +11,7 @@
 
 flag {
   name: "voice_activation_permission_apis"
+  is_exported: true
   namespace: "permissions"
   description: "enable voice activation permission APIs"
   bug: "287264308"
@@ -17,6 +19,7 @@
 
 flag {
     name: "system_server_role_controller_enabled"
+    is_exported: true
     is_fixed_read_only: true
     namespace: "permissions"
     description: "enable role controller in system server"
@@ -25,6 +28,7 @@
 
 flag {
   name: "set_next_attribution_source"
+  is_exported: true
   namespace: "permissions"
   description: "enable AttributionSource.setNextAttributionSource"
   bug: "304478648"
@@ -32,6 +36,7 @@
 
 flag {
     name: "should_register_attribution_source"
+    is_exported: true
     namespace: "permissions"
     description: "enable the shouldRegisterAttributionSource API"
     bug: "305057691"
@@ -39,6 +44,7 @@
 
 flag {
   name: "attribution_source_constructor"
+  is_exported: true
   namespace: "permissions"
   description: "enable AttributionSource(int, int, String, String, IBinder, String[], AttributionSource)"
   bug: "304478648"
@@ -46,6 +52,7 @@
 
 flag {
     name: "enhanced_confirmation_mode_apis_enabled"
+    is_exported: true
     is_fixed_read_only: true
     namespace: "permissions"
     description: "enable enhanced confirmation mode apis"
@@ -54,6 +61,7 @@
 
 flag {
   name: "op_enable_mobile_data_by_user"
+  is_exported: true
   namespace: "permissions"
   description: "enables logging of the OP_ENABLE_MOBILE_DATA_BY_USER"
   bug: "222650148"
@@ -61,6 +69,7 @@
 
 flag {
   name: "factory_reset_prep_permission_apis"
+  is_exported: true
   namespace: "wallet_integration"
   description: "enable Permission PREPARE_FACTORY_RESET."
   bug: "302016478"
@@ -68,6 +77,7 @@
 
 flag {
     name: "retail_demo_role_enabled"
+    is_exported: true
     namespace: "permissions"
     description: "default retail demo role holder"
     bug: "274132354"
@@ -82,6 +92,7 @@
 
 flag {
     name: "wallet_role_enabled"
+    is_exported: true
     namespace: "wallet_integration"
     description: "This flag is used to enabled the Wallet Role for all users on the device"
     bug: "283989236"
@@ -114,6 +125,7 @@
 
 flag {
      name: "get_emergency_role_holder_api_enabled"
+     is_exported: true
      is_fixed_read_only: true
      namespace: "permissions"
      description: "Enables the getEmergencyRoleHolder API."
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 25c2b0e..d0593e7 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12389,6 +12389,10 @@
         /**
          * Whether or not secure windows should be disabled. This only works on debuggable builds.
          *
+         * <p>When this setting is set to a non-zero value, all windows are treated as non-secure.
+         * Content in windows with {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} will
+         * appear in screenshots and recordings.
+         *
          * @hide
          */
         public static final String DISABLE_SECURE_WINDOWS = "disable_secure_windows";
diff --git a/core/java/android/provider/flags.aconfig b/core/java/android/provider/flags.aconfig
index ea1ac27..9245557 100644
--- a/core/java/android/provider/flags.aconfig
+++ b/core/java/android/provider/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "system_settings_default"
+    is_exported: true
     namespace: "package_manager_service"
     description: "Enable Settings.System.resetToDefault APIs."
     bug: "279083734"
@@ -9,6 +10,7 @@
 
 flag {
     name: "user_keys"
+    is_exported: true
     namespace: "privacy_infra_policy"
     description: "This flag controls new E2EE contact keys API"
     bug: "290696572"
@@ -16,6 +18,7 @@
 
 flag {
     name: "backup_tasks_settings_screen"
+    is_exported: true
     namespace: "backstage_power"
     description: "Add a new settings page for the RUN_BACKUP_JOBS permission."
     bug: "320563660"
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 3c77c44..7f5b550 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -10,6 +10,7 @@
 
 flag {
     name: "fsverity_api"
+    is_exported: true
     namespace: "hardware_backed_security"
     description: "Feature flag for fs-verity API"
     bug: "285185747"
@@ -64,6 +65,7 @@
 
 flag {
     name: "frp_enforcement"
+    is_exported: true
     namespace: "hardware_backed_security"
     description: "This flag controls whether PDB enforces FRP"
     bug: "290312729"
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index 0bae459..548f8aa 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -9,6 +9,7 @@
 
 flag {
     name: "asm_restrictions_enabled"
+    is_exported: true
     namespace: "responsible_apis"
     description: "Enables ASM restrictions for activity starts and finishes"
     bug: "230590090"
@@ -23,6 +24,7 @@
 
 flag {
     name: "content_uri_permission_apis"
+    is_exported: true
     namespace: "responsible_apis"
     description: "Enables the content URI permission APIs"
     bug: "293467489"
@@ -30,6 +32,7 @@
 
 flag {
     name: "enforce_intent_filter_match"
+    is_exported: true
     namespace: "responsible_apis"
     description: "Make delivered intents match components' intent filters"
     bug: "293560872"
diff --git a/core/java/android/service/appprediction/flags/flags.aconfig b/core/java/android/service/appprediction/flags/flags.aconfig
index c7e47d4..7f9764e 100644
--- a/core/java/android/service/appprediction/flags/flags.aconfig
+++ b/core/java/android/service/appprediction/flags/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
   name: "service_features_api"
+  is_exported: true
   namespace: "systemui"
   description: "Guards the new requestServiceFeatures api"
   bug: "292565550"
diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig
index 00236df..a3eff3b 100644
--- a/core/java/android/service/chooser/flags.aconfig
+++ b/core/java/android/service/chooser/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
   name: "chooser_album_text"
+  is_exported: true
   namespace: "intentresolver"
   description: "Flag controlling the album text subtype hint for sharesheet"
   bug: "323380224"
@@ -9,6 +10,7 @@
 
 flag {
     name: "enable_sharesheet_metadata_extra"
+    is_exported: true
     namespace: "intentresolver"
     description: "This flag enables sharesheet metadata to be displayed to users."
     bug: "318942069"
@@ -16,6 +18,7 @@
 
 flag {
   name: "chooser_payload_toggling"
+  is_exported: true
   namespace: "intentresolver"
   description: "This flag controls content toggling in Chooser"
   bug: "302691505"
@@ -23,6 +26,7 @@
 
 flag {
   name: "enable_chooser_result"
+  is_exported: true
   namespace: "intentresolver"
   description: "Provides additional callbacks with information about user actions in ChooserResult"
   bug: "263474465"
diff --git a/core/java/android/service/controls/flags/flags.aconfig b/core/java/android/service/controls/flags/flags.aconfig
index 3a28844..197f1bc 100644
--- a/core/java/android/service/controls/flags/flags.aconfig
+++ b/core/java/android/service/controls/flags/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "home_panel_dream"
+    is_exported: true
     namespace: "systemui"
     description: "Enables the home controls dream feature."
     bug: "298025023"
diff --git a/core/java/android/service/notification/flags.aconfig b/core/java/android/service/notification/flags.aconfig
index c5acc2c..35cd3ed 100644
--- a/core/java/android/service/notification/flags.aconfig
+++ b/core/java/android/service/notification/flags.aconfig
@@ -10,6 +10,7 @@
 
 flag {
   name: "redact_sensitive_notifications_from_untrusted_listeners"
+  is_exported: true
   namespace: "systemui"
   description: "This flag controls the redacting of sensitive notifications from untrusted NotificationListenerServices"
   bug: "306271190"
@@ -18,6 +19,7 @@
 
 flag {
   name: "callstyle_callback_api"
+  is_exported: true
   namespace: "systemui"
   description: "Guards the new CallStyleNotificationEventsCallback"
   bug: "305095040"
diff --git a/core/java/android/service/voice/flags/flags.aconfig b/core/java/android/service/voice/flags/flags.aconfig
index 22e8cdd..633304b 100644
--- a/core/java/android/service/voice/flags/flags.aconfig
+++ b/core/java/android/service/voice/flags/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "allow_training_data_egress_from_hds"
+    is_exported: true
     namespace: "machine_learning"
     description: "This flag allows the hotword detection service to egress training data to the default assistant."
     bug: "296074924"
@@ -9,6 +10,7 @@
 
 flag {
     name: "allow_hotword_bump_egress"
+    is_exported: true
     namespace: "machine_learning"
     description: "This flag allows hotword detection service to egress reason code for hotword bump."
     bug: "290951024"
@@ -16,6 +18,7 @@
 
 flag {
     name: "allow_foreground_activities_in_on_show"
+    is_exported: true
     namespace: "machine_learning"
     description: "This flag allows providing foreground app component along with onShow args."
     bug: "319409708"
@@ -23,6 +26,7 @@
 
 flag {
     name: "allow_various_attention_types"
+    is_exported: true
     namespace: "visual_query"
     description: "This flag allows visual query detection service to set different attention types."
     bug: "318617199"
@@ -30,6 +34,7 @@
 
 flag {
     name: "allow_complex_results_egress_from_vqds"
+    is_exported: true
     namespace: "visual_query"
     description: "This flag allows visual query detection service egress detailed results. "
     bug: "318617199"
@@ -37,6 +42,7 @@
 
 flag {
     name: "allow_speaker_id_egress"
+    is_exported: true
     namespace: "machine_learning"
     description: "This flag allows hotword detection service and visual query detection service to egress current speaker profile id."
     bug: "318617199"
diff --git a/core/java/android/speech/flags/speech_flags.aconfig b/core/java/android/speech/flags/speech_flags.aconfig
index fd80127..fa33592 100644
--- a/core/java/android/speech/flags/speech_flags.aconfig
+++ b/core/java/android/speech/flags/speech_flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "multilang_extra_launch"
+    is_exported: true
     namespace: "machine_learning"
     description: "Feature flag for adding new extra for multi-lang feature"
     bug: "312489931"
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index 30b1a2e..8e1ac63 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -10,6 +10,7 @@
 
 flag {
   name: "new_fonts_fallback_xml"
+  is_exported: true
   namespace: "text"
   description: "Feature flag for deprecating fonts.xml. By setting true for this feature flag, the new font configuration XML, /system/etc/font_fallback.xml is used. The new XML has a new syntax and flexibility of variable font declarations, but it is not compatible with the apps that reads fonts.xml. So, fonts.xml is maintained as a subset of the font_fallback.xml"
   # Make read only, as it could be used before the Settings provider is initialized.
@@ -26,6 +27,7 @@
 
 flag {
   name: "fix_line_height_for_locale"
+  is_exported: true
   namespace: "text"
   description: "Feature flag that preserve the line height of the TextView and EditText even if the the locale is different from Latin"
   bug: "303326708"
@@ -33,6 +35,7 @@
 
 flag {
   name: "no_break_no_hyphenation_span"
+  is_exported: true
   namespace: "text"
   description: "A feature flag that adding new spans that prevents line breaking and hyphenation."
   bug: "283193586"
@@ -57,6 +60,7 @@
 
 flag {
   name: "use_bounds_for_width"
+  is_exported: true
   namespace: "text"
   description: "Feature flag for preventing horizontal clipping."
   bug: "63938206"
@@ -71,6 +75,7 @@
 
 flag {
   name: "word_style_auto"
+  is_exported: true
   namespace: "text"
   description: "A feature flag that implements line break word style auto."
   bug: "280005585"
@@ -78,6 +83,7 @@
 
 flag {
   name: "letter_spacing_justification"
+  is_exported: true
   namespace: "text"
   description: "A feature flag that implement inter character justification."
   bug: "283193133"
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index 5b99c71f..91bd4ea 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -4,6 +4,7 @@
 
 flag {
     name: "a11y_overlay_callbacks"
+    is_exported: true
     namespace: "accessibility"
     description: "Whether to allow the passing of result callbacks when attaching a11y overlays."
     bug: "304478691"
@@ -26,6 +27,7 @@
 flag {
     namespace: "accessibility"
     name: "braille_display_hid"
+    is_exported: true
     description: "Enables new APIs for an AccessibilityService to communicate with a HID Braille display"
     bug: "303522222"
 }
@@ -40,6 +42,7 @@
 flag {
     namespace: "accessibility"
     name: "collection_info_item_counts"
+    is_exported: true
     description: "Fields for total items and the number of important for accessibility items in a collection"
     bug: "302376158"
 }
@@ -61,6 +64,7 @@
 flag {
     namespace: "accessibility"
     name: "flash_notification_system_api"
+    is_exported: true
     description: "Makes flash notification APIs as system APIs for calling from mainline module"
     bug: "303131332"
 }
@@ -74,6 +78,7 @@
 
 flag {
     name: "motion_event_observing"
+    is_exported: true
     namespace: "accessibility"
     description: "Allows accessibility services to intercept but not consume motion events from specified sources."
     bug: "297595990"
@@ -82,6 +87,7 @@
 flag {
     namespace: "accessibility"
     name: "granular_scrolling"
+    is_exported: true
     description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen"
     bug: "302376158"
 }
@@ -103,6 +109,7 @@
 flag {
     namespace: "accessibility"
     name: "add_type_window_control"
+    is_exported: true
     description: "adds new TYPE_WINDOW_CONTROL to AccessibilityWindowInfo for detecting Window Decorations"
     bug: "320445550"
 }
diff --git a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
index 5d3153c..4de0f29 100644
--- a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
+++ b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
@@ -23,6 +23,7 @@
 
 flag {
     name: "create_accessibility_overlay_app_op_enabled"
+    is_exported: true
     namespace: "content_protection"
     description: "If true, an appop is logged on creation of accessibility overlays."
     bug: "289081465"
@@ -30,6 +31,7 @@
 
 flag {
     name: "rapid_clear_notifications_by_listener_app_op_enabled"
+    is_exported: true
     namespace: "content_protection"
     description: "If true, an appop is logged when a notification is rapidly cleared by a notification listener."
     bug: "289080543"
@@ -37,6 +39,7 @@
 
 flag {
     name: "manage_device_policy_enabled"
+    is_exported: true
     namespace: "content_protection"
     description: "If true, the APIs to manage content protection device policy will be enabled."
     bug: "319477846"
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index 05cabd5..06598b3 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "view_velocity_api"
+    is_exported: true
     namespace: "toolkit"
     description: "Feature flag for view content velocity api"
     bug: "293513816"
@@ -16,6 +17,7 @@
 
 flag {
     name: "toolkit_set_frame_rate_read_only"
+    is_exported: true
     namespace: "toolkit"
     description: "Feature flag for toolkit to set frame rate"
     bug: "293512962"
@@ -24,6 +26,7 @@
 
 flag {
     name: "expected_presentation_time_api"
+    is_exported: true
     namespace: "toolkit"
     description: "Feature flag for using expected presentation time of the Choreographer"
     bug: "278730197"
@@ -31,6 +34,7 @@
 
 flag {
     name: "expected_presentation_time_read_only"
+    is_exported: true
     namespace: "toolkit"
     description: "Feature flag for using expected presentation time of the Choreographer"
     bug: "278730197"
diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig
index d1d871c2..a7c4104 100644
--- a/core/java/android/view/flags/scroll_feedback_flags.aconfig
+++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig
@@ -3,6 +3,7 @@
 flag {
     namespace: "toolkit"
     name: "scroll_feedback_api"
+    is_exported: true
     description: "Enable the scroll feedback APIs"
     bug: "239594271"
 }
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 6cf89d6..c482f8b 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -28,6 +28,7 @@
 
 flag {
   name: "sensitive_content_app_protection_api"
+  is_exported: true
   namespace: "permissions"
   description: "This flag controls the new sensitive content protection API,"
     " The API will be used by other ui toolkits (i.e. compose, webview, custom virtual views)."
diff --git a/core/java/android/view/flags/window_insets.aconfig b/core/java/android/view/flags/window_insets.aconfig
index 201b7ad..bf6df5c 100644
--- a/core/java/android/view/flags/window_insets.aconfig
+++ b/core/java/android/view/flags/window_insets.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "customizable_window_headers"
+    is_exported: true
     namespace: "lse_desktop_experience"
     description: "Flag to control the caption bar appearance and to fit app content in its empty space"
     bug: "316387515"
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index 8d3920f..be74a65 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -10,6 +10,7 @@
 
 flag {
     name: "editorinfo_handwriting_enabled"
+    is_exported: true
     namespace: "input_method"
     description: "Feature flag for adding EditorInfo#mStylusHandwritingEnabled"
     bug: "293898187"
@@ -18,6 +19,7 @@
 
 flag {
     name: "imm_userhandle_hostsidetests"
+    is_exported: true
     namespace: "input_method"
     description: "Feature flag for replacing UserIdInt with UserHandle in some helper IMM functions"
     bug: "301713309"
@@ -26,6 +28,7 @@
 
 flag {
     name: "concurrent_input_methods"
+    is_exported: true
     namespace: "input_method"
     description: "Feature flag for concurrent multi-session IME"
     bug: "284527000"
@@ -34,6 +37,7 @@
 
 flag {
     name: "home_screen_handwriting_delegator"
+    is_exported: true
     namespace: "input_method"
     description: "Feature flag for supporting stylus handwriting delegation from RemoteViews on the home screen"
     bug: "279959705"
@@ -49,6 +53,7 @@
 
 flag {
     name: "use_zero_jank_proxy"
+    is_exported: true
     namespace: "input_method"
     description: "Feature flag for using a proxy that uses async calls to achieve zero jank for IMMS calls."
     bug: "293640003"
@@ -57,6 +62,7 @@
 
 flag {
     name: "ime_switcher_revamp"
+    is_exported: true
     namespace: "input_method"
     description: "Feature flag for revamping the Input Method Switcher menu"
     bug: "311791923"
@@ -73,6 +79,7 @@
 
 flag {
     name: "connectionless_handwriting"
+    is_exported: true
     namespace: "input_method"
     description: "Feature flag for connectionless stylus handwriting APIs"
     bug: "300979854"
diff --git a/core/java/android/webkit/flags.aconfig b/core/java/android/webkit/flags.aconfig
index 6938b29..2d834a8 100644
--- a/core/java/android/webkit/flags.aconfig
+++ b/core/java/android/webkit/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "update_service_ipc_wrapper"
+    is_exported: true
     namespace: "webview"
     description: "New API: proper wrapper for IWebViewUpdateService"
     bug: "319292658"
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 254f4f7..7fbec67 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -18,6 +18,7 @@
 
 flag {
   name: "density_390_api"
+  is_exported: true
   namespace: "large_screen_experiences_app_compat"
   description: "Whether the API DisplayMetrics.DENSITY_390 is available"
   bug: "297550533"
@@ -26,6 +27,7 @@
 
 flag {
   name: "app_compat_properties_api"
+  is_exported: true
   namespace: "large_screen_experiences_app_compat"
   description: "Whether app compat property APIs are public. Which includes: /n"
                  "WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE,/n"
diff --git a/core/java/android/window/flags/wallpaper_manager.aconfig b/core/java/android/window/flags/wallpaper_manager.aconfig
index ea9da96..dea9497 100644
--- a/core/java/android/window/flags/wallpaper_manager.aconfig
+++ b/core/java/android/window/flags/wallpaper_manager.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "always_update_wallpaper_permission"
+    is_exported: true
     namespace: "wear_frameworks"
     description: "Allow out of focus process to update wallpaper complications"
     bug: "271132915"
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 3f48341..00b600c 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -45,6 +45,7 @@
 flag {
     namespace: "window_surfaces"
     name: "trusted_presentation_listener_for_window"
+    is_exported: true
     description: "Enable trustedPresentationListener on windows public API"
     is_fixed_read_only: true
     bug: "278027319"
@@ -53,6 +54,7 @@
 flag {
     namespace: "window_surfaces"
     name: "sdk_desired_present_time"
+    is_exported: true
     description: "Feature flag for the new SDK API to set desired present time"
     is_fixed_read_only: true
     bug: "295038072"
@@ -61,6 +63,7 @@
 flag {
     namespace: "window_surfaces"
     name: "surface_control_input_receiver"
+    is_exported: true
     description: "Enable public API to register an InputReceiver for a SurfaceControl"
     is_fixed_read_only: true
     bug: "278757236"
@@ -69,6 +72,7 @@
 flag {
     namespace: "window_surfaces"
     name: "screen_recording_callbacks"
+    is_exported: true
     description: "Enable screen recording callbacks public API"
     is_fixed_read_only: true
     bug: "304574518"
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 65bf241..247f28c 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -16,6 +16,7 @@
 
 flag {
   name: "enforce_edge_to_edge"
+  is_exported: true
   namespace: "windowing_frontend"
   description: "Make app go edge-to-edge when targeting SDK level 35 or greater"
   bug: "309578419"
@@ -88,6 +89,7 @@
 
 flag {
     name: "supports_multi_instance_system_ui"
+    is_exported: true
     namespace: "multitasking"
     description: "Feature flag to enable a multi-instance system ui component property."
     bug: "262864589"
@@ -96,6 +98,7 @@
 
 flag {
   name: "delegate_unhandled_drags"
+  is_exported: true
   namespace: "multitasking"
   description: "Enables delegating unhandled drags to SystemUI"
   bug: "320797628"
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 82e613e..4b3d8e8 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -43,6 +43,7 @@
 flag {
     namespace: "windowing_sdk"
     name: "untrusted_embedding_any_app_permission"
+    is_exported: true
     description: "Feature flag to enable the permission to embed any app in untrusted mode."
     bug: "293647332"
     is_fixed_read_only: true
@@ -59,6 +60,7 @@
 flag {
     namespace: "windowing_sdk"
     name: "untrusted_embedding_state_sharing"
+    is_exported: true
     description: "Feature flag to enable state sharing in untrusted embedding when apps opt in."
     bug: "293647332"
     is_fixed_read_only: true
@@ -74,6 +76,7 @@
 flag {
     namespace: "windowing_sdk"
     name: "cover_display_opt_in"
+    is_exported: true
     description: "Properties to allow apps and activities to opt-in to cover display rendering"
     bug: "312530526"
     is_fixed_read_only: true
diff --git a/graphics/java/android/framework_graphics.aconfig b/graphics/java/android/framework_graphics.aconfig
index 6c81a60..1e41b4d 100644
--- a/graphics/java/android/framework_graphics.aconfig
+++ b/graphics/java/android/framework_graphics.aconfig
@@ -2,6 +2,7 @@
 
 flag {
      name: "exact_compute_bounds"
+     is_exported: true
      namespace: "core_graphics"
      description: "Add a function without unused exact param for computeBounds."
      bug: "304478551"
@@ -9,6 +10,7 @@
 
 flag {
      name: "yuv_image_compress_to_ultra_hdr"
+     is_exported: true
      namespace: "core_graphics"
      description: "Feature flag for YUV image compress to Ultra HDR."
      bug: "308978825"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt
index 4c34971..9e8dfb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiInstanceHelper.kt
@@ -21,11 +21,9 @@
 import android.content.pm.LauncherApps
 import android.content.pm.PackageManager
 import android.os.UserHandle
-import android.view.WindowManager
 import android.view.WindowManager.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI
 import com.android.internal.annotations.VisibleForTesting
 import com.android.wm.shell.R
-import com.android.wm.shell.protolog.ShellProtoLogGroup
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL
 import com.android.wm.shell.util.KtProtoLog
 import java.util.Arrays
@@ -37,7 +35,8 @@
     private val context: Context,
     private val packageManager: PackageManager,
     private val staticAppsSupportingMultiInstance: Array<String> = context.resources
-            .getStringArray(R.array.config_appsSupportMultiInstancesSplit)) {
+            .getStringArray(R.array.config_appsSupportMultiInstancesSplit),
+    private val supportsMultiInstanceProperty: Boolean) {
 
     /**
      * Returns whether a specific component desires to be launched in multiple instances.
@@ -59,6 +58,11 @@
             }
         }
 
+        if (!supportsMultiInstanceProperty) {
+            // If not checking the multi-instance properties, then return early
+            return false;
+        }
+
         // Check the activity property first
         try {
             val activityProp = packageManager.getProperty(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 8d489e1..5122114 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -29,6 +29,7 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.launcher3.icons.IconProvider;
+import com.android.window.flags.Flags;
 import com.android.wm.shell.ProtoLogController;
 import com.android.wm.shell.R;
 import com.android.wm.shell.RootDisplayAreaOrganizer;
@@ -326,7 +327,8 @@
     @WMSingleton
     @Provides
     static MultiInstanceHelper provideMultiInstanceHelper(Context context) {
-        return new MultiInstanceHelper(context, context.getPackageManager());
+        return new MultiInstanceHelper(context, context.getPackageManager(),
+                Flags.supportsMultiInstanceSystemUi());
     }
 
     //
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiInstanceHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiInstanceHelperTest.kt
index 2f5fe11..bec91e9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiInstanceHelperTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiInstanceHelperTest.kt
@@ -32,9 +32,12 @@
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers
 import org.mockito.ArgumentMatchers.eq
+import org.mockito.kotlin.any
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.doThrow
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
@@ -77,7 +80,7 @@
     @Test
     fun supportsMultiInstanceSplit_inStaticAllowList() {
         val allowList = arrayOf(TEST_PACKAGE)
-        val helper = MultiInstanceHelper(mContext, context.packageManager, allowList)
+        val helper = MultiInstanceHelper(mContext, context.packageManager, allowList, true)
         val component = ComponentName(TEST_PACKAGE, TEST_ACTIVITY)
         assertEquals(true, helper.supportsMultiInstanceSplit(component))
     }
@@ -85,7 +88,7 @@
     @Test
     fun supportsMultiInstanceSplit_notInStaticAllowList() {
         val allowList = arrayOf(TEST_PACKAGE)
-        val helper = MultiInstanceHelper(mContext, context.packageManager, allowList)
+        val helper = MultiInstanceHelper(mContext, context.packageManager, allowList, true)
         val component = ComponentName(TEST_NOT_ALLOWED_PACKAGE, TEST_ACTIVITY)
         assertEquals(false, helper.supportsMultiInstanceSplit(component))
     }
@@ -104,7 +107,7 @@
             eq(component.packageName)))
                 .thenReturn(appProp)
 
-        val helper = MultiInstanceHelper(mContext, pm, emptyArray())
+        val helper = MultiInstanceHelper(mContext, pm, emptyArray(), true)
         // Expect activity property to override application property
         assertEquals(true, helper.supportsMultiInstanceSplit(component))
     }
@@ -123,7 +126,7 @@
             eq(component.packageName)))
                 .thenReturn(appProp)
 
-        val helper = MultiInstanceHelper(mContext, pm, emptyArray())
+        val helper = MultiInstanceHelper(mContext, pm, emptyArray(), true)
         // Expect activity property to override application property
         assertEquals(false, helper.supportsMultiInstanceSplit(component))
     }
@@ -141,7 +144,7 @@
             eq(component.packageName)))
                 .thenReturn(appProp)
 
-        val helper = MultiInstanceHelper(mContext, pm, emptyArray())
+        val helper = MultiInstanceHelper(mContext, pm, emptyArray(), true)
         // Expect fall through to app property
         assertEquals(true, helper.supportsMultiInstanceSplit(component))
     }
@@ -158,10 +161,30 @@
             eq(component.packageName)))
                 .thenThrow(PackageManager.NameNotFoundException())
 
-        val helper = MultiInstanceHelper(mContext, pm, emptyArray())
+        val helper = MultiInstanceHelper(mContext, pm, emptyArray(), true)
         assertEquals(false, helper.supportsMultiInstanceSplit(component))
     }
 
+    @Test
+    @Throws(PackageManager.NameNotFoundException::class)
+    fun checkNoMultiInstancePropertyFlag_ignoreProperty() {
+        val component = ComponentName(TEST_PACKAGE, TEST_ACTIVITY)
+        val pm = mock<PackageManager>()
+        val activityProp = PackageManager.Property("", true, "", "")
+        whenever(pm.getProperty(eq(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI),
+            eq(component)))
+            .thenReturn(activityProp)
+        val appProp = PackageManager.Property("", true, "", "")
+        whenever(pm.getProperty(eq(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI),
+            eq(component.packageName)))
+            .thenReturn(appProp)
+
+        val helper = MultiInstanceHelper(mContext, pm, emptyArray(), false)
+        // Expect we only check the static list and not the property
+        assertEquals(false, helper.supportsMultiInstanceSplit(component))
+        verify(pm, never()).getProperty(any(), any<ComponentName>())
+    }
+
     companion object {
         val TEST_PACKAGE = "com.android.wm.shell.common"
         val TEST_NOT_ALLOWED_PACKAGE = "com.android.wm.shell.common.fake";
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
index 76a0a64..659bcdc 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
   name: "clip_shader"
+  is_exported: true
   namespace: "core_graphics"
   description: "API for canvas shader clipping operations"
   bug: "280116960"
@@ -9,6 +10,7 @@
 
 flag {
   name: "matrix_44"
+  is_exported: true
   namespace: "core_graphics"
   description: "API for 4x4 matrix and related canvas functions"
   bug: "280116960"
@@ -16,6 +18,7 @@
 
 flag {
   name: "limited_hdr"
+  is_exported: true
   namespace: "core_graphics"
   description: "API to enable apps to restrict the amount of HDR headroom that is used"
   bug: "234181960"
@@ -44,6 +47,7 @@
 
 flag {
   name: "gainmap_animations"
+  is_exported: true
   namespace: "core_graphics"
   description: "APIs to help enable animations involving gainmaps"
   bug: "296482289"
@@ -51,6 +55,7 @@
 
 flag {
   name: "gainmap_constructor_with_metadata"
+  is_exported: true
   namespace: "core_graphics"
   description: "APIs to create a new gainmap with a bitmap for metadata."
   bug: "304478551"
@@ -65,6 +70,7 @@
 
 flag {
   name: "requested_formats_v"
+  is_exported: true
   namespace: "core_graphics"
   description: "Enable r_8, r_16_uint, rg_1616_uint, and rgba_10101010 in the SDK"
   bug: "292545615"
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index f33bcb7..ce689ac 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -9,6 +9,7 @@
 
 flag {
     name: "location_bypass"
+    is_exported: true
     namespace: "location"
     description: "Enable location bypass appops behavior"
     bug: "329151785"
diff --git a/media/java/android/media/flags/editing.aconfig b/media/java/android/media/flags/editing.aconfig
index c3997e9..5bf1b4e 100644
--- a/media/java/android/media/flags/editing.aconfig
+++ b/media/java/android/media/flags/editing.aconfig
@@ -2,6 +2,7 @@
 
 flag {
   name: "add_media_metrics_editing"
+  is_exported: true
   namespace: "media_solutions"
   description: "Add media metrics for transcoding/editing events."
   bug: "297487694"
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index bf39425..40929f7 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "enable_rlp_callbacks_in_media_router2"
+    is_exported: true
     namespace: "media_solutions"
     description: "Make RouteListingPreference getter and callbacks public in MediaRouter2."
     bug: "281067101"
@@ -16,6 +17,7 @@
 
 flag {
     name: "enable_audio_policies_device_and_bluetooth_controller"
+    is_exported: true
     namespace: "media_solutions"
     description: "Use Audio Policies implementation for device and Bluetooth route controllers."
     bug: "280576228"
@@ -44,6 +46,7 @@
 
 flag {
     name: "enable_new_media_route_2_info_types"
+    is_exported: true
     namespace: "media_solutions"
     description: "Enables the following type constants in MediaRoute2Info: CAR, COMPUTER, GAME_CONSOLE, SMARTPHONE, SMARTWATCH, TABLET, TABLET_DOCKED. Note that this doesn't gate any behavior. It only guards some API int symbols."
     bug: "301713440"
@@ -51,6 +54,7 @@
 
 flag {
     name: "enable_privileged_routing_for_media_routing_control"
+    is_exported: true
     namespace: "media_solutions"
     description: "Allow access to privileged routing capabilities to MEDIA_ROUTING_CONTROL holders."
     bug: "305919655"
@@ -58,6 +62,7 @@
 
 flag {
     name: "enable_cross_user_routing_in_media_router2"
+    is_exported: true
     namespace: "media_solutions"
     description: "Allows clients of privileged MediaRouter2 that hold INTERACT_ACROSS_USERS_FULL to control routing across users."
     bug: "288580225"
@@ -72,6 +77,7 @@
 
 flag {
      name: "enable_built_in_speaker_route_suitability_statuses"
+     is_exported: true
      namespace: "media_solutions"
      description: "Make MediaRoute2Info provide information about routes suitability for transfer."
      bug: "279555229"
@@ -79,6 +85,7 @@
 
 flag {
     name: "enable_notifying_activity_manager_with_media_session_status_change"
+    is_exported: true
     namespace: "media_solutions"
     description: "Notify ActivityManager with the changes in playback state of the media session."
     bug: "295518668"
@@ -86,6 +93,7 @@
 
 flag {
     name: "enable_get_transferable_routes"
+    is_exported: true
     namespace: "media_solutions"
     description: "Exposes RoutingController#getTransferableRoutes() (previously hidden) to the public API."
     bug: "323154573"
@@ -100,6 +108,7 @@
 
 flag {
     name: "enable_screen_off_scanning"
+    is_exported: true
     namespace: "media_solutions"
     description: "Enable new MediaRouter2 API to enable watch companion apps to scan while the phone screen is off."
     bug: "281072508"
diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig
index f110705..1731e5e 100644
--- a/media/java/android/media/tv/flags/media_tv.aconfig
+++ b/media/java/android/media/tv/flags/media_tv.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "broadcast_visibility_types"
+    is_exported: true
     namespace: "media_tv"
     description: "Constants for standardizing broadcast visibility types."
     bug: "222402395"
@@ -9,6 +10,7 @@
 
 flag {
     name: "enable_ad_service_fw"
+    is_exported: true
     namespace: "media_tv"
     description: "Enable the TV client-side AD framework."
     bug: "303506816"
@@ -16,6 +18,7 @@
 
 flag {
     name: "tiaf_v_apis"
+    is_exported: true
     namespace: "media_tv"
     description: "TIAF V3.0 APIs for Android V"
     bug: "303323657"
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index ba084c0..6d4a17c 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -63,6 +63,7 @@
 
 flag {
     name: "enable_nfc_charging"
+    is_exported: true
     namespace: "nfc"
     description: "Flag for NFC charging changes"
     bug: "292143899"
diff --git a/packages/CrashRecovery/aconfig/flags.aconfig b/packages/CrashRecovery/aconfig/flags.aconfig
index 572a669..8627eac 100644
--- a/packages/CrashRecovery/aconfig/flags.aconfig
+++ b/packages/CrashRecovery/aconfig/flags.aconfig
@@ -10,6 +10,7 @@
 
 flag {
     name: "enable_crashrecovery"
+    is_exported: true
     namespace: "crashrecovery"
     description: "Enables various dependencies of crashrecovery module"
     bug: "289203818"
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm
index 071f9f4..854c2fd 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_uk.kcm
@@ -23,8 +23,8 @@
 ### ROW 1
 
 key GRAVE {
-    label:                              '`'
-    base:                               '`'
+    label:                              '\u0300'
+    base:                               '\u0300'
     shift:                              '\u00AC'
     ralt:                               '\u00A6'
 }
@@ -39,6 +39,7 @@
     label:                              '2'
     base:                               '2'
     shift:                              '"'
+    ralt:                               '\u0308'
 }
 
 key 3 {
@@ -64,6 +65,7 @@
     label:                              '6'
     base:                               '6'
     shift:                              '^'
+    ralt:                               '\u0302'
 }
 
 key 7 {
@@ -202,6 +204,7 @@
     label:                              ']'
     base:                               ']'
     shift:                              '}'
+    shift+ralt:                         '|'
 }
 
 ### ROW 3
@@ -282,14 +285,16 @@
     label:                              '\''
     base:                               '\''
     shift:                              '@'
+    ralt:                               '\u0301'
+    shift+ralt:                         '`'
 }
 
 key POUND {
     label:                              '#'
     base:                               '#'
     shift:                              '~'
-    ralt:                               '\\'
-    shift+ralt:                         '|'
+    ralt:                               '\u0303'
+    shift+ralt:                         '\\'
 }
 
 ### ROW 4
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
index 416b369..baccda7e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
@@ -163,6 +163,16 @@
     default void onAclConnectionStateChanged(
             @NonNull CachedBluetoothDevice cachedDevice, int state) {}
 
+    /**
+     * Called when the Auto-on state is changed for any user. Listens to intent
+     * {@link android.bluetooth.BluetoothAdapter#ACTION_AUTO_ON_STATE_CHANGED }
+     *
+     * @param state        the Auto-on state, the possible values are:
+     *                     {@link android.bluetooth.BluetoothAdapter#AUTO_ON_STATE_ENABLED},
+     *                     {@link android.bluetooth.BluetoothAdapter#AUTO_ON_STATE_DISABLED}
+     */
+    default void onAutoOnStateChanged(int state) {}
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "STATE_" }, value = {
             STATE_DISCONNECTED,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 647fcb9..0996d52 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -133,6 +133,8 @@
         addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler());
         addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler());
 
+        addHandler(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED, new AutoOnStateChangedHandler());
+
         registerAdapterIntentReceiver();
     }
 
@@ -552,4 +554,21 @@
             dispatchAudioModeChanged();
         }
     }
+
+    private class AutoOnStateChangedHandler implements Handler {
+
+        @Override
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            String action = intent.getAction();
+            if (action == null) {
+                Log.w(TAG, "AutoOnStateChangedHandler() action is null");
+                return;
+            }
+            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_AUTO_ON_STATE,
+                    BluetoothAdapter.ERROR);
+            for (BluetoothCallback callback : mCallbacks) {
+                callback.onAutoOnStateChanged(state);
+            }
+        }
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 13635c3..48bbf4e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -489,4 +490,17 @@
         verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
                 eq(R.string.bluetooth_pairing_pin_error_message));
     }
+
+    /**
+     * Intent ACTION_AUTO_ON_STATE_CHANGED should dispatch to callback.
+     */
+    @Test
+    public void intentWithExtraState_autoOnStateChangedShouldDispatchToRegisterCallback() {
+        mBluetoothEventManager.registerCallback(mBluetoothCallback);
+        mIntent = new Intent(BluetoothAdapter.ACTION_AUTO_ON_STATE_CHANGED);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mBluetoothCallback).onAutoOnStateChanged(anyInt());
+    }
 }
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a155dc4..f057acc 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -25,6 +25,16 @@
 }
 
 flag {
+   name: "notification_minimalism_prototype"
+   namespace: "systemui"
+   description: "Prototype of notification minimalism; the new 'Intermediate' lockscreen customization proposal."
+   bug: "330387368"
+   metadata {
+        purpose: PURPOSE_BUGFIX
+   }
+}
+
+flag {
    name: "notification_view_flipper_pausing"
    namespace: "systemui"
    description: "Pause ViewFlippers inside Notification custom layouts when the shade is closed."
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index 1da6c1e..0f3d3dc2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -484,6 +484,7 @@
         onChangeScene = {},
         transitions = SceneTransitions,
         modifier = modifier,
+        enableInterruptions = false,
     ) {
         scene(SceneKeys.ContiguousSceneKey) {
             FoldableScene(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index d0c4984..a1d8c29 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -71,6 +71,7 @@
             currentScene,
             onChangeScene = { viewModel.onSceneChanged(it) },
             transitions = sceneTransitions,
+            enableInterruptions = false,
         )
     val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false)
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index bc4e555..1178cc8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -74,6 +74,7 @@
             transitions =
                 transitions { sceneKeyByBlueprintId.values.forEach { sceneKey -> to(sceneKey) } },
             modifier = modifier,
+            enableInterruptions = false,
         ) {
             sceneKeyByBlueprint.entries.forEach { (blueprint, sceneKey) ->
                 scene(sceneKey) { with(blueprint) { Content(Modifier.fillMaxSize()) } }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt
index d9ed497..a12f099 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt
@@ -80,5 +80,14 @@
 object ClockElementKeys {
     val largeClockElementKey = ElementKey("large-clock")
     val smallClockElementKey = ElementKey("small-clock")
+    val weatherSmallClockElementKey = ElementKey("weather-small-clock")
     val smartspaceElementKey = ElementKey("smart-space")
 }
+
+object WeatherClockElementKeys {
+    val timeElementKey = ElementKey("weather-large-clock-time")
+    val dateElementKey = ElementKey("weather-large-clock-date")
+    val weatherIconElementKey = ElementKey("weather-large-clock-weather-icon")
+    val temperatureElementKey = ElementKey("weather-large-clock-temperature")
+    val dndAlarmElementKey = ElementKey("weather-large-clock-dnd-alarm")
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
index ee4e2d6..fe774a0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
@@ -23,6 +23,8 @@
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.layout.Layout
@@ -33,11 +35,14 @@
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.padding
+import com.android.keyguard.KeyguardClockSwitch.LARGE
 import com.android.systemui.Flags
+import com.android.systemui.customization.R as customizationR
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
+import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChanged
 import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
 import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
 import com.android.systemui.keyguard.ui.composable.section.LockSection
@@ -47,8 +52,8 @@
 import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
 import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
 import com.android.systemui.keyguard.ui.composable.section.WeatherClockSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
-import com.android.systemui.media.controls.ui.composable.MediaCarousel
 import com.android.systemui.res.R
 import com.android.systemui.shade.LargeScreenHeaderHelper
 import dagger.Binds
@@ -71,6 +76,7 @@
     private val settingsMenuSection: SettingsMenuSection,
     private val clockInteractor: KeyguardClockInteractor,
     private val mediaCarouselSection: MediaCarouselSection,
+    private val clockViewModel: KeyguardClockViewModel,
 ) : ComposableLockscreenSceneBlueprint {
 
     override val id: String = WEATHER_CLOCK_BLUEPRINT_ID
@@ -79,7 +85,7 @@
         val isUdfpsVisible = viewModel.isUdfpsVisible
         val burnIn = rememberBurnIn(clockInteractor)
         val resources = LocalContext.current.resources
-
+        val currentClockState = clockViewModel.currentClock.collectAsState()
         LockscreenLongPress(
             viewModel = viewModel.longPress,
             modifier = modifier,
@@ -91,7 +97,34 @@
                         modifier = Modifier.fillMaxWidth(),
                     ) {
                         with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
-                        // TODO: Add weather clock for small and large clock
+                        val currentClock = currentClockState.value
+                        val clockSize by clockViewModel.clockSize.collectAsState()
+                        with(weatherClockSection) {
+                            if (currentClock == null) {
+                                return@with
+                            }
+
+                            if (clockSize == LARGE) {
+                                Time(
+                                    clock = currentClock,
+                                    modifier =
+                                        Modifier.padding(
+                                            start =
+                                                dimensionResource(
+                                                    customizationR.dimen.clock_padding_start
+                                                )
+                                        )
+                                )
+                            } else {
+                                SmallClock(
+                                    burnInParams = burnIn.parameters,
+                                    modifier =
+                                        Modifier.align(Alignment.Start)
+                                            .onTopPlacementChanged(burnIn.onSmallClockTopChanged),
+                                    clock = currentClock
+                                )
+                            }
+                        }
                         with(smartSpaceSection) {
                             SmartSpace(
                                 burnInParams = burnIn.parameters,
@@ -119,6 +152,12 @@
                                 )
                             }
                         }
+                        with(weatherClockSection) {
+                            if (currentClock == null || clockSize != LARGE) {
+                                return@with
+                            }
+                            LargeClockSectionBelowSmartspace(clock = currentClock)
+                        }
 
                         if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
                             with(ambientIndicationSectionOptional.get()) {
@@ -234,6 +273,7 @@
     private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
     private val weatherClockSection: WeatherClockSection,
     private val mediaCarouselSection: MediaCarouselSection,
+    private val clockViewModel: KeyguardClockViewModel,
 ) : ComposableLockscreenSceneBlueprint {
     override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
 
@@ -242,7 +282,7 @@
         val isUdfpsVisible = viewModel.isUdfpsVisible
         val burnIn = rememberBurnIn(clockInteractor)
         val resources = LocalContext.current.resources
-
+        val currentClockState = clockViewModel.currentClock.collectAsState()
         LockscreenLongPress(
             viewModel = viewModel.longPress,
             modifier = modifier,
@@ -257,11 +297,42 @@
                         Row(
                             modifier = Modifier.fillMaxSize(),
                         ) {
-                            // TODO: Add weather clock for small and large clock
                             Column(
                                 modifier = Modifier.fillMaxHeight().weight(weight = 1f),
                                 horizontalAlignment = Alignment.CenterHorizontally,
                             ) {
+                                val currentClock = currentClockState.value
+                                val clockSize by clockViewModel.clockSize.collectAsState()
+                                with(weatherClockSection) {
+                                    if (currentClock == null) {
+                                        return@with
+                                    }
+
+                                    if (clockSize == LARGE) {
+                                        Time(
+                                            clock = currentClock,
+                                            modifier =
+                                                Modifier.align(Alignment.Start)
+                                                    .padding(
+                                                        start =
+                                                            dimensionResource(
+                                                                customizationR.dimen
+                                                                    .clock_padding_start
+                                                            )
+                                                    )
+                                        )
+                                    } else {
+                                        SmallClock(
+                                            burnInParams = burnIn.parameters,
+                                            modifier =
+                                                Modifier.align(Alignment.Start)
+                                                    .onTopPlacementChanged(
+                                                        burnIn.onSmallClockTopChanged
+                                                    ),
+                                            clock = currentClock,
+                                        )
+                                    }
+                                }
                                 with(smartSpaceSection) {
                                     SmartSpace(
                                         burnInParams = burnIn.parameters,
@@ -284,6 +355,14 @@
                                 }
 
                                 with(mediaCarouselSection) { MediaCarousel() }
+
+                                with(weatherClockSection) {
+                                    if (currentClock == null || clockSize != LARGE) {
+                                        return@with
+                                    }
+
+                                    LargeClockSectionBelowSmartspace(currentClock)
+                                }
                             }
                             with(notificationSection) {
                                 val splitShadeTopMargin: Dp =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index 1d86b15..2781f39 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -20,6 +20,7 @@
 import android.view.ViewGroup
 import android.widget.FrameLayout
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
@@ -32,6 +33,7 @@
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.padding
 import com.android.systemui.customization.R as customizationR
+import com.android.systemui.customization.R
 import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.largeClockElementKey
 import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.smallClockElementKey
 import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
@@ -58,19 +60,21 @@
         if (currentClock?.smallClock?.view == null) {
             return
         }
-
         val context = LocalContext.current
         MovableElement(key = smallClockElementKey, modifier = modifier) {
             content {
                 AndroidView(
                     factory = { context ->
                         FrameLayout(context).apply {
-                            addClockView(checkNotNull(currentClock).smallClock.view)
+                            ensureClockViewExists(checkNotNull(currentClock).smallClock.view)
                         }
                     },
-                    update = { it.addClockView(checkNotNull(currentClock).smallClock.view) },
+                    update = {
+                        it.ensureClockViewExists(checkNotNull(currentClock).smallClock.view)
+                    },
                     modifier =
-                        Modifier.padding(
+                        Modifier.height(dimensionResource(R.dimen.small_clock_height))
+                            .padding(
                                 horizontal =
                                     dimensionResource(customizationR.dimen.clock_padding_start)
                             )
@@ -91,23 +95,24 @@
         if (currentClock?.largeClock?.view == null) {
             return
         }
-
         MovableElement(key = largeClockElementKey, modifier = modifier) {
             content {
                 AndroidView(
                     factory = { context ->
                         FrameLayout(context).apply {
-                            addClockView(checkNotNull(currentClock).largeClock.view)
+                            ensureClockViewExists(checkNotNull(currentClock).largeClock.view)
                         }
                     },
-                    update = { it.addClockView(checkNotNull(currentClock).largeClock.view) },
+                    update = {
+                        it.ensureClockViewExists(checkNotNull(currentClock).largeClock.view)
+                    },
                     modifier = Modifier.fillMaxSize()
                 )
             }
         }
     }
 
-    private fun FrameLayout.addClockView(clockView: View) {
+    private fun FrameLayout.ensureClockViewExists(clockView: View) {
         if (contains(clockView)) {
             return
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 7635841..d72d5ca 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -92,6 +92,7 @@
             currentScene = currentScene,
             onChangeScene = {},
             transitions = ClockTransition.defaultClockTransitions,
+            enableInterruptions = false,
         ) {
             scene(ClockScenes.splitShadeLargeClockScene) {
                 Row(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
index 2e7bc2a..d358453 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
@@ -16,45 +16,177 @@
 
 package com.android.systemui.keyguard.ui.composable.section
 
+import android.view.ViewGroup
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.viewinterop.AndroidView
+import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.modifiers.padding
+import com.android.systemui.customization.R
+import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.weatherSmallClockElementKey
+import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockElementKeys
+import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
+import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.plugins.clocks.ClockController
 import javax.inject.Inject
 
 /** Provides small clock and large clock composables for the weather clock layout. */
-class WeatherClockSection @Inject constructor() {
+class WeatherClockSection
+@Inject
+constructor(
+    private val viewModel: KeyguardClockViewModel,
+    private val aodBurnInViewModel: AodBurnInViewModel,
+) {
     @Composable
     fun SceneScope.Time(
+        clock: ClockController,
         modifier: Modifier = Modifier,
     ) {
-        // TODO: compose view
+        WeatherElement(
+            weatherClockElementViewId = R.id.weather_clock_time,
+            clock = clock,
+            elementKey = WeatherClockElementKeys.timeElementKey,
+            modifier = modifier.wrapContentSize(),
+        )
     }
 
     @Composable
-    fun SceneScope.Date(
+    private fun SceneScope.Date(
+        clock: ClockController,
         modifier: Modifier = Modifier,
     ) {
-        // TODO: compose view
+        WeatherElement(
+            weatherClockElementViewId = R.id.weather_clock_date,
+            clock = clock,
+            elementKey = WeatherClockElementKeys.dateElementKey,
+            modifier = modifier,
+        )
     }
 
     @Composable
-    fun SceneScope.Weather(
+    private fun SceneScope.Weather(
+        clock: ClockController,
         modifier: Modifier = Modifier,
     ) {
-        // TODO: compose view
+        WeatherElement(
+            weatherClockElementViewId = R.id.weather_clock_weather_icon,
+            clock = clock,
+            elementKey = WeatherClockElementKeys.weatherIconElementKey,
+            modifier = modifier.wrapContentSize(),
+        )
     }
 
     @Composable
-    fun SceneScope.DndAlarmStatus(
+    private fun SceneScope.DndAlarmStatus(
+        clock: ClockController,
         modifier: Modifier = Modifier,
     ) {
-        // TODO: compose view
+        WeatherElement(
+            weatherClockElementViewId = R.id.weather_clock_alarm_dnd,
+            clock = clock,
+            elementKey = WeatherClockElementKeys.dndAlarmElementKey,
+            modifier = modifier.wrapContentSize(),
+        )
     }
 
     @Composable
-    fun SceneScope.Temperature(
+    private fun SceneScope.Temperature(
+        clock: ClockController,
         modifier: Modifier = Modifier,
     ) {
-        // TODO: compose view
+        WeatherElement(
+            weatherClockElementViewId = R.id.weather_clock_temperature,
+            clock = clock,
+            elementKey = WeatherClockElementKeys.temperatureElementKey,
+            modifier = modifier.wrapContentSize(),
+        )
+    }
+
+    @Composable
+    private fun SceneScope.WeatherElement(
+        weatherClockElementViewId: Int,
+        clock: ClockController,
+        elementKey: ElementKey,
+        modifier: Modifier
+    ) {
+        MovableElement(key = elementKey, modifier) {
+            content {
+                AndroidView(
+                    factory = {
+                        val view =
+                            clock.largeClock.layout.views.first {
+                                it.id == weatherClockElementViewId
+                            }
+                        (view.parent as? ViewGroup)?.removeView(view)
+                        view
+                    },
+                    update = {},
+                    modifier = modifier
+                )
+            }
+        }
+    }
+
+    @Composable
+    fun SceneScope.LargeClockSectionBelowSmartspace(
+        clock: ClockController,
+    ) {
+        Row(
+            modifier =
+                Modifier.height(IntrinsicSize.Max)
+                    .padding(horizontal = dimensionResource(R.dimen.clock_padding_start))
+        ) {
+            Date(clock = clock, modifier = Modifier.wrapContentSize())
+            Box(modifier = Modifier.fillMaxSize()) {
+                Weather(clock = clock, modifier = Modifier.align(Alignment.TopStart))
+                Temperature(clock = clock, modifier = Modifier.align(Alignment.BottomEnd))
+                DndAlarmStatus(clock = clock, modifier = Modifier.align(Alignment.TopEnd))
+            }
+        }
+    }
+
+    @Composable
+    fun SceneScope.SmallClock(
+        burnInParams: BurnInParameters,
+        modifier: Modifier = Modifier,
+        clock: ClockController,
+    ) {
+        val localContext = LocalContext.current
+        MovableElement(key = weatherSmallClockElementKey, modifier) {
+            content {
+                AndroidView(
+                    factory = {
+                        val view = clock.smallClock.view
+                        if (view.parent != null) {
+                            (view.parent as? ViewGroup)?.removeView(view)
+                        }
+                        view
+                    },
+                    modifier =
+                        modifier
+                            .height(dimensionResource(R.dimen.small_clock_height))
+                            .padding(start = dimensionResource(R.dimen.clock_padding_start))
+                            .padding(top = { viewModel.getSmallClockTopMargin(localContext) })
+                            .burnInAware(
+                                viewModel = aodBurnInViewModel,
+                                params = burnInParams,
+                            ),
+                    update = {},
+                )
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 0fdaabe..fe6701c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -79,6 +79,7 @@
             initialScene = currentSceneKey,
             canChangeScene = { toScene -> viewModel.canChangeScene(toScene) },
             transitions = SceneContainerTransitions,
+            enableInterruptions = false,
         )
     }
 
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index 6cff30c..da07f6d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -138,8 +138,9 @@
     // that will actually animate it.
     layoutState.startTransition(transition, transitionKey)
 
-    // The transformation now contains the spec that we should use to instantiate the Animatable.
-    val animationSpec = layoutState.transformationSpec.progressSpec
+    // The transition now contains the transformation spec that we should use to instantiate the
+    // Animatable.
+    val animationSpec = transition.transformationSpec.progressSpec
     val visibilityThreshold =
         (animationSpec as? SpringSpec)?.visibilityThreshold ?: ProgressVisibilityThreshold
     val animatable =
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 82083f9..1b06275 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -18,10 +18,8 @@
 
 package com.android.compose.animation.scene
 
-import android.util.Log
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.AnimationVector1D
-import androidx.compose.animation.core.SpringSpec
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableFloatStateOf
@@ -145,16 +143,6 @@
         }
 
         val transitionState = layoutImpl.state.transitionState
-        if (transitionState is TransitionState.Transition) {
-            // TODO(b/290184746): Better handle interruptions here if state != idle.
-            Log.w(
-                TAG,
-                "start from TransitionState.Transition is not fully supported: from" +
-                    " ${transitionState.fromScene} to ${transitionState.toScene} " +
-                    "(progress ${transitionState.progress})"
-            )
-        }
-
         val fromScene = layoutImpl.scene(transitionState.currentScene)
         val swipes = computeSwipes(fromScene, startedPosition, pointersDown)
         val result =
@@ -269,19 +257,6 @@
     fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
         if (isDrivingTransition || force) {
             layoutState.startTransition(newTransition, newTransition.key)
-
-            // Initialize SwipeTransition.transformationSpec and .swipeSpec. Note that this must be
-            // called right after layoutState.startTransition() is called, because it computes the
-            // current layoutState.transformationSpec().
-            val transformationSpec = layoutState.transformationSpec
-            newTransition.transformationSpec = transformationSpec
-            newTransition.swipeSpec =
-                transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec
-        } else {
-            // We were not driving the transition and we don't force the update, so the specs won't
-            // be used and it doesn't matter which ones we set here.
-            newTransition.transformationSpec = TransformationSpec.Empty
-            newTransition.swipeSpec = SceneTransitions.DefaultSwipeSpec
         }
 
         swipeTransition = newTransition
@@ -616,18 +591,6 @@
     override val isUserInputOngoing: Boolean
         get() = offsetAnimation == null
 
-    /**
-     * The [TransformationSpecImpl] associated to this transition.
-     *
-     * Note: This is lateinit because this [SwipeTransition] is needed by
-     * [BaseSceneTransitionLayoutState] to compute the [TransitionSpec], and it will be set right
-     * after [BaseSceneTransitionLayoutState.startTransition] is called with this transition.
-     */
-    lateinit var transformationSpec: TransformationSpecImpl
-
-    /** The spec to use when animating this transition to either [fromScene] or [toScene]. */
-    lateinit var swipeSpec: SpringSpec<Float>
-
     override val overscrollScope: OverscrollScope =
         object : OverscrollScope {
             override val absoluteDistance: Float
@@ -701,6 +664,9 @@
                 coroutineScope
                     .launch {
                         try {
+                            val swipeSpec =
+                                transformationSpec.swipeSpec
+                                    ?: layoutState.transitions.defaultSwipeSpec
                             animatable.animateTo(
                                 targetValue = targetOffset,
                                 animationSpec = swipeSpec,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 15712b5..69f1d45 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -203,7 +203,7 @@
         measurable: Measurable,
         constraints: Constraints,
     ): MeasureResult {
-        val overscrollScene = layoutImpl.state.currentOverscrollSpec?.scene
+        val overscrollScene = layoutImpl.state.currentTransition?.currentOverscrollSpec?.scene
         if (overscrollScene != null && overscrollScene != scene.key) {
             // There is an overscroll in progress on another scene
             // By measuring composable elements, Compose can cache relevant information.
@@ -269,13 +269,12 @@
         transition == null ||
             transition.fromScene !in element.sceneStates ||
             transition.toScene !in element.sceneStates ||
-            layoutImpl.state.currentOverscrollSpec?.scene == scene.key
+            transition.currentOverscrollSpec?.scene == scene.key
     ) {
         return true
     }
 
-    val sharedTransformation =
-        sharedElementTransformation(layoutImpl.state, transition, element.key)
+    val sharedTransformation = sharedElementTransformation(transition, element.key)
     if (sharedTransformation?.enabled == false) {
         return true
     }
@@ -305,23 +304,21 @@
             fromSceneZIndex = layoutImpl.scenes.getValue(fromScene).zIndex,
             toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex,
         ) == scene
-    return chosenByPicker || layoutImpl.state.currentOverscrollSpec?.scene == scene
+    return chosenByPicker || transition.currentOverscrollSpec?.scene == scene
 }
 
 private fun isSharedElementEnabled(
-    layoutState: BaseSceneTransitionLayoutState,
     transition: TransitionState.Transition,
     element: ElementKey,
 ): Boolean {
-    return sharedElementTransformation(layoutState, transition, element)?.enabled ?: true
+    return sharedElementTransformation(transition, element)?.enabled ?: true
 }
 
 internal fun sharedElementTransformation(
-    layoutState: BaseSceneTransitionLayoutState,
     transition: TransitionState.Transition,
     element: ElementKey,
 ): SharedElementTransformation? {
-    val transformationSpec = layoutState.transformationSpec
+    val transformationSpec = transition.transformationSpec
     val sharedInFromScene = transformationSpec.transformations(element, transition.fromScene).shared
     val sharedInToScene = transformationSpec.transformations(element, transition.toScene).shared
 
@@ -360,11 +357,11 @@
     }
 
     val isSharedElement = fromState != null && toState != null
-    if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
+    if (isSharedElement && isSharedElementEnabled(transition, element.key)) {
         return true
     }
 
-    return layoutImpl.state.transformationSpec.transformations(element.key, scene.key).alpha == null
+    return transition.transformationSpec.transformations(element.key, scene.key).alpha == null
 }
 
 /**
@@ -559,7 +556,7 @@
     }
 
     if (transition is TransitionState.HasOverscrollProperties) {
-        val overscroll = layoutImpl.state.currentOverscrollSpec
+        val overscroll = transition.currentOverscrollSpec
         if (overscroll?.scene == scene.key) {
             val elementSpec = overscroll.transformationSpec.transformations(element.key, scene.key)
             val propertySpec = transformation(elementSpec) ?: return currentValue()
@@ -597,7 +594,7 @@
     // TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared
     // elements follow the finger direction.
     val isSharedElement = fromState != null && toState != null
-    if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
+    if (isSharedElement && isSharedElementEnabled(transition, element.key)) {
         val start = sceneValue(fromState!!)
         val end = sceneValue(toState!!)
 
@@ -607,7 +604,7 @@
     }
 
     val transformation =
-        transformation(layoutImpl.state.transformationSpec.transformations(element.key, scene.key))
+        transformation(transition.transformationSpec.transformations(element.key, scene.key))
         // If there is no transformation explicitly associated to this element value, let's use
         // the value given by the system (like the current position and size given by the layout
         // pass).
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index ebc9099..c7c874c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -96,9 +96,17 @@
     modifier: Modifier = Modifier,
     swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector,
     @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f,
+    enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
     scenes: SceneTransitionLayoutScope.() -> Unit,
 ) {
-    val state = updateSceneTransitionLayoutState(currentScene, onChangeScene, transitions)
+    val state =
+        updateSceneTransitionLayoutState(
+            currentScene,
+            onChangeScene,
+            transitions,
+            enableInterruptions = enableInterruptions,
+        )
+
     SceneTransitionLayout(
         state,
         modifier,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 617a8ea..f13c016 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -16,15 +16,16 @@
 
 package com.android.compose.animation.scene
 
+import android.util.Log
+import androidx.annotation.VisibleForTesting
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.SnapshotStateList
+import androidx.compose.ui.util.fastAll
 import androidx.compose.ui.util.fastFilter
 import androidx.compose.ui.util.fastForEach
 import com.android.compose.animation.scene.transition.link.LinkedTransition
@@ -50,10 +51,21 @@
      */
     val transitionState: TransitionState
 
-    /** The current transition, or `null` if we are idle. */
+    /**
+     * The current transition, or `null` if we are idle.
+     *
+     * Note: If you need to handle interruptions and multiple transitions running in parallel, use
+     * [currentTransitions] instead.
+     */
     val currentTransition: TransitionState.Transition?
         get() = transitionState as? TransitionState.Transition
 
+    /**
+     * The list of [TransitionState.Transition] currently running. This will be the empty list if we
+     * are idle.
+     */
+    val currentTransitions: List<TransitionState.Transition>
+
     /** The [SceneTransitions] used when animating this state. */
     val transitions: SceneTransitions
 
@@ -120,12 +132,14 @@
     transitions: SceneTransitions = SceneTransitions.Empty,
     canChangeScene: (SceneKey) -> Boolean = { true },
     stateLinks: List<StateLink> = emptyList(),
+    enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
 ): MutableSceneTransitionLayoutState {
     return MutableSceneTransitionLayoutStateImpl(
         initialScene,
         transitions,
         canChangeScene,
         stateLinks,
+        enableInterruptions,
     )
 }
 
@@ -154,6 +168,7 @@
     transitions: SceneTransitions = SceneTransitions.Empty,
     canChangeScene: (SceneKey) -> Boolean = { true },
     stateLinks: List<StateLink> = emptyList(),
+    enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
 ): SceneTransitionLayoutState {
     return remember {
             HoistedSceneTransitionLayoutState(
@@ -162,9 +177,19 @@
                 onChangeScene,
                 canChangeScene,
                 stateLinks,
+                enableInterruptions,
             )
         }
-        .apply { update(currentScene, onChangeScene, canChangeScene, transitions, stateLinks) }
+        .apply {
+            update(
+                currentScene,
+                onChangeScene,
+                canChangeScene,
+                transitions,
+                stateLinks,
+                enableInterruptions,
+            )
+        }
 }
 
 @Stable
@@ -204,6 +229,30 @@
         /** Whether user input is currently driving the transition. */
         abstract val isUserInputOngoing: Boolean
 
+        /**
+         * The current [TransformationSpecImpl] and [OverscrollSpecImpl] associated to this
+         * transition.
+         *
+         * Important: These will be set exactly once, when this transition is
+         * [started][BaseSceneTransitionLayoutState.startTransition].
+         */
+        internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
+        private var fromOverscrollSpec: OverscrollSpecImpl? = null
+        private var toOverscrollSpec: OverscrollSpecImpl? = null
+
+        /** The current [OverscrollSpecImpl], if this transition is currently overscrolling. */
+        internal val currentOverscrollSpec: OverscrollSpecImpl?
+            get() {
+                if (this !is HasOverscrollProperties) return null
+                val progress = progress
+                val bouncingScene = bouncingScene
+                return when {
+                    progress < 0f || bouncingScene == fromScene -> fromOverscrollSpec
+                    progress > 1f || bouncingScene == toScene -> toOverscrollSpec
+                    else -> null
+                }
+            }
+
         init {
             check(fromScene != toScene)
         }
@@ -232,6 +281,14 @@
             return isTransitioning(from = scene, to = other) ||
                 isTransitioning(from = other, to = scene)
         }
+
+        internal fun updateOverscrollSpecs(
+            fromSpec: OverscrollSpecImpl?,
+            toSpec: OverscrollSpecImpl?,
+        ) {
+            fromOverscrollSpec = fromSpec
+            toOverscrollSpec = toSpec
+        }
     }
 
     interface HasOverscrollProperties {
@@ -270,38 +327,41 @@
 internal abstract class BaseSceneTransitionLayoutState(
     initialScene: SceneKey,
     protected var stateLinks: List<StateLink>,
+
+    // TODO(b/290930950): Remove this flag.
+    internal var enableInterruptions: Boolean,
 ) : SceneTransitionLayoutState {
-    override var transitionState: TransitionState by
-        mutableStateOf(TransitionState.Idle(initialScene))
-        protected set
-
     /**
-     * The current [transformationSpec] associated to [transitionState]. Accessing this value makes
-     * sense only if [transitionState] is a [TransitionState.Transition].
+     * The current [TransitionState]. This list will either be:
+     * 1. A list with a single [TransitionState.Idle] element, when we are idle.
+     * 2. A list with one or more [TransitionState.Transition], when we are transitioning.
      */
-    internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
+    @VisibleForTesting
+    internal val transitionStates: MutableList<TransitionState> =
+        SnapshotStateList<TransitionState>().apply { add(TransitionState.Idle(initialScene)) }
 
-    private var fromOverscrollSpec: OverscrollSpecImpl? = null
-    private var toOverscrollSpec: OverscrollSpecImpl? = null
+    override val transitionState: TransitionState
+        get() = transitionStates.last()
 
-    /**
-     * @return the overscroll [OverscrollSpecImpl] if it is defined for the current
-     *   [transitionState] and we are currently over scrolling.
-     */
-    internal val currentOverscrollSpec: OverscrollSpecImpl?
+    private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
+
+    override val currentTransitions: List<TransitionState.Transition>
         get() {
-            val transition = currentTransition ?: return null
-            if (transition !is TransitionState.HasOverscrollProperties) return null
-            val progress = transition.progress
-            val bouncingScene = transition.bouncingScene
-            return when {
-                progress < 0f || bouncingScene == transition.fromScene -> fromOverscrollSpec
-                progress > 1f || bouncingScene == transition.toScene -> toOverscrollSpec
-                else -> null
+            if (transitionStates.last() is TransitionState.Idle) {
+                check(transitionStates.size == 1)
+                return emptyList()
+            } else {
+                @Suppress("UNCHECKED_CAST")
+                return transitionStates as List<TransitionState.Transition>
             }
         }
 
-    private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
+    /**
+     * The mapping of transitions that are finished, i.e. for which [finishTransition] was called,
+     * to their idle scene.
+     */
+    @VisibleForTesting
+    internal val finishedTransitions = mutableMapOf<TransitionState.Transition, SceneKey>()
 
     /** Whether we can transition to the given [scene]. */
     internal abstract fun canChangeScene(scene: SceneKey): Boolean
@@ -324,7 +384,11 @@
         return transition.isTransitioningBetween(scene, other)
     }
 
-    /** Start a new [transition], instantly interrupting any ongoing transition if there was one. */
+    /**
+     * Start a new [transition], instantly interrupting any ongoing transition if there was one.
+     *
+     * Important: you *must* call [finishTransition] once the transition is finished.
+     */
     internal fun startTransition(
         transition: TransitionState.Transition,
         transitionKey: TransitionKey?,
@@ -333,13 +397,81 @@
         val fromScene = transition.fromScene
         val toScene = transition.toScene
         val orientation = (transition as? TransitionState.HasOverscrollProperties)?.orientation
-        transformationSpec =
+
+        // Update the transition specs.
+        transition.transformationSpec =
             transitions.transitionSpec(fromScene, toScene, key = transitionKey).transformationSpec()
-        fromOverscrollSpec = orientation?.let { transitions.overscrollSpec(fromScene, it) }
-        toOverscrollSpec = orientation?.let { transitions.overscrollSpec(toScene, it) }
+        if (orientation != null) {
+            transition.updateOverscrollSpecs(
+                fromSpec = transitions.overscrollSpec(fromScene, orientation),
+                toSpec = transitions.overscrollSpec(toScene, orientation),
+            )
+        } else {
+            transition.updateOverscrollSpecs(fromSpec = null, toSpec = null)
+        }
+
+        // Handle transition links.
         cancelActiveTransitionLinks()
         setupTransitionLinks(transition)
-        transitionState = transition
+
+        if (!enableInterruptions) {
+            // Set the current transition.
+            check(transitionStates.size == 1)
+            transitionStates[0] = transition
+            return
+        }
+
+        when (val currentState = transitionStates.last()) {
+            is TransitionState.Idle -> {
+                // Replace [Idle] by [transition].
+                check(transitionStates.size == 1)
+                transitionStates[0] = transition
+            }
+            is TransitionState.Transition -> {
+                // Force the current transition to finish to currentScene.
+                currentState.finish().invokeOnCompletion {
+                    // Make sure [finishTransition] is called at the end of the transition.
+                    finishTransition(currentState, currentState.currentScene)
+                }
+
+                // Check that we don't have too many concurrent transitions.
+                if (transitionStates.size >= MAX_CONCURRENT_TRANSITIONS) {
+                    Log.wtf(
+                        TAG,
+                        buildString {
+                            appendLine("Potential leak detected in SceneTransitionLayoutState!")
+                            appendLine(
+                                "  Some transition(s) never called STLState.finishTransition()."
+                            )
+                            appendLine("  Transitions (size=${transitionStates.size}):")
+                            transitionStates.fastForEach { state ->
+                                val transition = state as TransitionState.Transition
+                                val from = transition.fromScene
+                                val to = transition.toScene
+                                val indicator =
+                                    if (finishedTransitions.contains(transition)) "x" else " "
+                                appendLine("  [$indicator] $from => $to ($transition)")
+                            }
+                        }
+                    )
+
+                    // Force finish all transitions.
+                    while (currentTransitions.isNotEmpty()) {
+                        val transition = transitionStates[0] as TransitionState.Transition
+                        finishTransition(transition, transition.currentScene)
+                    }
+
+                    // We finished all transitions, so we are now idle. We remove this state so that
+                    // we end up only with the new transition after appending it.
+                    check(transitionStates.size == 1)
+                    check(transitionStates[0] is TransitionState.Idle)
+                    transitionStates.clear()
+                }
+
+                // Append the new transition.
+                transitionStates.add(transition)
+            }
+        }
     }
 
     private fun cancelActiveTransitionLinks() {
@@ -379,13 +511,54 @@
      * nothing if [transition] was interrupted since it was started.
      */
     internal fun finishTransition(transition: TransitionState.Transition, idleScene: SceneKey) {
-        resolveActiveTransitionLinks(idleScene)
-        if (transitionState == transition) {
-            transitionState = TransitionState.Idle(idleScene)
+        val existingIdleScene = finishedTransitions[transition]
+        if (existingIdleScene != null) {
+            // This transition was already finished.
+            check(idleScene == existingIdleScene) {
+                "Transition $transition was finished multiple times with different " +
+                    "idleScene ($existingIdleScene != $idleScene)"
+            }
+            return
+        }
+
+        if (!transitionStates.contains(transition)) {
+            // This transition was already removed from transitionStates.
+            return
+        }
+
+        check(transitionStates.fastAll { it is TransitionState.Transition })
+
+        // Mark this transition as finished and save the scene it is settling at.
+        finishedTransitions[transition] = idleScene
+
+        // Finish all linked transitions.
+        finishActiveTransitionLinks(idleScene)
+
+        // Keep a reference to the idle scene of the last removed transition, in case we remove all
+        // transitions and should settle to Idle.
+        var lastRemovedIdleScene: SceneKey? = null
+
+        // Remove all first n finished transitions.
+        while (transitionStates.isNotEmpty()) {
+            val firstTransition = transitionStates[0]
+            if (!finishedTransitions.contains(firstTransition)) {
+                // Stop here.
+                break
+            }
+
+            // Remove the transition from the list and from the set of finished transitions.
+            transitionStates.removeAt(0)
+            lastRemovedIdleScene = finishedTransitions.remove(firstTransition)
+        }
+
+        // If all transitions are finished, we are idle.
+        if (transitionStates.isEmpty()) {
+            check(finishedTransitions.isEmpty())
+            transitionStates.add(TransitionState.Idle(checkNotNull(lastRemovedIdleScene)))
         }
     }
 
-    private fun resolveActiveTransitionLinks(idleScene: SceneKey) {
+    private fun finishActiveTransitionLinks(idleScene: SceneKey) {
         val previousTransition = this.transitionState as? TransitionState.Transition ?: return
         for ((link, linkedTransition) in activeTransitionLinks) {
             if (previousTransition.fromScene == idleScene) {
@@ -406,20 +579,39 @@
      * Check if a transition is in progress. If the progress value is near 0 or 1, immediately snap
      * to the closest scene.
      *
+     * Important: Snapping to the closest scene will instantly finish *all* ongoing transitions,
+     * only the progress of the last transition will be checked.
+     *
      * @return true if snapped to the closest scene.
      */
     internal fun snapToIdleIfClose(threshold: Float): Boolean {
         val transition = currentTransition ?: return false
         val progress = transition.progress
+
         fun isProgressCloseTo(value: Float) = (progress - value).absoluteValue <= threshold
 
+        fun finishAllTransitions(lastTransitionIdleScene: SceneKey) {
+            // Force finish all transitions.
+            while (currentTransitions.isNotEmpty()) {
+                val transition = transitionStates[0] as TransitionState.Transition
+                val idleScene =
+                    if (transitionStates.size == 1) {
+                        lastTransitionIdleScene
+                    } else {
+                        transition.currentScene
+                    }
+
+                finishTransition(transition, idleScene)
+            }
+        }
+
         return when {
             isProgressCloseTo(0f) -> {
-                finishTransition(transition, transition.fromScene)
+                finishAllTransitions(transition.fromScene)
                 true
             }
             isProgressCloseTo(1f) -> {
-                finishTransition(transition, transition.toScene)
+                finishAllTransitions(transition.toScene)
                 true
             }
             else -> false
@@ -437,7 +629,8 @@
     private var changeScene: (SceneKey) -> Unit,
     private var canChangeScene: (SceneKey) -> Boolean,
     stateLinks: List<StateLink> = emptyList(),
-) : BaseSceneTransitionLayoutState(initialScene, stateLinks) {
+    enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
+) : BaseSceneTransitionLayoutState(initialScene, stateLinks, enableInterruptions) {
     private val targetSceneChannel = Channel<SceneKey>(Channel.CONFLATED)
 
     override fun canChangeScene(scene: SceneKey): Boolean = canChangeScene.invoke(scene)
@@ -451,12 +644,14 @@
         canChangeScene: (SceneKey) -> Boolean,
         transitions: SceneTransitions,
         stateLinks: List<StateLink>,
+        enableInterruptions: Boolean,
     ) {
         SideEffect {
             this.changeScene = onChangeScene
             this.canChangeScene = canChangeScene
             this.transitions = transitions
             this.stateLinks = stateLinks
+            this.enableInterruptions = enableInterruptions
 
             targetSceneChannel.trySend(currentScene)
         }
@@ -482,7 +677,10 @@
     override var transitions: SceneTransitions,
     private val canChangeScene: (SceneKey) -> Boolean = { true },
     stateLinks: List<StateLink> = emptyList(),
-) : MutableSceneTransitionLayoutState, BaseSceneTransitionLayoutState(initialScene, stateLinks) {
+    enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
+) :
+    MutableSceneTransitionLayoutState,
+    BaseSceneTransitionLayoutState(initialScene, stateLinks, enableInterruptions) {
     override fun setTargetScene(
         targetScene: SceneKey,
         coroutineScope: CoroutineScope,
@@ -501,3 +699,15 @@
         setTargetScene(scene, coroutineScope = this)
     }
 }
+
+private const val TAG = "SceneTransitionLayoutState"
+
+/** Whether support for interruptions in enabled by default. */
+internal const val DEFAULT_INTERRUPTIONS_ENABLED = true
+
+/**
+ * The max number of concurrent transitions. If the number of transitions goes past this number,
+ * this probably means that there is a leak and we will Log.wtf before clearing the list of
+ * transitions.
+ */
+private const val MAX_CONCURRENT_TRANSITIONS = 100
diff --git a/packages/SystemUI/compose/scene/tests/Android.bp b/packages/SystemUI/compose/scene/tests/Android.bp
index 59cc63a..af13896 100644
--- a/packages/SystemUI/compose/scene/tests/Android.bp
+++ b/packages/SystemUI/compose/scene/tests/Android.bp
@@ -26,7 +26,6 @@
     name: "PlatformComposeSceneTransitionLayoutTests",
     manifest: "AndroidManifest.xml",
     test_suites: ["device-tests"],
-    sdk_version: "current",
     certificate: "platform",
 
     srcs: [
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 1e9a7e2..2ed51eb 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -984,14 +984,14 @@
         val scene = layoutState.transitionState.currentScene
         // We should have overscroll spec for scene C
         assertThat(layoutState.transitions.overscrollSpec(scene, Orientation.Vertical)).isNotNull()
-        assertThat(layoutState.currentOverscrollSpec).isNull()
+        assertThat(layoutState.currentTransition?.currentOverscrollSpec).isNull()
 
         val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
         nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f))
 
         // We scrolled down, under scene C there is nothing, so we can use the overscroll spec
-        assertThat(layoutState.currentOverscrollSpec).isNotNull()
-        assertThat(layoutState.currentOverscrollSpec?.scene).isEqualTo(SceneC)
+        assertThat(layoutState.currentTransition?.currentOverscrollSpec).isNotNull()
+        assertThat(layoutState.currentTransition?.currentOverscrollSpec?.scene).isEqualTo(SceneC)
         val transition = layoutState.currentTransition
         assertThat(transition).isNotNull()
         assertThat(transition!!.progress).isEqualTo(-0.1f)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 597da9e..2453e25 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -595,7 +595,7 @@
         }
 
         assertThat(state.currentTransition).isNull()
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         // Swipe by half of verticalSwipeDistance.
         rule.onRoot().performTouchInput {
@@ -643,7 +643,7 @@
 
         // Scroll 150% (Scene B overscroll by 50%)
         assertThat(transition.progress).isEqualTo(1.5f)
-        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
         fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
         // animatedFloat cannot overflow (canOverflow = false)
         assertThat(animatedFloat).isEqualTo(100f)
@@ -655,7 +655,7 @@
 
         // Scroll 250% (Scene B overscroll by 150%)
         assertThat(transition.progress).isEqualTo(2.5f)
-        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
         fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
         assertThat(animatedFloat).isEqualTo(100f)
     }
@@ -707,7 +707,7 @@
         }
 
         assertThat(state.currentTransition).isNull()
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
         val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
         fooElement.assertTopPositionInRootIsEqualTo(0.dp)
 
@@ -720,7 +720,7 @@
         }
 
         val transition = state.currentTransition
-        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
         assertThat(transition).isNotNull()
         assertThat(transition!!.progress).isEqualTo(-0.5f)
         fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
@@ -732,7 +732,7 @@
 
         // Scroll 150% (Scene B overscroll by 50%)
         assertThat(transition.progress).isEqualTo(-1.5f)
-        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
         fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
     }
 
@@ -771,7 +771,7 @@
 
         // Scroll 150% (100% scroll + 50% overscroll)
         assertThat(transition!!.progress).isEqualTo(1.5f)
-        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
         fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 0.5f)
         assertThat(animatedFloat).isEqualTo(100f)
 
@@ -782,7 +782,7 @@
 
         // Scroll 250% (100% scroll + 150% overscroll)
         assertThat(transition.progress).isEqualTo(2.5f)
-        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
         fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * 1.5f)
         assertThat(animatedFloat).isEqualTo(100f)
     }
@@ -828,7 +828,7 @@
 
         // Scroll 150% (100% scroll + 50% overscroll)
         assertThat(transition.progress).isEqualTo(1.5f)
-        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
         fooElement.assertTopPositionInRootIsEqualTo(layoutHeight * (transition.progress - 1f))
         assertThat(animatedFloat).isEqualTo(100f)
 
@@ -840,7 +840,7 @@
         rule.waitUntil(timeoutMillis = 10_000) { transition.progress < 1f }
 
         assertThat(transition.progress).isLessThan(1f)
-        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
         assertThat(transition.bouncingScene).isEqualTo(transition.toScene)
         assertThat(animatedFloat).isEqualTo(100f)
     }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index 9baabc3..93e94f8 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.compose.animation.scene
 
+import android.util.Log
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -28,9 +29,12 @@
 import com.android.compose.test.runMonotonicClockTest
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancelAndJoin
-import kotlinx.coroutines.job
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.test.runTest
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -271,11 +275,21 @@
     }
 
     @Test
-    fun linkedTransition_startsLinkButLinkedStateIsTakenOver() {
+    fun linkedTransition_startsLinkButLinkedStateIsTakenOver() = runTest {
         val (parentState, childState) = setupLinkedStates()
 
-        val childTransition = transition(SceneA, SceneB)
-        val parentTransition = transition(SceneC, SceneA)
+        val childTransition =
+            transition(
+                SceneA,
+                SceneB,
+                onFinish = { launch { /* Do nothing. */} },
+            )
+        val parentTransition =
+            transition(
+                SceneC,
+                SceneA,
+                onFinish = { launch { /* Do nothing. */} },
+            )
         childState.startTransition(childTransition, null)
         parentState.startTransition(parentTransition, null)
 
@@ -303,7 +317,7 @@
 
         // Default transition from A to B.
         assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNotNull()
-        assertThat(state.transformationSpec.transformations).hasSize(1)
+        assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1)
 
         // Go back to A.
         state.setTargetScene(SceneA, coroutineScope = this)
@@ -320,14 +334,14 @@
                 )
             )
             .isNotNull()
-        assertThat(state.transformationSpec.transformations).hasSize(2)
+        assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2)
     }
 
     @Test
     fun snapToIdleIfClose_snapToStart() = runMonotonicClockTest {
         val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
         state.startTransition(
-            transition(from = SceneA, to = TestScenes.SceneB, progress = { 0.2f }),
+            transition(from = SceneA, to = SceneB, progress = { 0.2f }),
             transitionKey = null
         )
         assertThat(state.isTransitioning()).isTrue()
@@ -346,7 +360,7 @@
     fun snapToIdleIfClose_snapToEnd() = runMonotonicClockTest {
         val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
         state.startTransition(
-            transition(from = SceneA, to = TestScenes.SceneB, progress = { 0.8f }),
+            transition(from = SceneA, to = SceneB, progress = { 0.8f }),
             transitionKey = null
         )
         assertThat(state.isTransitioning()).isTrue()
@@ -358,7 +372,35 @@
         // Go to the final scene if it is close to 1.
         assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
         assertThat(state.isTransitioning()).isFalse()
-        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneB))
+        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneB))
+    }
+
+    @Test
+    fun snapToIdleIfClose_multipleTransitions() = runMonotonicClockTest {
+        val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+
+        val aToB =
+            transition(
+                from = SceneA,
+                to = SceneB,
+                progress = { 0.5f },
+                onFinish = { launch { /* do nothing */} },
+            )
+        state.startTransition(aToB, transitionKey = null)
+        assertThat(state.currentTransitions).containsExactly(aToB).inOrder()
+
+        val bToC = transition(from = SceneB, to = SceneC, progress = { 0.8f })
+        state.startTransition(bToC, transitionKey = null)
+        assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()
+
+        // Ignore the request if the progress is not close to 0 or 1, using the threshold.
+        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+        assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()
+
+        // Go to the final scene if it is close to 1.
+        assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
+        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneC))
+        assertThat(state.currentTransitions).isEmpty()
     }
 
     @Test
@@ -435,23 +477,23 @@
                         overscroll(SceneB, Orientation.Vertical) { fade(TestElements.Foo) }
                     }
             )
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         // overscroll for SceneA is NOT defined
         progress.value = -0.1f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         // scroll from SceneA to SceneB
         progress.value = 0.5f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         progress.value = 1f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         // overscroll for SceneB is defined
         progress.value = 1.1f
-        assertThat(state.currentOverscrollSpec).isNotNull()
-        assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneB)
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec?.scene).isEqualTo(SceneB)
     }
 
     @Test
@@ -465,23 +507,23 @@
                         overscroll(SceneA, Orientation.Vertical) { fade(TestElements.Foo) }
                     }
             )
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         // overscroll for SceneA is defined
         progress.value = -0.1f
-        assertThat(state.currentOverscrollSpec).isNotNull()
-        assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneA)
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec?.scene).isEqualTo(SceneA)
 
         // scroll from SceneA to SceneB
         progress.value = 0.5f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         progress.value = 1f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         // overscroll for SceneB is NOT defined
         progress.value = 1.1f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
     }
 
     @Test
@@ -492,21 +534,99 @@
                 progress = { progress.value },
                 sceneTransitions = transitions {}
             )
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         // overscroll for SceneA is NOT defined
         progress.value = -0.1f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         // scroll from SceneA to SceneB
         progress.value = 0.5f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         progress.value = 1f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
 
         // overscroll for SceneB is NOT defined
         progress.value = 1.1f
-        assertThat(state.currentOverscrollSpec).isNull()
+        assertThat(state.currentTransition?.currentOverscrollSpec).isNull()
+    }
+
+    @Test
+    fun multipleTransitions() = runTest {
+        val finishingTransitions = mutableSetOf<TransitionState.Transition>()
+        fun onFinish(transition: TransitionState.Transition): Job {
+            // Instead of letting the transition finish, we put the transition in the
+            // finishingTransitions set so that we can verify that finish() is called when expected
+            // and then we call state STLState.finishTransition() ourselves.
+            finishingTransitions.add(transition)
+
+            return backgroundScope.launch {
+                // Try to acquire a locked mutex so that this code never completes.
+                Mutex(locked = true).withLock {}
+            }
+        }
+
+        val state = MutableSceneTransitionLayoutStateImpl(SceneA, EmptyTestTransitions)
+        val aToB = transition(SceneA, SceneB, onFinish = ::onFinish)
+        val bToC = transition(SceneB, SceneC, onFinish = ::onFinish)
+        val cToA = transition(SceneC, SceneA, onFinish = ::onFinish)
+
+        // Starting state.
+        assertThat(finishingTransitions).isEmpty()
+        assertThat(state.currentTransitions).isEmpty()
+
+        // A => B.
+        state.startTransition(aToB, transitionKey = null)
+        assertThat(finishingTransitions).isEmpty()
+        assertThat(state.finishedTransitions).isEmpty()
+        assertThat(state.currentTransitions).containsExactly(aToB).inOrder()
+
+        // B => C. This should automatically call finish() on aToB.
+        state.startTransition(bToC, transitionKey = null)
+        assertThat(finishingTransitions).containsExactly(aToB)
+        assertThat(state.finishedTransitions).isEmpty()
+        assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()
+
+        // C => A. This should automatically call finish() on bToC.
+        state.startTransition(cToA, transitionKey = null)
+        assertThat(finishingTransitions).containsExactly(aToB, bToC)
+        assertThat(state.finishedTransitions).isEmpty()
+        assertThat(state.currentTransitions).containsExactly(aToB, bToC, cToA).inOrder()
+
+        // Mark bToC as finished. The list of current transitions does not change because aToB is
+        // still not marked as finished.
+        state.finishTransition(bToC, idleScene = bToC.currentScene)
+        assertThat(state.finishedTransitions).containsExactly(bToC, bToC.currentScene)
+        assertThat(state.currentTransitions).containsExactly(aToB, bToC, cToA).inOrder()
+
+        // Mark aToB as finished. This will remove both aToB and bToC from the list of transitions.
+        state.finishTransition(aToB, idleScene = aToB.currentScene)
+        assertThat(state.finishedTransitions).isEmpty()
+        assertThat(state.currentTransitions).containsExactly(cToA).inOrder()
+    }
+
+    @Test
+    fun tooManyTransitionsLogsWtfAndClearsTransitions() = runTest {
+        val state = MutableSceneTransitionLayoutStateImpl(SceneA, EmptyTestTransitions)
+
+        fun startTransition() {
+            val transition = transition(SceneA, SceneB, onFinish = { launch { /* do nothing */} })
+            state.startTransition(transition, transitionKey = null)
+        }
+
+        var hasLoggedWtf = false
+        val originalHandler = Log.setWtfHandler { _, _, _ -> hasLoggedWtf = true }
+        try {
+            repeat(100) { startTransition() }
+            assertThat(hasLoggedWtf).isFalse()
+            assertThat(state.currentTransitions).hasSize(100)
+
+            startTransition()
+            assertThat(hasLoggedWtf).isTrue()
+            assertThat(state.currentTransitions).hasSize(1)
+        } finally {
+            Log.setWtfHandler(originalHandler)
+        }
     }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index efaea71..723a182 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -299,6 +299,11 @@
             .isWithin(DpOffsetSubject.DefaultTolerance)
             .of(DpOffset(expectedOffset, expectedOffset))
 
+        // Wait for the transition to C to finish.
+        rule.mainClock.advanceTimeBy(TestTransitionDuration)
+        assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java)
+        assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneC)
+
         // Go back to scene A. This should happen instantly (once the animation started, i.e. after
         // 2 frames) given that we use a snap() animation spec.
         currentScene = TestScenes.SceneA
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 99372a5..f034c18 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -547,12 +547,12 @@
         }
 
         assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
-        assertThat(state.transformationSpec.transformations).hasSize(1)
+        assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1)
 
         // Move the pointer up to swipe to scene B using the new transition.
         rule.onRoot().performTouchInput { moveBy(Offset(0f, -1.dp.toPx()), delayMillis = 1_000) }
         assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
-        assertThat(state.transformationSpec.transformations).hasSize(2)
+        assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2)
     }
 
     @Test
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt
index a32fe22..767057b 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/Transition.kt
@@ -29,6 +29,7 @@
     isUpOrLeft: Boolean = false,
     bouncingScene: SceneKey? = null,
     orientation: Orientation = Orientation.Horizontal,
+    onFinish: ((TransitionState.Transition) -> Job)? = null,
 ): TransitionState.Transition {
     return object : TransitionState.Transition(from, to), TransitionState.HasOverscrollProperties {
         override val currentScene: SceneKey = from
@@ -46,7 +47,13 @@
             }
 
         override fun finish(): Job {
-            error("finish() is not supported in test transitions")
+            val onFinish =
+                onFinish
+                    ?: error(
+                        "onFinish() must be provided if finish() is called on test transitions"
+                    )
+
+            return onFinish(this)
         }
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
index 69ff5ab..b4f87c4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetInteractionHandlerTest.kt
@@ -21,6 +21,8 @@
 import android.view.View
 import android.widget.FrameLayout
 import android.widget.RemoteViews.RemoteResponse
+import androidx.core.util.component1
+import androidx.core.util.component2
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -29,6 +31,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.refEq
 import org.mockito.Mock
 import org.mockito.Mockito.isNull
 import org.mockito.Mockito.notNull
@@ -62,6 +65,7 @@
         val parent = FrameLayout(context)
         val view = CommunalAppWidgetHostView(context)
         parent.addView(view)
+        val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)
 
         underTest.onInteraction(view, testIntent, testResponse)
 
@@ -70,6 +74,8 @@
                 eq(testIntent),
                 isNull(),
                 notNull(),
+                refEq(fillInIntent),
+                refEq(activityOptions.toBundle()),
             )
     }
 
@@ -78,10 +84,17 @@
         val parent = FrameLayout(context)
         val view = View(context)
         parent.addView(view)
+        val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)
 
         underTest.onInteraction(view, testIntent, testResponse)
 
         verify(activityStarter)
-            .startPendingIntentMaybeDismissingKeyguard(eq(testIntent), isNull(), isNull())
+            .startPendingIntentMaybeDismissingKeyguard(
+                eq(testIntent),
+                isNull(),
+                isNull(),
+                refEq(fillInIntent),
+                refEq(activityOptions.toBundle()),
+            )
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
index 8aa0e3fc..c8062fb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
@@ -16,12 +16,15 @@
 
 package com.android.systemui.statusbar.phone
 
+import android.app.ActivityOptions
 import android.app.PendingIntent
 import android.content.Intent
+import android.os.Bundle
 import android.os.RemoteException
 import android.os.UserHandle
 import android.view.View
 import android.widget.FrameLayout
+import android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
@@ -48,6 +51,7 @@
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.whenever
@@ -173,6 +177,53 @@
             )
     }
 
+    fun startPendingIntentDismissingKeyguard_fillInIntentAndExtraOptions_sendAndReturnResult() {
+        val pendingIntent = mock(PendingIntent::class.java)
+        val fillInIntent = mock(Intent::class.java)
+        val parent = FrameLayout(context)
+        val view =
+            object : View(context), LaunchableView {
+                override fun setShouldBlockVisibilityChanges(block: Boolean) {}
+            }
+        parent.addView(view)
+        val controller = ActivityTransitionAnimator.Controller.fromView(view)
+        whenever(pendingIntent.isActivity).thenReturn(true)
+        whenever(keyguardStateController.isShowing).thenReturn(true)
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt()))
+            .thenReturn(false)
+
+        // extra activity options to set on pending intent
+        val activityOptions = mock(ActivityOptions::class.java)
+        activityOptions.splashScreenStyle = SPLASH_SCREEN_STYLE_SOLID_COLOR
+        activityOptions.isPendingIntentBackgroundActivityLaunchAllowedByPermission = false
+        val bundleCaptor = argumentCaptor<Bundle>()
+
+        underTest.startPendingIntentMaybeDismissingKeyguard(
+            intent = pendingIntent,
+            animationController = controller,
+            intentSentUiThreadCallback = null,
+            fillInIntent = fillInIntent,
+            extraOptions = activityOptions.toBundle(),
+        )
+        mainExecutor.runAllReady()
+
+        // Fill-in intent is passed and options contain extra values specified
+        verify(pendingIntent)
+            .sendAndReturnResult(
+                eq(context),
+                eq(0),
+                eq(fillInIntent),
+                nullable(),
+                nullable(),
+                nullable(),
+                bundleCaptor.capture()
+            )
+        val options = ActivityOptions.fromBundle(bundleCaptor.value)
+        assertThat(options.isPendingIntentBackgroundActivityLaunchAllowedByPermission).isFalse()
+        assertThat(options.splashScreenStyle).isEqualTo(SPLASH_SCREEN_STYLE_SOLID_COLOR)
+    }
+
     @Test
     fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() {
         val pendingIntent = mock(PendingIntent::class.java)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 1126ec3..072ec99 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -17,6 +17,7 @@
 import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.UserHandle;
 import android.view.View;
 
@@ -67,6 +68,17 @@
             @Nullable ActivityTransitionAnimator.Controller animationController);
 
     /**
+     * Similar to {@link #startPendingIntentMaybeDismissingKeyguard(PendingIntent, Runnable,
+     * ActivityTransitionAnimator.Controller)}, but also specifies a fill-in intent and extra
+     * options that could be used to populate the pending intent and launch the activity.
+     */
+    void startPendingIntentMaybeDismissingKeyguard(PendingIntent intent,
+            @Nullable Runnable intentSentUiThreadCallback,
+            @Nullable ActivityTransitionAnimator.Controller animationController,
+            @Nullable Intent fillInIntent,
+            @Nullable Bundle extraOptions);
+
+    /**
      * The intent flag can be specified in startActivity().
      */
     void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags);
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
index 4c1e77b..778d8cf 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
@@ -16,9 +16,14 @@
 
 package com.android.systemui.communal.widgets
 
+import android.app.ActivityOptions
 import android.app.PendingIntent
+import android.content.Intent
+import android.util.Pair
 import android.view.View
 import android.widget.RemoteViews
+import androidx.core.util.component1
+import androidx.core.util.component2
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.common.ui.view.getNearestParent
 import com.android.systemui.plugins.ActivityStarter
@@ -33,21 +38,33 @@
         view: View,
         pendingIntent: PendingIntent,
         response: RemoteViews.RemoteResponse
-    ): Boolean =
-        when {
-            pendingIntent.isActivity -> startActivity(view, pendingIntent)
-            else ->
-                RemoteViews.startPendingIntent(view, pendingIntent, response.getLaunchOptions(view))
+    ): Boolean {
+        val launchOptions = response.getLaunchOptions(view)
+        return when {
+            pendingIntent.isActivity ->
+                // Forward the fill-in intent and activity options retrieved from the response
+                // to populate the pending intent, so that list items can launch respective
+                // activities.
+                startActivity(view, pendingIntent, launchOptions)
+            else -> RemoteViews.startPendingIntent(view, pendingIntent, launchOptions)
         }
+    }
 
-    private fun startActivity(view: View, pendingIntent: PendingIntent): Boolean {
+    private fun startActivity(
+        view: View,
+        pendingIntent: PendingIntent,
+        launchOptions: Pair<Intent, ActivityOptions>,
+    ): Boolean {
         val hostView = view.getNearestParent<CommunalAppWidgetHostView>()
         val animationController = hostView?.let(ActivityTransitionAnimator.Controller::fromView)
+        val (fillInIntent, activityOptions) = launchOptions
 
         activityStarter.startPendingIntentMaybeDismissingKeyguard(
             pendingIntent,
             /* intentSentUiThreadCallback = */ null,
-            animationController
+            animationController,
+            fillInIntent,
+            activityOptions.toBundle(),
         )
         return true
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 18d2f30..b0707db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -111,7 +111,7 @@
     @Override
     protected void handleClick(@Nullable View view) {
         if (mFeatureFlags.isEnabled(Flags.BLUETOOTH_QS_TILE_DIALOG)) {
-            mDialogViewModel.showDialog(mContext, view);
+            mDialogViewModel.showDialog(view);
         } else {
             // Secondary clicks are header clicks, just toggle.
             final boolean isEnabled = mState.value;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt
index 1247854..59fc81c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt
@@ -19,8 +19,6 @@
 import android.util.Log
 import com.android.systemui.dagger.SysUISingleton
 import javax.inject.Inject
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.map
 
 /** Interactor class responsible for interacting with the Bluetooth Auto-On feature. */
 @SysUISingleton
@@ -30,14 +28,10 @@
     private val bluetoothAutoOnRepository: BluetoothAutoOnRepository,
 ) {
 
-    val isEnabled = bluetoothAutoOnRepository.isAutoOn.map { it == ENABLED }.distinctUntilChanged()
+    val isEnabled = bluetoothAutoOnRepository.isAutoOn
 
-    /**
-     * Checks if the auto on value is present in the repository.
-     *
-     * @return `true` if a value is present (i.e, the feature is enabled by the Bluetooth server).
-     */
-    suspend fun isValuePresent(): Boolean = bluetoothAutoOnRepository.isValuePresent()
+    /** Checks if the auto on feature is supported. */
+    suspend fun isAutoOnSupported(): Boolean = bluetoothAutoOnRepository.isAutoOnSupported()
 
     /**
      * Sets enabled or disabled based on the provided value.
@@ -45,17 +39,14 @@
      * @param value `true` to enable the feature, `false` to disable it.
      */
     suspend fun setEnabled(value: Boolean) {
-        if (!isValuePresent()) {
+        if (!isAutoOnSupported()) {
             Log.e(TAG, "Trying to set toggle value while feature not available.")
         } else {
-            val newValue = if (value) ENABLED else DISABLED
-            bluetoothAutoOnRepository.setAutoOn(newValue)
+            bluetoothAutoOnRepository.setAutoOn(value)
         }
     }
 
     companion object {
         private const val TAG = "BluetoothAutoOnInteractor"
-        const val DISABLED = 0
-        const val ENABLED = 1
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt
index f97fc38..9ee582a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt
@@ -16,22 +16,23 @@
 
 package com.android.systemui.qs.tiles.dialog.bluetooth
 
+import android.bluetooth.BluetoothAdapter
+import android.util.Log
+import com.android.settingslib.bluetooth.BluetoothCallback
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.user.data.repository.UserRepository
-import com.android.systemui.util.settings.SecureSettings
-import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.withContext
@@ -44,61 +45,87 @@
 class BluetoothAutoOnRepository
 @Inject
 constructor(
-    private val secureSettings: SecureSettings,
-    private val userRepository: UserRepository,
+    localBluetoothManager: LocalBluetoothManager?,
+    private val bluetoothAdapter: BluetoothAdapter?,
     @Application private val coroutineScope: CoroutineScope,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) {
 
-    // Flow representing the auto on setting value for the current user
-    @OptIn(ExperimentalCoroutinesApi::class)
-    internal val isAutoOn: StateFlow<Int> =
-        userRepository.selectedUserInfo
-            .flatMapLatest { userInfo ->
-                secureSettings
-                    .observerFlow(userInfo.id, SETTING_NAME)
-                    .onStart { emit(Unit) }
-                    .map { secureSettings.getIntForUser(SETTING_NAME, UNSET, userInfo.id) }
-            }
-            .distinctUntilChanged()
-            .flowOn(backgroundDispatcher)
-            .stateIn(
-                coroutineScope,
-                SharingStarted.WhileSubscribed(replayExpirationMillis = 0),
-                UNSET
-            )
+    // Flow representing the auto on state for the current user
+    internal val isAutoOn: Flow<Boolean> =
+        localBluetoothManager?.eventManager?.let { eventManager ->
+            conflatedCallbackFlow {
+                    val listener =
+                        object : BluetoothCallback {
+                            override fun onAutoOnStateChanged(autoOnState: Int) {
+                                super.onAutoOnStateChanged(autoOnState)
+                                if (
+                                    autoOnState == BluetoothAdapter.AUTO_ON_STATE_ENABLED ||
+                                        autoOnState == BluetoothAdapter.AUTO_ON_STATE_DISABLED
+                                ) {
+                                    trySendWithFailureLogging(
+                                        autoOnState == BluetoothAdapter.AUTO_ON_STATE_ENABLED,
+                                        TAG,
+                                        "onAutoOnStateChanged"
+                                    )
+                                }
+                            }
+                        }
+                    eventManager.registerCallback(listener)
+                    awaitClose { eventManager.unregisterCallback(listener) }
+                }
+                .onStart { emit(isAutoOnEnabled()) }
+                .flowOn(backgroundDispatcher)
+                .stateIn(
+                    coroutineScope,
+                    SharingStarted.WhileSubscribed(replayExpirationMillis = 0),
+                    initialValue = false
+                )
+        }
+            ?: flowOf(false)
 
     /**
-     * Checks if the auto on setting value is ever set for the current user.
+     * Checks if the auto on feature is supported for the current user.
      *
-     * @return `true` if the setting value is not UNSET, `false` otherwise.
+     * @throws Exception if an error occurs while checking auto-on support.
      */
-    suspend fun isValuePresent(): Boolean =
+    suspend fun isAutoOnSupported(): Boolean =
         withContext(backgroundDispatcher) {
-            secureSettings.getIntForUser(
-                SETTING_NAME,
-                UNSET,
-                userRepository.getSelectedUserInfo().id
-            ) != UNSET
+            try {
+                bluetoothAdapter?.isAutoOnSupported ?: false
+            } catch (e: Exception) {
+                // Server could throw TimeoutException, InterruptedException or ExecutionException
+                Log.e(TAG, "Error calling isAutoOnSupported", e)
+                false
+            }
         }
 
-    /**
-     * Sets the Bluetooth Auto-On setting value for the current user.
-     *
-     * @param value The new setting value to be applied.
-     */
-    suspend fun setAutoOn(value: Int) {
+    /** Sets the Bluetooth Auto-On for the current user. */
+    suspend fun setAutoOn(value: Boolean) {
         withContext(backgroundDispatcher) {
-            secureSettings.putIntForUser(
-                SETTING_NAME,
-                value,
-                userRepository.getSelectedUserInfo().id
-            )
+            try {
+                bluetoothAdapter?.setAutoOnEnabled(value)
+            } catch (e: Exception) {
+                // Server could throw IllegalStateException, TimeoutException, InterruptedException
+                // or ExecutionException
+                Log.e(TAG, "Error calling setAutoOnEnabled", e)
+            }
         }
     }
 
-    companion object {
-        const val SETTING_NAME = "bluetooth_automatic_turn_on"
-        const val UNSET = -1
+    private suspend fun isAutoOnEnabled() =
+        withContext(backgroundDispatcher) {
+            try {
+                bluetoothAdapter?.isAutoOnEnabled ?: false
+            } catch (e: Exception) {
+                // Server could throw IllegalStateException, TimeoutException, InterruptedException
+                // or ExecutionException
+                Log.e(TAG, "Error calling isAutoOnEnabled", e)
+                false
+            }
+        }
+
+    private companion object {
+        const val TAG = "BluetoothAutoOnRepository"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
index 9d53703..a8d9e78 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.qs.tiles.dialog.bluetooth
 
-import android.content.Context
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
@@ -58,7 +57,6 @@
 class BluetoothTileDialogDelegate
 @AssistedInject
 internal constructor(
-    @Assisted private val context: Context,
     @Assisted private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
     @Assisted private val cachedContentHeight: Int,
     @Assisted private val bluetoothToggleInitialValue: Boolean,
@@ -69,11 +67,8 @@
     private val uiEventLogger: UiEventLogger,
     private val logger: BluetoothTileDialogLogger,
     private val systemuiDialogFactory: SystemUIDialog.Factory,
-    mainLayoutInflater: LayoutInflater,
 ) : SystemUIDialog.Delegate {
 
-    private val layoutInflater = mainLayoutInflater.cloneInContext(context)
-
     private val mutableBluetoothStateToggle: MutableStateFlow<Boolean> =
         MutableStateFlow(bluetoothToggleInitialValue)
     internal val bluetoothStateToggle
@@ -102,7 +97,6 @@
     @AssistedFactory
     internal interface Factory {
         fun create(
-            context: Context,
             initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
             cachedContentHeight: Int,
             bluetoothEnabled: Boolean,
@@ -112,16 +106,15 @@
     }
 
     override fun createDialog(): SystemUIDialog {
-        val dialog = systemuiDialogFactory.create(this, context)
-
-        return dialog
+        return systemuiDialogFactory.create(this)
     }
 
     override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
         SystemUIDialog.registerDismissListener(dialog, dismissListener)
         uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN)
+        val context = dialog.context
 
-        layoutInflater.inflate(R.layout.bluetooth_tile_dialog, null).apply {
+        LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null).apply {
             accessibilityPaneTitle = context.getText(R.string.accessibility_desc_quick_settings)
             dialog.setContentView(this)
         }
@@ -201,7 +194,7 @@
             setEnabled(true)
             alpha = ENABLED_ALPHA
         }
-        getSubtitleTextView(dialog).text = context.getString(uiProperties.subTitleResId)
+        getSubtitleTextView(dialog).text = dialog.context.getString(uiProperties.subTitleResId)
         getAutoOnToggleView(dialog).visibility = uiProperties.autoOnToggleVisibility
     }
 
@@ -215,7 +208,7 @@
             setEnabled(true)
             alpha = ENABLED_ALPHA
         }
-        getAutoOnToggleInfoTextView(dialog).text = context.getString(infoResId)
+        getAutoOnToggleInfoTextView(dialog).text = dialog.context.getString(infoResId)
     }
 
     private fun setupToggle(dialog: SystemUIDialog) {
@@ -288,7 +281,7 @@
 
     private fun setupRecyclerView(dialog: SystemUIDialog) {
         getDeviceListView(dialog).apply {
-            layoutManager = LinearLayoutManager(context)
+            layoutManager = LinearLayoutManager(dialog.context)
             adapter = deviceItemAdapter
         }
     }
@@ -343,7 +336,9 @@
         private val asyncListDiffer = AsyncListDiffer(this, diffUtilCallback)
 
         override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeviceItemViewHolder {
-            val view = layoutInflater.inflate(R.layout.bluetooth_device_item, parent, false)
+            val view =
+                LayoutInflater.from(parent.context)
+                    .inflate(R.layout.bluetooth_device_item, parent, false)
             return DeviceItemViewHolder(view)
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
index e4f3c19..fd624d2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.qs.tiles.dialog.bluetooth
 
-import android.content.Context
 import android.content.Intent
 import android.content.SharedPreferences
 import android.os.Bundle
@@ -29,7 +28,6 @@
 import androidx.annotation.VisibleForTesting
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.UiEventLogger
-import com.android.settingslib.flags.Flags.bluetoothQsTileDialogAutoOnToggle
 import com.android.systemui.Prefs
 import com.android.systemui.animation.DialogCuj
 import com.android.systemui.animation.DialogTransitionAnimator
@@ -78,19 +76,19 @@
     /**
      * Shows the dialog.
      *
-     * @param context The context in which the dialog is displayed.
      * @param view The view from which the dialog is shown.
      */
     @kotlinx.coroutines.ExperimentalCoroutinesApi
-    fun showDialog(context: Context, view: View?) {
+    fun showDialog(view: View?) {
         cancelJob()
 
         job =
             coroutineScope.launch(mainDispatcher) {
                 var updateDeviceItemJob: Job?
                 var updateDialogUiJob: Job? = null
-                val dialogDelegate = createBluetoothTileDialog(context)
+                val dialogDelegate = createBluetoothTileDialog()
                 val dialog = dialogDelegate.createDialog()
+                val context = dialog.context
 
                 view?.let {
                     dialogTransitionAnimator.showFromView(
@@ -213,7 +211,7 @@
             }
     }
 
-    private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialogDelegate {
+    private suspend fun createBluetoothTileDialog(): BluetoothTileDialogDelegate {
         val cachedContentHeight =
             withContext(backgroundDispatcher) {
                 sharedPreferences.getInt(
@@ -223,7 +221,6 @@
             }
 
         return bluetoothDialogDelegateFactory.create(
-            context,
             UiProperties.build(
                 bluetoothStateInteractor.isBluetoothEnabled,
                 isAutoOnToggleFeatureAvailable()
@@ -277,7 +274,7 @@
 
     @VisibleForTesting
     internal suspend fun isAutoOnToggleFeatureAvailable() =
-        bluetoothQsTileDialogAutoOnToggle() && bluetoothAutoOnInteractor.isValuePresent()
+        bluetoothAutoOnInteractor.isAutoOnSupported()
 
     companion object {
         private const val INTERACTION_JANK_TAG = "bluetooth_tile_dialog"
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
index 06c0b8b..c89b476 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsService.java
@@ -33,6 +33,7 @@
 import android.content.Intent.CaptureContentForNoteStatusCodes;
 import android.content.res.Resources;
 import android.os.IBinder;
+import android.util.Log;
 
 import androidx.annotation.Nullable;
 
@@ -58,6 +59,8 @@
  */
 public class AppClipsService extends Service {
 
+  private static final String TAG = AppClipsService.class.getSimpleName();
+
     @Application private final Context mContext;
     private final FeatureFlags mFeatureFlags;
     private final Optional<Bubbles> mOptionalBubbles;
@@ -77,14 +80,22 @@
 
     private boolean checkIndependentVariables() {
         if (!mFeatureFlags.isEnabled(SCREENSHOT_APP_CLIPS)) {
+            Log.d(TAG, "Feature flag disabled");
             return false;
         }
 
         if (mOptionalBubbles.isEmpty()) {
+            Log.d(TAG, "Bubbles not available");
             return false;
         }
 
-        return isComponentValid();
+        if (isComponentValid()) {
+            Log.d(TAG, "checkIndependentVariables returned true");
+            return true;
+        }
+
+        Log.d(TAG, "checkIndependentVariables returned false");
+        return false;
     }
 
     private boolean isComponentValid() {
@@ -93,12 +104,27 @@
             componentName = ComponentName.unflattenFromString(
                     mContext.getString(R.string.config_screenshotAppClipsActivityComponent));
         } catch (Resources.NotFoundException e) {
+            Log.d(TAG, "AppClips activity component resource not defined");
             return false;
         }
 
-        return componentName != null
-                && !componentName.getPackageName().isEmpty()
-                && !componentName.getClassName().isEmpty();
+        if (componentName == null) {
+            Log.d(TAG, "AppClips component name not defined");
+            return false;
+        }
+
+        if (componentName.getPackageName().isEmpty()) {
+            Log.d(TAG, "AppClips component package name is empty");
+            return false;
+        }
+
+        if (componentName.getClassName().isEmpty()) {
+            Log.d(TAG, "AppClips component class name is empty");
+            return false;
+        }
+
+        Log.d(TAG, "isComponentValid returned true");
+        return true;
     }
 
     @Nullable
@@ -107,24 +133,39 @@
         return new IAppClipsService.Stub() {
             @Override
             public boolean canLaunchCaptureContentActivityForNote(int taskId) {
-                return canLaunchCaptureContentActivityForNoteInternal(taskId)
-                        == CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
+                if (canLaunchCaptureContentActivityForNoteInternal(taskId)
+                        == CAPTURE_CONTENT_FOR_NOTE_SUCCESS) {
+                    Log.d(TAG, String.format("Can launch AppClips returned true for %d", taskId));
+                    return true;
+                }
+
+                Log.d(TAG, String.format("Can launch AppClips returned false for %d", taskId));
+                return false;
             }
 
             @Override
             @CaptureContentForNoteStatusCodes
             public int canLaunchCaptureContentActivityForNoteInternal(int taskId) {
                 if (!mAreTaskAndTimeIndependentPrerequisitesMet) {
+                    Log.d(TAG,
+                        String.format("Task (%d) and time independent prereqs not met", taskId));
                     return CAPTURE_CONTENT_FOR_NOTE_FAILED;
                 }
 
                 if (!mOptionalBubbles.get().isAppBubbleTaskId(taskId)) {
+                    Log.d(TAG, String.format("Taskid %d is not app bubble task", taskId));
                     return CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED;
                 }
 
-                return mDevicePolicyManager.getScreenCaptureDisabled(null)
-                        ? CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN
-                        : CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
+                if (mDevicePolicyManager.getScreenCaptureDisabled(null)) {
+                    Log.d(TAG,
+                        String.format("Screen capture disabled by admin, taskId %d", taskId));
+                    return CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN;
+                }
+
+                Log.d(TAG,
+                    String.format("Can launch AppClips (internal) successful for %d", taskId));
+                return CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
             }
         };
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 0c69a65..8531eaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -22,6 +22,7 @@
 import android.provider.Settings
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.Dumpable
+import com.android.systemui.Flags.notificationMinimalismPrototype
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dump.DumpManager
@@ -59,6 +60,7 @@
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
@@ -260,8 +262,11 @@
         }
     }
 
-    private suspend fun trackUnseenFilterSettingChanges() {
-        secureSettings
+    private fun unseenFeatureEnabled(): Flow<Boolean> {
+        if (notificationMinimalismPrototype()) {
+            return flowOf(true)
+        }
+        return secureSettings
             // emit whenever the setting has changed
             .observerFlow(
                 UserHandle.USER_ALL,
@@ -283,17 +288,20 @@
             // only track the most recent emission, if events are happening faster than they can be
             // consumed
             .conflate()
-            .collectLatest { setting ->
-                // update local field and invalidate if necessary
-                if (setting != unseenFilterEnabled) {
-                    unseenFilterEnabled = setting
-                    unseenNotifFilter.invalidateList("unseen setting changed")
-                }
-                // if the setting is enabled, then start tracking and filtering unseen notifications
-                if (setting) {
-                    trackSeenNotifications()
-                }
+    }
+
+    private suspend fun trackUnseenFilterSettingChanges() {
+        unseenFeatureEnabled().collectLatest { setting ->
+            // update local field and invalidate if necessary
+            if (setting != unseenFilterEnabled) {
+                unseenFilterEnabled = setting
+                unseenNotifFilter.invalidateList("unseen setting changed")
             }
+            // if the setting is enabled, then start tracking and filtering unseen notifications
+            if (setting) {
+                trackSeenNotifications()
+            }
+        }
     }
 
     private val collectionListener =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index f792898..adcbbfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -58,6 +58,7 @@
 
     private FooterViewButton mClearAllButton;
     private FooterViewButton mManageOrHistoryButton;
+    private boolean mShouldBeHidden;
     private boolean mShowHistory;
     // String cache, for performance reasons.
     // Reading them from a Resources object can be quite slow sometimes.
@@ -110,6 +111,20 @@
         setSecondaryVisible(visible, animate, onAnimationEnded);
     }
 
+    /** See {@link this#setShouldBeHidden} below. */
+    public boolean shouldBeHidden() {
+        return mShouldBeHidden;
+    }
+
+    /**
+     * Whether this view's visibility should be set to INVISIBLE. Note that this is different from
+     * the {@link StackScrollerDecorView#setVisible} method, which in turn handles visibility
+     * transitions between VISIBLE and GONE.
+     */
+    public void setShouldBeHidden(boolean hide) {
+        mShouldBeHidden = hide;
+    }
+
     @Override
     public void dump(PrintWriter pwOriginal, String[] args) {
         IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index b8b4a03..eb6c7b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1767,9 +1767,7 @@
      */
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         this(context, attrs, context);
-        if (com.android.systemui.Flags.notificationRowUserContext()) {
-            Log.wtf(TAG, "This constructor shouldn't be called");
-        }
+        Log.wtf(TAG, "This constructor shouldn't be called");
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index 609b15e..3e932aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -31,7 +31,6 @@
 import com.android.internal.widget.ImageResolver;
 import com.android.internal.widget.LocalImageResolver;
 import com.android.internal.widget.MessagingMessage;
-import com.android.systemui.Flags;
 
 import java.util.HashSet;
 import java.util.List;
@@ -67,11 +66,7 @@
      * @param imageCache The implementation of internal cache.
      */
     public NotificationInlineImageResolver(Context context, ImageCache imageCache) {
-        if (Flags.notificationRowUserContext()) {
-            mContext = context;
-        } else {
-            mContext = context.getApplicationContext();
-        }
+        mContext = context;
         mImageCache = imageCache;
 
         if (mImageCache != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
index ea3036e..5fbcebd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
@@ -66,9 +66,7 @@
             mInflateOrigin = new Throwable("inflate requested here");
         }
         mListener = listener;
-        AsyncLayoutInflater inflater = com.android.systemui.Flags.notificationRowUserContext()
-                ? new AsyncLayoutInflater(context, makeRowInflater(entry))
-                : new AsyncLayoutInflater(context);
+        AsyncLayoutInflater inflater = new AsyncLayoutInflater(context, makeRowInflater(entry));
         mEntry = entry;
         entry.setInflationTask(this);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index 2d9c63e..1b53cbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -20,6 +20,7 @@
 import android.util.Log
 import android.view.View.GONE
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.Flags.notificationMinimalismPrototype
 import com.android.systemui.res.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
@@ -66,6 +67,11 @@
      */
     private var maxKeyguardNotifications by notNull<Int>()
 
+    /**
+     * Whether [maxKeyguardNotifications] will have 1 added to it when media is shown in the stack.
+     */
+    private var maxNotificationsExcludesMedia = false
+
     /** Minimum space between two notifications, see [calculateGapAndDividerHeight]. */
     private var dividerHeight by notNull<Float>()
 
@@ -168,7 +174,11 @@
         log { "\n" }
 
         val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfHeight)
+
+        // TODO: Avoid making this split shade assumption by simply checking the stack for media
         val isMediaShowing = mediaDataManager.hasActiveMediaOrRecommendation()
+        val isMediaShowingInStack = isMediaShowing && !splitShadeStateController
+                .shouldUseSplitNotificationShade(resources)
 
         log { "\tGet maxNotifWithoutSavingSpace ---" }
         val maxNotifWithoutSavingSpace =
@@ -181,12 +191,11 @@
             }
 
         // How many notifications we can show at heightWithoutLockscreenConstraints
-        var minCountAtHeightWithoutConstraints =
-            if (isMediaShowing && !splitShadeStateController
-                    .shouldUseSplitNotificationShade(resources)) 2 else 1
+        val minCountAtHeightWithoutConstraints = if (isMediaShowingInStack) 2 else 1
         log {
             "\t---maxNotifWithoutSavingSpace=$maxNotifWithoutSavingSpace " +
                 "isMediaShowing=$isMediaShowing" +
+                "isMediaShowingInStack=$isMediaShowingInStack" +
                 "minCountAtHeightWithoutConstraints=$minCountAtHeightWithoutConstraints"
         }
         log { "\n" }
@@ -223,7 +232,9 @@
         }
 
         if (onLockscreen()) {
-            maxNotifications = min(maxKeyguardNotifications, maxNotifications)
+            val increaseMaxForMedia = maxNotificationsExcludesMedia && isMediaShowingInStack
+            val lockscreenMax = maxKeyguardNotifications.safeIncrementIf(increaseMaxForMedia)
+            maxNotifications = min(lockscreenMax, maxNotifications)
         }
 
         // Could be < 0 if the space available is less than the shelf size. Returns 0 in this case.
@@ -276,7 +287,7 @@
             height = notifsHeight + shelfHeightWithSpaceBefore
             log {
                 "--- computeHeight(maxNotifs=$maxNotifs, shelfHeight=$shelfHeight)" +
-                    " -> ${height}=($notifsHeight+$shelfHeightWithSpaceBefore)" +
+                    " -> $height=($notifsHeight+$shelfHeightWithSpaceBefore)" +
                     " | saveSpaceOnLockscreen=$saveSpaceOnLockscreen"
             }
         }
@@ -367,8 +378,9 @@
     }
 
     fun updateResources() {
-        maxKeyguardNotifications =
-            infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+        maxKeyguardNotifications = if (notificationMinimalismPrototype()) 1
+            else infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+        maxNotificationsExcludesMedia = notificationMinimalismPrototype()
 
         dividerHeight =
             max(1f, resources.getDimensionPixelSize(R.dimen.notification_divider_height).toFloat())
@@ -486,6 +498,13 @@
             v
         }
 
+    private fun Int.safeIncrementIf(condition: Boolean): Int =
+        if (condition && this != Int.MAX_VALUE) {
+            this + 1
+        } else {
+            this
+        }
+
     /** Returns the last index where [predicate] returns true, or -1 if it was always false. */
     private fun <T> Sequence<T>.lastIndexWhile(predicate: (T) -> Boolean): Int =
         takeWhile(predicate).count() - 1
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index b42c07d..5eaccd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -594,15 +594,16 @@
         );
         if (view instanceof FooterView) {
             if (FooterViewRefactor.isEnabled()) {
-                final float footerEnd = algorithmState.mCurrentExpandedYPosition
-                        + view.getIntrinsicHeight();
-                final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight();
-                // TODO(b/293167744): May be able to keep only noSpaceForFooter here if we add an
-                //  emission when clearAllNotifications is called, and then use that in the footer
-                //  visibility flow.
-                ((FooterView.FooterViewState) viewState).hideContent =
-                        noSpaceForFooter || (ambientState.isClearAllInProgress()
-                                && !hasNonClearableNotifs(algorithmState));
+                if (((FooterView) view).shouldBeHidden()) {
+                    viewState.hidden = true;
+                } else {
+                    final float footerEnd = algorithmState.mCurrentExpandedYPosition
+                            + view.getIntrinsicHeight();
+                    final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight();
+                    ((FooterView.FooterViewState) viewState).hideContent =
+                            noSpaceForFooter || (ambientState.isClearAllInProgress()
+                                    && !hasNonClearableNotifs(algorithmState));
+                }
 
             } else {
                 final boolean shadeClosed = !ambientState.isShadeExpanded();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 97cbbe8..18bb5119 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -193,13 +193,14 @@
                 },
             )
         launch {
-            viewModel.shouldShowFooterView.collect { animatedVisibility ->
+            viewModel.shouldIncludeFooterView.collect { animatedVisibility ->
                 footerView.setVisible(
                     /* visible = */ animatedVisibility.value,
                     /* animate = */ animatedVisibility.isAnimating,
                 )
             }
         }
+        launch { viewModel.shouldHideFooterView.collect { footerView.setShouldBeHidden(it) } }
         disposableHandle.awaitCancellationThenDispose()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index a6ca027..5a7433d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -31,7 +31,6 @@
 import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackInteractor
 import com.android.systemui.statusbar.policy.domain.interactor.UserSetupInteractor
 import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
-import com.android.systemui.util.kotlin.combine
 import com.android.systemui.util.kotlin.sample
 import com.android.systemui.util.ui.AnimatableEvent
 import com.android.systemui.util.ui.AnimatedValue
@@ -111,7 +110,32 @@
         }
     }
 
-    val shouldShowFooterView: Flow<AnimatedValue<Boolean>> by lazy {
+    /**
+     * Whether the footer should not be visible for the user, even if it's present in the list (as
+     * per [shouldIncludeFooterView] below).
+     *
+     * This essentially corresponds to having the view set to INVISIBLE.
+     */
+    val shouldHideFooterView: Flow<Boolean> by lazy {
+        if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
+            flowOf(false)
+        } else {
+            // When the shade is closed, the footer is still present in the list, but not visible.
+            // This prevents the footer from being shown when a HUN is present, while still allowing
+            // the footer to be counted as part of the shade for measurements.
+            shadeInteractor.shadeExpansion.map { it == 0f }.distinctUntilChanged()
+        }
+    }
+
+    /**
+     * Whether the footer should be part of the list or not, and whether the transition from one
+     * state to another should be animated. This essentially corresponds to transitioning the view
+     * visibility from VISIBLE to GONE and vice versa.
+     *
+     * Note that this value being true doesn't necessarily mean that the footer is visible. It could
+     * be hidden by another condition (see [shouldHideFooterView] above).
+     */
+    val shouldIncludeFooterView: Flow<AnimatedValue<Boolean>> by lazy {
         if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
             flowOf(AnimatedValue.NotAnimating(false))
         } else {
@@ -120,34 +144,30 @@
                     userSetupInteractor.isUserSetUp,
                     notificationStackInteractor.isShowingOnLockscreen,
                     shadeInteractor.isQsFullscreen,
-                    remoteInputInteractor.isRemoteInputActive,
-                    shadeInteractor.shadeExpansion.map { it == 0f }.distinctUntilChanged(),
+                    remoteInputInteractor.isRemoteInputActive
                 ) {
                     hasNotifications,
                     isUserSetUp,
                     isShowingOnLockscreen,
                     qsFullScreen,
-                    isRemoteInputActive,
-                    isShadeClosed ->
+                    isRemoteInputActive ->
                     when {
-                        !hasNotifications -> VisibilityChange.HIDE_WITH_ANIMATION
+                        !hasNotifications -> VisibilityChange.DISAPPEAR_WITH_ANIMATION
                         // Hide the footer until the user setup is complete, to prevent access
                         // to settings (b/193149550).
-                        !isUserSetUp -> VisibilityChange.HIDE_WITH_ANIMATION
+                        !isUserSetUp -> VisibilityChange.DISAPPEAR_WITH_ANIMATION
                         // Do not show the footer if the lockscreen is visible (incl. AOD),
                         // except if the shade is opened on top. See also b/219680200.
                         // Do not animate, as that makes the footer appear briefly when
                         // transitioning between the shade and keyguard.
-                        isShowingOnLockscreen -> VisibilityChange.HIDE_WITHOUT_ANIMATION
+                        isShowingOnLockscreen -> VisibilityChange.DISAPPEAR_WITHOUT_ANIMATION
                         // Do not show the footer if quick settings are fully expanded (except
                         // for the foldable split shade view). See b/201427195 && b/222699879.
-                        qsFullScreen -> VisibilityChange.HIDE_WITH_ANIMATION
+                        qsFullScreen -> VisibilityChange.DISAPPEAR_WITH_ANIMATION
                         // Hide the footer if remote input is active (i.e. user is replying to a
                         // notification). See b/75984847.
-                        isRemoteInputActive -> VisibilityChange.HIDE_WITH_ANIMATION
-                        // Never show the footer if the shade is collapsed (e.g. when HUNing).
-                        isShadeClosed -> VisibilityChange.HIDE_WITHOUT_ANIMATION
-                        else -> VisibilityChange.SHOW_WITH_ANIMATION
+                        isRemoteInputActive -> VisibilityChange.DISAPPEAR_WITH_ANIMATION
+                        else -> VisibilityChange.APPEAR_WITH_ANIMATION
                     }
                 }
                 .flowOn(bgDispatcher)
@@ -180,9 +200,9 @@
     }
 
     enum class VisibilityChange(val visible: Boolean, val canAnimate: Boolean) {
-        HIDE_WITHOUT_ANIMATION(visible = false, canAnimate = false),
-        HIDE_WITH_ANIMATION(visible = false, canAnimate = true),
-        SHOW_WITH_ANIMATION(visible = true, canAnimate = true)
+        DISAPPEAR_WITHOUT_ANIMATION(visible = false, canAnimate = false),
+        DISAPPEAR_WITH_ANIMATION(visible = false, canAnimate = true),
+        APPEAR_WITH_ANIMATION(visible = true, canAnimate = true)
     }
 
     // TODO(b/308591475): This should be tracked separately by the empty shade.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index a55de25..37646ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -21,6 +21,7 @@
 import android.app.TaskStackBuilder
 import android.content.Context
 import android.content.Intent
+import android.os.Bundle
 import android.os.RemoteException
 import android.os.UserHandle
 import android.provider.Settings
@@ -149,6 +150,23 @@
         )
     }
 
+    override fun startPendingIntentMaybeDismissingKeyguard(
+        intent: PendingIntent,
+        intentSentUiThreadCallback: Runnable?,
+        animationController: ActivityTransitionAnimator.Controller?,
+        fillInIntent: Intent?,
+        extraOptions: Bundle?,
+    ) {
+        activityStarterInternal.startPendingIntentDismissingKeyguard(
+            intent = intent,
+            intentSentUiThreadCallback = intentSentUiThreadCallback,
+            animationController = animationController,
+            showOverLockscreen = true,
+            fillInIntent = fillInIntent,
+            extraOptions = extraOptions,
+        )
+    }
+
     /**
      * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
      *   this.
@@ -554,6 +572,8 @@
             associatedView: View? = null,
             animationController: ActivityTransitionAnimator.Controller? = null,
             showOverLockscreen: Boolean = false,
+            fillInIntent: Intent? = null,
+            extraOptions: Bundle? = null,
         ) {
             val animationController =
                 if (associatedView is ExpandableNotificationRow) {
@@ -614,9 +634,10 @@
                                 val options =
                                     ActivityOptions(
                                         CentralSurfaces.getActivityOptions(
-                                            displayId,
-                                            animationAdapter
-                                        )
+                                                displayId,
+                                                animationAdapter
+                                            )
+                                            .apply { extraOptions?.let { putAll(it) } }
                                     )
                                 // TODO b/221255671: restrict this to only be set for
                                 // notifications
@@ -625,9 +646,9 @@
                                     ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
                                 )
                                 return intent.sendAndReturnResult(
-                                    null,
+                                    context,
                                     0,
-                                    null,
+                                    fillInIntent,
                                     null,
                                     null,
                                     null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
index 60b8599..b085d80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -301,7 +301,7 @@
             .flatMapLatest { it.networkName }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
+                columnPrefix = "intent",
                 initialValue = activeRepo.value.networkName.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
@@ -311,7 +311,7 @@
             .flatMapLatest { it.carrierName }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
+                columnPrefix = "sub",
                 initialValue = activeRepo.value.carrierName.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.carrierName.value)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index f01ac0e..5ab2ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -358,7 +358,13 @@
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), telephonyManager.simCarrierId)
 
-    /** BroadcastDispatcher does not handle sticky broadcasts, so we can't use it here */
+    /**
+     * BroadcastDispatcher does not handle sticky broadcasts, so we can't use it here. Note that we
+     * now use the [SharingStarted.Eagerly] strategy, because there have been cases where the sticky
+     * broadcast does not represent the correct state.
+     *
+     * See b/322432056 for context.
+     */
     @SuppressLint("RegisterReceiverViaContext")
     override val networkName: StateFlow<NetworkNameModel> =
         conflatedCallbackFlow {
@@ -388,7 +394,7 @@
                 awaitClose { context.unregisterReceiver(receiver) }
             }
             .flowOn(bgDispatcher)
-            .stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
+            .stateIn(scope, SharingStarted.Eagerly, defaultNetworkName)
 
     override val dataEnabled = run {
         val initial = telephonyManager.isDataConnectionAllowed
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt
index 3710713..036d3c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt
@@ -16,22 +16,25 @@
 
 package com.android.systemui.qs.tiles.dialog.bluetooth
 
-import android.content.pm.UserInfo
+import android.bluetooth.BluetoothAdapter
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.LocalBluetoothManager
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.settings.FakeSettings
-import com.google.common.truth.Truth
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import kotlin.test.Test
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Rule
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
 
@@ -41,8 +44,17 @@
     @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
     private val testDispatcher = StandardTestDispatcher()
     private val testScope = TestScope(testDispatcher)
-    private var secureSettings: FakeSettings = FakeSettings()
-    private val userRepository: FakeUserRepository = FakeUserRepository()
+    private val bluetoothAdapter =
+        mock<BluetoothAdapter> {
+            var autoOn = false
+            whenever(isAutoOnEnabled).thenAnswer { autoOn }
+
+            whenever(setAutoOnEnabled(anyBoolean())).thenAnswer { invocation ->
+                autoOn = invocation.getArgument(0) as Boolean
+                autoOn
+            }
+        }
+    @Mock private lateinit var localBluetoothManager: LocalBluetoothManager
     private lateinit var bluetoothAutoOnInteractor: BluetoothAutoOnInteractor
 
     @Before
@@ -50,49 +62,35 @@
         bluetoothAutoOnInteractor =
             BluetoothAutoOnInteractor(
                 BluetoothAutoOnRepository(
-                    secureSettings,
-                    userRepository,
+                    localBluetoothManager,
+                    bluetoothAdapter,
                     testScope.backgroundScope,
-                    testDispatcher
+                    testDispatcher,
                 )
             )
     }
 
     @Test
-    fun testSet_bluetoothAutoOnUnset_doNothing() {
+    fun testSetEnabled_bluetoothAutoOnUnsupported_doNothing() {
         testScope.runTest {
+            whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(false)
+
             bluetoothAutoOnInteractor.setEnabled(true)
-
-            val actualValue by collectLastValue(bluetoothAutoOnInteractor.isEnabled)
-
             runCurrent()
 
-            Truth.assertThat(actualValue).isEqualTo(false)
+            assertFalse(bluetoothAdapter.isAutoOnEnabled)
         }
     }
 
     @Test
-    fun testSet_bluetoothAutoOnSet_setNewValue() {
+    fun testSetEnabled_bluetoothAutoOnSupported_setNewValue() {
         testScope.runTest {
-            userRepository.setUserInfos(listOf(SYSTEM_USER))
-            secureSettings.putIntForUser(
-                BluetoothAutoOnRepository.SETTING_NAME,
-                BluetoothAutoOnInteractor.DISABLED,
-                SYSTEM_USER_ID
-            )
+            whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(true)
+
             bluetoothAutoOnInteractor.setEnabled(true)
-
-            val actualValue by collectLastValue(bluetoothAutoOnInteractor.isEnabled)
-
             runCurrent()
 
-            Truth.assertThat(actualValue).isEqualTo(true)
+            assertTrue(bluetoothAdapter.isAutoOnEnabled)
         }
     }
-
-    companion object {
-        private const val SYSTEM_USER_ID = 0
-        private val SYSTEM_USER =
-            UserInfo(/* id= */ SYSTEM_USER_ID, /* name= */ "system user", /* flags= */ 0)
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt
index cd1452a..3119284 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt
@@ -16,18 +16,14 @@
 
 package com.android.systemui.qs.tiles.dialog.bluetooth
 
-import android.content.pm.UserInfo
-import android.os.UserHandle
+import android.bluetooth.BluetoothAdapter
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.BluetoothEventManager
+import com.android.settingslib.bluetooth.LocalBluetoothManager
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnInteractor.Companion.DISABLED
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnInteractor.Companion.ENABLED
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnRepository.Companion.SETTING_NAME
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnRepository.Companion.UNSET
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
@@ -37,6 +33,7 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mock
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
 
@@ -46,83 +43,57 @@
     @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
     private val testDispatcher = StandardTestDispatcher()
     private val testScope = TestScope(testDispatcher)
-    private var secureSettings: FakeSettings = FakeSettings()
-    private val userRepository: FakeUserRepository = FakeUserRepository()
+    @Mock private lateinit var bluetoothAdapter: BluetoothAdapter
+    @Mock private lateinit var localBluetoothManager: LocalBluetoothManager
+    @Mock private lateinit var eventManager: BluetoothEventManager
 
     private lateinit var bluetoothAutoOnRepository: BluetoothAutoOnRepository
 
     @Before
     fun setUp() {
+        whenever(localBluetoothManager.eventManager).thenReturn(eventManager)
         bluetoothAutoOnRepository =
             BluetoothAutoOnRepository(
-                secureSettings,
-                userRepository,
+                localBluetoothManager,
+                bluetoothAdapter,
                 testScope.backgroundScope,
-                testDispatcher
+                testDispatcher,
             )
-
-        userRepository.setUserInfos(listOf(SECONDARY_USER, SYSTEM_USER))
     }
 
     @Test
-    fun testGetValue_valueUnset() {
+    fun testIsAutoOn_returnFalse() {
         testScope.runTest {
-            userRepository.setSelectedUserInfo(SYSTEM_USER)
+            whenever(bluetoothAdapter.isAutoOnEnabled).thenReturn(false)
             val actualValue by collectLastValue(bluetoothAutoOnRepository.isAutoOn)
 
             runCurrent()
 
-            assertThat(actualValue).isEqualTo(UNSET)
-            assertThat(bluetoothAutoOnRepository.isValuePresent()).isFalse()
+            assertThat(actualValue).isEqualTo(false)
         }
     }
 
     @Test
-    fun testGetValue_valueFalse() {
+    fun testIsAutoOn_returnTrue() {
         testScope.runTest {
-            userRepository.setSelectedUserInfo(SYSTEM_USER)
+            whenever(bluetoothAdapter.isAutoOnEnabled).thenReturn(true)
             val actualValue by collectLastValue(bluetoothAutoOnRepository.isAutoOn)
 
-            secureSettings.putIntForUser(SETTING_NAME, DISABLED, UserHandle.USER_SYSTEM)
             runCurrent()
 
-            assertThat(actualValue).isEqualTo(DISABLED)
+            assertThat(actualValue).isEqualTo(true)
         }
     }
 
     @Test
-    fun testGetValue_valueTrue() {
+    fun testIsAutoOnSupported_returnTrue() {
         testScope.runTest {
-            userRepository.setSelectedUserInfo(SYSTEM_USER)
-            val actualValue by collectLastValue(bluetoothAutoOnRepository.isAutoOn)
+            whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(true)
+            val actualValue = bluetoothAutoOnRepository.isAutoOnSupported()
 
-            secureSettings.putIntForUser(SETTING_NAME, ENABLED, UserHandle.USER_SYSTEM)
             runCurrent()
 
-            assertThat(actualValue).isEqualTo(ENABLED)
+            assertThat(actualValue).isEqualTo(true)
         }
     }
-
-    @Test
-    fun testGetValue_valueTrue_secondaryUser_returnTrue() {
-        testScope.runTest {
-            userRepository.setSelectedUserInfo(SECONDARY_USER)
-            val actualValue by collectLastValue(bluetoothAutoOnRepository.isAutoOn)
-
-            secureSettings.putIntForUser(SETTING_NAME, DISABLED, SYSTEM_USER_ID)
-            secureSettings.putIntForUser(SETTING_NAME, ENABLED, SECONDARY_USER_ID)
-            runCurrent()
-
-            assertThat(actualValue).isEqualTo(ENABLED)
-        }
-    }
-
-    companion object {
-        private const val SYSTEM_USER_ID = 0
-        private const val SECONDARY_USER_ID = 1
-        private val SYSTEM_USER =
-            UserInfo(/* id= */ SYSTEM_USER_ID, /* name= */ "system user", /* flags= */ 0)
-        private val SECONDARY_USER =
-            UserInfo(/* id= */ SECONDARY_USER_ID, /* name= */ "secondary user", /* flags= */ 0)
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
index 8ecb953..17b6127 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
@@ -109,7 +109,6 @@
 
         mBluetoothTileDialogDelegate =
             BluetoothTileDialogDelegate(
-                mContext,
                 uiProperties,
                 CONTENT_HEIGHT,
                 ENABLED,
@@ -119,14 +118,12 @@
                 fakeSystemClock,
                 uiEventLogger,
                 logger,
-                sysuiDialogFactory,
-                LayoutInflater.from(mContext)
+                sysuiDialogFactory
             )
 
         whenever(
                 sysuiDialogFactory.create(
-                    any(SystemUIDialog.Delegate::class.java),
-                    any(Context::class.java)
+                    any(SystemUIDialog.Delegate::class.java)
                 )
             )
             .thenAnswer {
@@ -216,7 +213,6 @@
             LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
         val viewHolder =
             BluetoothTileDialogDelegate(
-                    mContext,
                     uiProperties,
                     CONTENT_HEIGHT,
                     ENABLED,
@@ -227,7 +223,6 @@
                     uiEventLogger,
                     logger,
                     sysuiDialogFactory,
-                    LayoutInflater.from(mContext)
                 )
                 .Adapter(bluetoothTileDialogCallback)
                 .DeviceItemViewHolder(view)
@@ -273,7 +268,6 @@
             val cachedHeight = Int.MAX_VALUE
             val dialog =
                 BluetoothTileDialogDelegate(
-                        mContext,
                         BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
                         cachedHeight,
                         ENABLED,
@@ -284,7 +278,6 @@
                         uiEventLogger,
                         logger,
                         sysuiDialogFactory,
-                        LayoutInflater.from(mContext)
                     )
                     .createDialog()
             dialog.show()
@@ -298,7 +291,6 @@
         testScope.runTest {
             val dialog =
                 BluetoothTileDialogDelegate(
-                        mContext,
                         BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
                         MATCH_PARENT,
                         ENABLED,
@@ -309,7 +301,6 @@
                         uiEventLogger,
                         logger,
                         sysuiDialogFactory,
-                        LayoutInflater.from(mContext)
                     )
                     .createDialog()
             dialog.show()
@@ -323,7 +314,6 @@
         testScope.runTest {
             val dialog =
                 BluetoothTileDialogDelegate(
-                        mContext,
                         BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
                         MATCH_PARENT,
                         ENABLED,
@@ -334,7 +324,6 @@
                         uiEventLogger,
                         logger,
                         sysuiDialogFactory,
-                        LayoutInflater.from(mContext)
                     )
                     .createDialog()
             dialog.show()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
index 39e2413..c8a2aa6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.qs.tiles.dialog.bluetooth
 
-import android.content.pm.UserInfo
+import android.bluetooth.BluetoothAdapter
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.View
@@ -26,19 +26,18 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LocalBluetoothManager
 import com.android.settingslib.flags.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.kotlin.getMutableStateFlow
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineDispatcher
@@ -75,6 +74,8 @@
 
     @Mock private lateinit var bluetoothStateInteractor: BluetoothStateInteractor
 
+    @Mock private lateinit var bluetoothAutoOnInteractor: BluetoothAutoOnInteractor
+
     @Mock private lateinit var deviceItemInteractor: DeviceItemInteractor
 
     @Mock private lateinit var activityStarter: ActivityStarter
@@ -87,6 +88,10 @@
 
     @Mock private lateinit var uiEventLogger: UiEventLogger
 
+    @Mock private lateinit var bluetoothAdapter: BluetoothAdapter
+
+    @Mock private lateinit var localBluetoothManager: LocalBluetoothManager
+
     @Mock
     private lateinit var mBluetoothTileDialogDelegateDelegateFactory:
         BluetoothTileDialogDelegate.Factory
@@ -100,8 +105,6 @@
     private lateinit var scheduler: TestCoroutineScheduler
     private lateinit var dispatcher: CoroutineDispatcher
     private lateinit var testScope: TestScope
-    private lateinit var secureSettings: FakeSettings
-    private lateinit var userRepository: FakeUserRepository
 
     @Before
     fun setUp() {
@@ -109,14 +112,6 @@
         scheduler = TestCoroutineScheduler()
         dispatcher = UnconfinedTestDispatcher(scheduler)
         testScope = TestScope(dispatcher)
-        secureSettings = FakeSettings()
-        userRepository = FakeUserRepository()
-        userRepository.setUserInfos(listOf(SYSTEM_USER))
-        secureSettings.putIntForUser(
-            BluetoothAutoOnRepository.SETTING_NAME,
-            BluetoothAutoOnInteractor.ENABLED,
-            SYSTEM_USER_ID
-        )
         bluetoothTileDialogViewModel =
             BluetoothTileDialogViewModel(
                 deviceItemInteractor,
@@ -124,8 +119,8 @@
                 // TODO(b/316822488): Create FakeBluetoothAutoOnInteractor.
                 BluetoothAutoOnInteractor(
                     BluetoothAutoOnRepository(
-                        secureSettings,
-                        userRepository,
+                        localBluetoothManager,
+                        bluetoothAdapter,
                         testScope.backgroundScope,
                         dispatcher
                     )
@@ -148,7 +143,6 @@
         whenever(
                 mBluetoothTileDialogDelegateDelegateFactory.create(
                     any(),
-                    any(),
                     anyInt(),
                     ArgumentMatchers.anyBoolean(),
                     any(),
@@ -157,6 +151,7 @@
             )
             .thenReturn(bluetoothTileDialogDelegate)
         whenever(bluetoothTileDialogDelegate.createDialog()).thenReturn(sysuiDialog)
+        whenever(sysuiDialog.context).thenReturn(mContext)
         whenever(bluetoothTileDialogDelegate.bluetoothStateToggle)
             .thenReturn(getMutableStateFlow(false))
         whenever(bluetoothTileDialogDelegate.deviceItemClick)
@@ -169,7 +164,7 @@
     @Test
     fun testShowDialog_noAnimation() {
         testScope.runTest {
-            bluetoothTileDialogViewModel.showDialog(context, null)
+            bluetoothTileDialogViewModel.showDialog(null)
 
             verify(mDialogTransitionAnimator, never()).showFromView(any(), any(), any(), any())
         }
@@ -178,7 +173,7 @@
     @Test
     fun testShowDialog_animated() {
         testScope.runTest {
-            bluetoothTileDialogViewModel.showDialog(mContext, LinearLayout(mContext))
+            bluetoothTileDialogViewModel.showDialog(LinearLayout(mContext))
 
             verify(mDialogTransitionAnimator).showFromView(any(), any(), nullable(), anyBoolean())
         }
@@ -188,7 +183,7 @@
     fun testShowDialog_animated_callInBackgroundThread() {
         testScope.runTest {
             backgroundExecutor.execute {
-                bluetoothTileDialogViewModel.showDialog(mContext, LinearLayout(mContext))
+                bluetoothTileDialogViewModel.showDialog(LinearLayout(mContext))
 
                 verify(mDialogTransitionAnimator)
                     .showFromView(any(), any(), nullable(), anyBoolean())
@@ -199,7 +194,7 @@
     @Test
     fun testShowDialog_fetchDeviceItem() {
         testScope.runTest {
-            bluetoothTileDialogViewModel.showDialog(context, null)
+            bluetoothTileDialogViewModel.showDialog(null)
 
             verify(deviceItemInteractor).deviceItemUpdate
         }
@@ -208,7 +203,7 @@
     @Test
     fun testShowDialog_withBluetoothStateValue() {
         testScope.runTest {
-            bluetoothTileDialogViewModel.showDialog(context, null)
+            bluetoothTileDialogViewModel.showDialog(null)
 
             verify(bluetoothStateInteractor).bluetoothStateUpdate
         }
@@ -218,7 +213,7 @@
     fun testStartSettingsActivity_activityLaunched_dialogDismissed() {
         testScope.runTest {
             whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
-            bluetoothTileDialogViewModel.showDialog(context, null)
+            bluetoothTileDialogViewModel.showDialog(null)
 
             val clickedView = View(context)
             bluetoothTileDialogViewModel.onPairNewDeviceClicked(clickedView)
@@ -265,26 +260,22 @@
     }
 
     @Test
-    fun testIsAutoOnToggleFeatureAvailable_flagOn_settingValueSet_returnTrue() {
+    fun testIsAutoOnToggleFeatureAvailable_returnTrue() {
         testScope.runTest {
+            whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(true)
+
             val actual = bluetoothTileDialogViewModel.isAutoOnToggleFeatureAvailable()
             assertThat(actual).isTrue()
         }
     }
 
     @Test
-    fun testIsAutoOnToggleFeatureAvailable_flagOff_settingValueSet_returnFalse() {
+    fun testIsAutoOnToggleFeatureAvailable_returnFalse() {
         testScope.runTest {
-            mSetFlagsRule.disableFlags(Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE)
+            whenever(bluetoothAdapter.isAutoOnSupported).thenReturn(false)
 
             val actual = bluetoothTileDialogViewModel.isAutoOnToggleFeatureAvailable()
             assertThat(actual).isFalse()
         }
     }
-
-    companion object {
-        private const val SYSTEM_USER_ID = 0
-        private val SYSTEM_USER =
-            UserInfo(/* id= */ SYSTEM_USER_ID, /* name= */ "system user", /* flags= */ 0)
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index ee2eb80..0e89d80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -845,7 +845,6 @@
     }
 
     @Test
-    @EnableFlags(com.android.systemui.Flags.FLAG_NOTIFICATION_ROW_USER_CONTEXT)
     public void imageResolver_differentNotificationUser_createsUserContext() throws Exception {
         UserHandle user = new UserHandle(33);
         Context userContext = new SysuiTestableContext(mContext);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 6549193..fe0d9d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -23,6 +23,7 @@
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
 
+import static com.android.systemui.concurrency.FakeExecutorKosmosKt.getFakeExecutor;
 import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
 
 import static junit.framework.Assert.assertNotNull;
@@ -124,12 +125,11 @@
     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
             TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
 
-    private KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
-    private TestScope mTestScope = mKosmos.getTestScope();
-    private JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
-    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
-    private TestableLooper mTestableLooper;
-    private Handler mHandler;
+    private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
+    private final TestScope mTestScope = mKosmos.getTestScope();
+    private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
+    private final FakeExecutor mExecutor = mKosmos.getFakeExecutor();
+    private final Handler mHandler = mKosmos.getFakeExecutorHandler();
     private NotificationTestHelper mHelper;
     private NotificationGutsManager mGutsManager;
 
@@ -171,10 +171,8 @@
 
     @Before
     public void setUp() {
-        mTestableLooper = TestableLooper.get(this);
         allowTestableLooperAsMainThread();
-        mHandler = Handler.createAsync(mTestableLooper.getLooper());
-        mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
+        mHelper = new NotificationTestHelper(mContext, mDependency);
         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
 
         mWindowRootViewVisibilityInteractor = new WindowRootViewVisibilityInteractor(
@@ -248,7 +246,7 @@
 
         assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
         assertEquals(View.INVISIBLE, guts.getVisibility());
-        mTestableLooper.processAllMessages();
+        mExecutor.runAllReady();
         verify(guts).openControls(
                 anyInt(),
                 anyInt(),
@@ -261,7 +259,7 @@
 
         verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
         verify(row, times(1)).setGutsView(any());
-        mTestableLooper.processAllMessages();
+        mExecutor.runAllReady();
         verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), false);
     }
 
@@ -352,7 +350,7 @@
         when(entry.getGuts()).thenReturn(guts);
 
         assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
-        mTestableLooper.processAllMessages();
+        mExecutor.runAllReady();
         verify(guts).openControls(
                 anyInt(),
                 anyInt(),
@@ -365,7 +363,7 @@
         row.onDensityOrFontScaleChanged();
         mGutsManager.onDensityOrFontScaleChanged(entry);
 
-        mTestableLooper.processAllMessages();
+        mExecutor.runAllReady();
 
         mGutsManager.closeAndSaveGuts(false, false, false, 0, 0, false);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
index 012ff2e..65a960b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
@@ -27,12 +27,11 @@
 import android.content.pm.launcherApps
 import android.graphics.Color
 import android.os.Binder
-import android.os.Handler
+import android.os.fakeExecutorHandler
 import android.os.userManager
 import android.provider.Settings
 import android.service.notification.NotificationListenerService.Ranking
 import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import android.util.ArraySet
 import android.view.View
@@ -45,6 +44,7 @@
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.internal.statusbar.statusBarService
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.concurrency.fakeExecutor
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager
@@ -71,9 +71,7 @@
 import com.android.systemui.statusbar.policy.deviceProvisionedController
 import com.android.systemui.statusbar.policy.headsUpManager
 import com.android.systemui.testKosmos
-import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.kotlin.JavaAdapter
-import com.android.systemui.util.time.FakeSystemClock
 import com.android.systemui.wmshell.BubblesManager
 import java.util.Optional
 import junit.framework.Assert
@@ -106,9 +104,8 @@
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val javaAdapter = JavaAdapter(testScope.backgroundScope)
-    private val executor = FakeExecutor(FakeSystemClock())
-    private lateinit var testableLooper: TestableLooper
-    private lateinit var handler: Handler
+    private val executor = kosmos.fakeExecutor
+    private val handler = kosmos.fakeExecutorHandler
     private lateinit var helper: NotificationTestHelper
     private lateinit var gutsManager: NotificationGutsManager
     private lateinit var windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor
@@ -148,10 +145,8 @@
         MockitoAnnotations.initMocks(this)
         val sceneContainerFlags = kosmos.fakeSceneContainerFlags
         sceneContainerFlags.enabled = true
-        testableLooper = TestableLooper.get(this)
         allowTestableLooperAsMainThread()
-        handler = Handler.createAsync(testableLooper.getLooper())
-        helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+        helper = NotificationTestHelper(mContext, mDependency)
         Mockito.`when`(accessibilityManager.isTouchExplorationEnabled).thenReturn(false)
         windowRootViewVisibilityInteractor =
             WindowRootViewVisibilityInteractor(
@@ -227,7 +222,7 @@
         Mockito.`when`(row.guts).thenReturn(guts)
         Assert.assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem))
         assertEquals(View.INVISIBLE.toLong(), guts.visibility.toLong())
-        testableLooper.processAllMessages()
+        executor.runAllReady()
         verify(guts)
             .openControls(
                 ArgumentMatchers.anyInt(),
@@ -247,7 +242,7 @@
                 ArgumentMatchers.anyBoolean()
             )
         verify(row, Mockito.times(1)).setGutsView(ArgumentMatchers.any())
-        testableLooper.processAllMessages()
+        executor.runAllReady()
         verify(headsUpManager).setGutsShown(realRow.entry, false)
     }
 
@@ -343,7 +338,7 @@
         Mockito.`when`(entry.row).thenReturn(row)
         Mockito.`when`(entry.getGuts()).thenReturn(guts)
         Assert.assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem))
-        testableLooper.processAllMessages()
+        executor.runAllReady()
         verify(guts)
             .openControls(
                 ArgumentMatchers.anyInt(),
@@ -356,7 +351,7 @@
         verify(row).setGutsView(ArgumentMatchers.any())
         row.onDensityOrFontScaleChanged()
         gutsManager.onDensityOrFontScaleChanged(entry)
-        testableLooper.processAllMessages()
+        executor.runAllReady()
         gutsManager.closeAndSaveGuts(false, false, false, 0, 0, false)
         verify(guts)
             .closeControls(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 09a3eb48..954335e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -615,10 +615,8 @@
 
         LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        if (com.android.systemui.Flags.notificationRowUserContext()) {
-            inflater.setFactory2(new RowInflaterTask.RowAsyncLayoutInflater(entry, mSystemClock,
-                    mRowInflaterTaskLogger));
-        }
+        inflater.setFactory2(new RowInflaterTask.RowAsyncLayoutInflater(entry, mSystemClock,
+                mRowInflaterTaskLogger));
         mRow = (ExpandableNotificationRow) inflater.inflate(
                 R.layout.status_bar_notification_row,
                 null /* root */,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
index 8f88501..a15b4cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
@@ -25,8 +25,6 @@
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
 import android.view.LayoutInflater;
 import android.view.View;
 
@@ -44,7 +42,6 @@
 
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
-@RunWithLooper
 public class NotificationBigPictureTemplateViewWrapperTest extends SysuiTestCase {
 
     private View mView;
@@ -53,11 +50,7 @@
 
     @Before
     public void setup() throws Exception {
-        allowTestableLooperAsMainThread();
-        NotificationTestHelper helper = new NotificationTestHelper(
-                mContext,
-                mDependency,
-                TestableLooper.get(this));
+        NotificationTestHelper helper = new NotificationTestHelper(mContext, mDependency);
         mView = LayoutInflater.from(mContext).inflate(
                 com.android.internal.R.layout.notification_template_material_big_picture, null);
         mRow = helper.createRow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
index 3fa68bb..fe2971c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
@@ -18,8 +18,6 @@
 
 import android.graphics.drawable.AnimatedImageDrawable
 import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
 import android.view.View
 import androidx.test.filters.SmallTest
 import com.android.internal.R
@@ -41,7 +39,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
-@RunWithLooper
 class NotificationConversationTemplateViewWrapperTest : SysuiTestCase() {
 
     private lateinit var mRow: ExpandableNotificationRow
@@ -49,8 +46,7 @@
 
     @Before
     fun setUp() {
-        allowTestableLooperAsMainThread()
-        helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+        helper = NotificationTestHelper(mContext, mDependency)
         mRow = helper.createRow()
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
index 45f7c5a..2d72c7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
@@ -17,8 +17,6 @@
 package com.android.systemui.statusbar.notification.row.wrapper;
 
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
 import android.view.View;
 import android.widget.RemoteViews;
 
@@ -36,18 +34,13 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@RunWithLooper
 public class NotificationCustomViewWrapperTest extends SysuiTestCase {
 
     private ExpandableNotificationRow mRow;
 
     @Before
     public void setUp() throws Exception {
-        allowTestableLooperAsMainThread();
-        NotificationTestHelper helper = new NotificationTestHelper(
-                mContext,
-                mDependency,
-                TestableLooper.get(this));
+        NotificationTestHelper helper = new NotificationTestHelper(mContext, mDependency);
         mRow = helper.createRow();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
index c0444b5..f26c18b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
@@ -18,8 +18,6 @@
 
 import android.graphics.drawable.AnimatedImageDrawable
 import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
 import android.view.View
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.MessagingGroup
@@ -39,7 +37,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
-@RunWithLooper
 class NotificationMessagingTemplateViewWrapperTest : SysuiTestCase() {
 
     private lateinit var mRow: ExpandableNotificationRow
@@ -47,8 +44,7 @@
 
     @Before
     fun setUp() {
-        allowTestableLooperAsMainThread()
-        helper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+        helper = NotificationTestHelper(mContext, mDependency)
         mRow = helper.createRow()
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
index f7632aa..54eed26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
@@ -69,7 +69,7 @@
             TestUiOffloadThread(looper.looper)
         )
 
-        helper = NotificationTestHelper(mContext, mDependency, looper)
+        helper = NotificationTestHelper(mContext, mDependency)
         row = helper.createRow()
         // Some code in the view iterates through parents so we need some extra containers around
         // it.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
index 93a9e59..e3a77d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
@@ -39,7 +39,6 @@
 
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
-@RunWithLooper
 public class NotificationViewWrapperTest extends SysuiTestCase {
 
     private View mView;
@@ -48,13 +47,9 @@
 
     @Before
     public void setup() throws Exception {
-        allowTestableLooperAsMainThread();
         mView = mock(View.class);
         when(mView.getContext()).thenReturn(mContext);
-        NotificationTestHelper helper = new NotificationTestHelper(
-                mContext,
-                mDependency,
-                TestableLooper.get(this));
+        NotificationTestHelper helper = new NotificationTestHelper(mContext, mDependency);
         mRow = helper.createRow();
         mNotificationViewWrapper = new TestableNotificationViewWrapper(mContext, mView, mRow);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index 138e1fa..c308a98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -130,35 +130,35 @@
         }
 
     @Test
-    fun testShouldShowEmptyShadeView_trueWhenNoNotifs() =
+    fun testShouldIncludeEmptyShadeView_trueWhenNoNotifs() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+            val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
             // WHEN has no notifs
             activeNotificationListRepository.setActiveNotifs(count = 0)
             runCurrent()
 
             // THEN empty shade is visible
-            assertThat(shouldShow).isTrue()
+            assertThat(shouldInclude).isTrue()
         }
 
     @Test
-    fun testShouldShowEmptyShadeView_falseWhenNotifs() =
+    fun testShouldIncludeEmptyShadeView_falseWhenNotifs() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+            val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
             runCurrent()
 
             // THEN empty shade is not visible
-            assertThat(shouldShow).isFalse()
+            assertThat(shouldInclude).isFalse()
         }
 
     @Test
-    fun testShouldShowEmptyShadeView_falseWhenQsExpandedDefault() =
+    fun testShouldIncludeEmptyShadeView_falseWhenQsExpandedDefault() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+            val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
             // WHEN has no notifs
             activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -167,13 +167,13 @@
             runCurrent()
 
             // THEN empty shade is not visible
-            assertThat(shouldShow).isFalse()
+            assertThat(shouldInclude).isFalse()
         }
 
     @Test
-    fun testShouldShowEmptyShadeView_trueWhenQsExpandedInSplitShade() =
+    fun testShouldIncludeEmptyShadeView_trueWhenQsExpandedInSplitShade() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+            val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
             // WHEN has no notifs
             activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -185,13 +185,13 @@
             runCurrent()
 
             // THEN empty shade is visible
-            assertThat(shouldShow).isTrue()
+            assertThat(shouldInclude).isTrue()
         }
 
     @Test
-    fun testShouldShowEmptyShadeView_trueWhenLockedShade() =
+    fun testShouldIncludeEmptyShadeView_trueWhenLockedShade() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+            val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
             // WHEN has no notifs
             activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -200,13 +200,13 @@
             runCurrent()
 
             // THEN empty shade is visible
-            assertThat(shouldShow).isTrue()
+            assertThat(shouldInclude).isTrue()
         }
 
     @Test
-    fun testShouldShowEmptyShadeView_falseWhenKeyguard() =
+    fun testShouldIncludeEmptyShadeView_falseWhenKeyguard() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+            val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
             // WHEN has no notifs
             activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -215,13 +215,13 @@
             runCurrent()
 
             // THEN empty shade is not visible
-            assertThat(shouldShow).isFalse()
+            assertThat(shouldInclude).isFalse()
         }
 
     @Test
-    fun testShouldShowEmptyShadeView_falseWhenStartingToSleep() =
+    fun testShouldIncludeEmptyShadeView_falseWhenStartingToSleep() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowEmptyShadeView)
+            val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
             // WHEN has no notifs
             activeNotificationListRepository.setActiveNotifs(count = 0)
@@ -232,7 +232,7 @@
             runCurrent()
 
             // THEN empty shade is not visible
-            assertThat(shouldShow).isFalse()
+            assertThat(shouldInclude).isFalse()
         }
 
     @Test
@@ -282,9 +282,9 @@
         }
 
     @Test
-    fun testShouldShowFooterView_trueWhenShade() =
+    fun testShouldIncludeFooterView_trueWhenShade() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -294,13 +294,13 @@
             runCurrent()
 
             // THEN footer is visible
-            assertThat(shouldShow?.value).isTrue()
+            assertThat(shouldInclude?.value).isTrue()
         }
 
     @Test
-    fun testShouldShowFooterView_trueWhenLockedShade() =
+    fun testShouldIncludeFooterView_trueWhenLockedShade() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -310,13 +310,13 @@
             runCurrent()
 
             // THEN footer is visible
-            assertThat(shouldShow?.value).isTrue()
+            assertThat(shouldInclude?.value).isTrue()
         }
 
     @Test
-    fun testShouldShowFooterView_falseWhenKeyguard() =
+    fun testShouldIncludeFooterView_falseWhenKeyguard() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -325,13 +325,13 @@
             runCurrent()
 
             // THEN footer is not visible
-            assertThat(shouldShow?.value).isFalse()
+            assertThat(shouldInclude?.value).isFalse()
         }
 
     @Test
-    fun testShouldShowFooterView_falseWhenUserNotSetUp() =
+    fun testShouldIncludeFooterView_falseWhenUserNotSetUp() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -343,13 +343,13 @@
             runCurrent()
 
             // THEN footer is not visible
-            assertThat(shouldShow?.value).isFalse()
+            assertThat(shouldInclude?.value).isFalse()
         }
 
     @Test
-    fun testShouldShowFooterView_falseWhenStartingToSleep() =
+    fun testShouldIncludeFooterView_falseWhenStartingToSleep() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -361,13 +361,13 @@
             runCurrent()
 
             // THEN footer is not visible
-            assertThat(shouldShow?.value).isFalse()
+            assertThat(shouldInclude?.value).isFalse()
         }
 
     @Test
-    fun testShouldShowFooterView_falseWhenQsExpandedDefault() =
+    fun testShouldIncludeFooterView_falseWhenQsExpandedDefault() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -380,13 +380,13 @@
             runCurrent()
 
             // THEN footer is not visible
-            assertThat(shouldShow?.value).isFalse()
+            assertThat(shouldInclude?.value).isFalse()
         }
 
     @Test
-    fun testShouldShowFooterView_trueWhenQsExpandedSplitShade() =
+    fun testShouldIncludeFooterView_trueWhenQsExpandedSplitShade() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -401,13 +401,13 @@
             runCurrent()
 
             // THEN footer is visible
-            assertThat(shouldShow?.value).isTrue()
+            assertThat(shouldInclude?.value).isTrue()
         }
 
     @Test
-    fun testShouldShowFooterView_falseWhenRemoteInputActive() =
+    fun testShouldIncludeFooterView_falseWhenRemoteInputActive() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -419,29 +419,13 @@
             runCurrent()
 
             // THEN footer is not visible
-            assertThat(shouldShow?.value).isFalse()
+            assertThat(shouldInclude?.value).isFalse()
         }
 
     @Test
-    fun testShouldShowFooterView_falseWhenShadeIsClosed() =
+    fun testShouldIncludeFooterView_animatesWhenShade() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
-
-            // WHEN has notifs
-            activeNotificationListRepository.setActiveNotifs(count = 2)
-            // AND shade is closed
-            fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
-            fakeShadeRepository.setLegacyShadeExpansion(0f)
-            runCurrent()
-
-            // THEN footer is not visible
-            assertThat(shouldShow?.value).isFalse()
-        }
-
-    @Test
-    fun testShouldShowFooterView_animatesWhenShade() =
-        testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -451,13 +435,13 @@
             runCurrent()
 
             // THEN footer visibility animates
-            assertThat(shouldShow?.isAnimating).isTrue()
+            assertThat(shouldInclude?.isAnimating).isTrue()
         }
 
     @Test
-    fun testShouldShowFooterView_notAnimatingOnKeyguard() =
+    fun testShouldIncludeFooterView_notAnimatingOnKeyguard() =
         testScope.runTest {
-            val shouldShow by collectLastValue(underTest.shouldShowFooterView)
+            val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
             // WHEN has notifs
             activeNotificationListRepository.setActiveNotifs(count = 2)
@@ -467,7 +451,35 @@
             runCurrent()
 
             // THEN footer visibility does not animate
-            assertThat(shouldShow?.isAnimating).isFalse()
+            assertThat(shouldInclude?.isAnimating).isFalse()
+        }
+
+    @Test
+    fun testShouldHideFooterView_trueWhenShadeIsClosed() =
+        testScope.runTest {
+            val shouldHide by collectLastValue(underTest.shouldHideFooterView)
+
+            // WHEN shade is closed
+            fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            fakeShadeRepository.setLegacyShadeExpansion(0f)
+            runCurrent()
+
+            // THEN footer is hidden
+            assertThat(shouldHide).isTrue()
+        }
+
+    @Test
+    fun testShouldHideFooterView_falseWhenShadeIsOpen() =
+        testScope.runTest {
+            val shouldHide by collectLastValue(underTest.shouldHideFooterView)
+
+            // WHEN shade is open
+            fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            fakeShadeRepository.setLegacyShadeExpansion(1f)
+            runCurrent()
+
+            // THEN footer is hidden
+            assertThat(shouldHide).isFalse()
         }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index 9855651..f761bcf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -868,6 +868,24 @@
         }
 
     @Test
+    fun networkName_usingEagerStrategy_retainsNameBetweenSubscribers() =
+        testScope.runTest {
+            // Use the [StateFlow.value] getter so we can prove that the collection happens
+            // even when there is no [Job]
+
+            // Starts out default
+            assertThat(underTest.networkName.value).isEqualTo(DEFAULT_NAME_MODEL)
+
+            val intent = spnIntent()
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.value!!.onReceive(context, intent)
+
+            // The value is still there despite no active subscribers
+            assertThat(underTest.networkName.value).isEqualTo(intent.toNetworkNameModel(SEP))
+        }
+
+    @Test
     fun operatorAlphaShort_tracked() =
         testScope.runTest {
             var latest: String? = null
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index e861892..c879588 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -19,6 +19,7 @@
 package com.android.systemui.kosmos
 
 import android.content.applicationContext
+import android.os.fakeExecutorHandler
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.bouncerRepository
 import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
@@ -27,6 +28,7 @@
 import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.communal.data.repository.fakeCommunalRepository
 import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.concurrency.fakeExecutor
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.flags.fakeFeatureFlagsClassic
@@ -65,6 +67,8 @@
     val testScope by lazy { kosmos.testScope }
     val fakeFeatureFlags by lazy { kosmos.fakeFeatureFlagsClassic }
     val fakeSceneContainerFlags by lazy { kosmos.fakeSceneContainerFlags }
+    val fakeExecutor by lazy { kosmos.fakeExecutor }
+    val fakeExecutorHandler by lazy { kosmos.fakeExecutorHandler }
     val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
     val configurationInteractor by lazy { kosmos.configurationInteractor }
     val bouncerRepository by lazy { kosmos.bouncerRepository }
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
index 532db12..c130cee 100644
--- a/services/autofill/features.aconfig
+++ b/services/autofill/features.aconfig
@@ -16,6 +16,7 @@
 
 flag {
     name: "autofill_credman_dev_integration"
+    is_exported: true
     namespace: "autofill"
     description: "Guards against Autofill-Credman Phase1 developer integration via new APIs"
     bug: "320730001"
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 53c0f58..0f951746 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -12360,7 +12360,8 @@
     }
 
     private boolean callerHasPermission(String permission) {
-        return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
+        return mContext.checkCallingOrSelfPermission(permission)
+                == PackageManager.PERMISSION_GRANTED;
     }
 
     /** @return true if projection is a valid MediaProjection that can project audio. */
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 04e7f77..851d197 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -894,6 +894,7 @@
     @Nullable
     private HdrBrightnessData mHdrBrightnessData;
 
+    // Null if low brightness mode is disabled - in config or by flag.
     @Nullable
     public LowBrightnessData mLowBrightnessData;
 
@@ -1063,6 +1064,9 @@
      * @return The brightness mapping nits array.
      */
     public float[] getNits() {
+        if (mLowBrightnessData != null) {
+            return mLowBrightnessData.mNits;
+        }
         return mNits;
     }
 
@@ -1071,7 +1075,11 @@
      *
      * @return The backlight mapping value array.
      */
+    @VisibleForTesting
     public float[] getBacklight() {
+        if (mLowBrightnessData != null) {
+            return mLowBrightnessData.mBacklight;
+        }
         return mBacklight;
     }
 
@@ -1083,9 +1091,26 @@
      * @return backlight value on the HAL scale of 0-1
      */
     public float getBacklightFromBrightness(float brightness) {
+        if (mLowBrightnessData != null) {
+            return mLowBrightnessData.mBrightnessToBacklight.interpolate(brightness);
+        }
         return mBrightnessToBacklightSpline.interpolate(brightness);
     }
 
+    private float getBrightnessFromBacklight(float brightness) {
+        if (mLowBrightnessData != null) {
+            return mLowBrightnessData.mBacklightToBrightness.interpolate(brightness);
+        }
+        return mBacklightToBrightnessSpline.interpolate(brightness);
+    }
+
+    private Spline getBacklightToBrightnessSpline() {
+        if (mLowBrightnessData != null) {
+            return mLowBrightnessData.mBacklightToBrightness;
+        }
+        return mBacklightToBrightnessSpline;
+    }
+
     /**
      * Calculates the nits value for the specified backlight value if a mapping exists.
      *
@@ -1093,6 +1118,14 @@
      * exits.
      */
     public float getNitsFromBacklight(float backlight) {
+        if (mLowBrightnessData != null) {
+            if (mLowBrightnessData.mBacklightToNits == null) {
+                return INVALID_NITS;
+            }
+            backlight = Math.max(backlight, mBacklightMinimum);
+            return mLowBrightnessData.mBacklightToNits.interpolate(backlight);
+        }
+
         if (mBacklightToNitsSpline == null) {
             return INVALID_NITS;
         }
@@ -1100,6 +1133,20 @@
         return mBacklightToNitsSpline.interpolate(backlight);
     }
 
+    private float getBacklightFromNits(float nits) {
+        if (mLowBrightnessData != null) {
+            return mLowBrightnessData.mNitsToBacklight.interpolate(nits);
+        }
+        return mNitsToBacklightSpline.interpolate(nits);
+    }
+
+    private Spline getNitsToBacklightSpline() {
+        if (mLowBrightnessData != null) {
+            return mLowBrightnessData.mNitsToBacklight;
+        }
+        return mNitsToBacklightSpline;
+    }
+
     /**
      * @return true if there is sdrHdrRatioMap, false otherwise.
      */
@@ -1126,13 +1173,13 @@
 
         float ratio = Math.min(mSdrToHdrRatioSpline.interpolate(nits), maxDesiredHdrSdrRatio);
         float hdrNits = nits * ratio;
-        if (mNitsToBacklightSpline == null) {
+        if (getNitsToBacklightSpline() == null) {
             return PowerManager.BRIGHTNESS_INVALID;
         }
 
-        float hdrBacklight = mNitsToBacklightSpline.interpolate(hdrNits);
+        float hdrBacklight = getBacklightFromNits(hdrNits);
         hdrBacklight = Math.max(mBacklightMinimum, Math.min(mBacklightMaximum, hdrBacklight));
-        float hdrBrightness = mBacklightToBrightnessSpline.interpolate(hdrBacklight);
+        float hdrBrightness = getBrightnessFromBacklight(hdrBacklight);
 
         if (DEBUG) {
             Slog.d(TAG, "getHdrBrightnessFromSdr: sdr brightness " + brightness
@@ -1154,6 +1201,9 @@
      * @return brightness array
      */
     public float[] getBrightness() {
+        if (mLowBrightnessData != null) {
+            return mLowBrightnessData.mBrightness;
+        }
         return mBrightness;
     }
 
@@ -1987,7 +2037,8 @@
                 + "mHdrBrightnessData= " + mHdrBrightnessData + "\n"
                 + "mBrightnessCapForWearBedtimeMode= " + mBrightnessCapForWearBedtimeMode
                 + "\n"
-                + (mLowBrightnessData != null ? mLowBrightnessData.toString() : "")
+                + "mLowBrightnessData:" + (mLowBrightnessData != null
+                ? mLowBrightnessData.toString() : "null")
                 + "}";
     }
 
@@ -2588,9 +2639,9 @@
                     // A negative value means that there's no threshold
                     mLowDisplayBrightnessThresholds[i] = thresholdNits;
                 } else {
-                    float thresholdBacklight = mNitsToBacklightSpline.interpolate(thresholdNits);
+                    float thresholdBacklight = getBacklightFromNits(thresholdNits);
                     mLowDisplayBrightnessThresholds[i] =
-                            mBacklightToBrightnessSpline.interpolate(thresholdBacklight);
+                            getBrightnessFromBacklight(thresholdBacklight);
                 }
 
                 mLowAmbientBrightnessThresholds[i] = lowerThresholdDisplayBrightnessPoints
@@ -2639,9 +2690,9 @@
                     // A negative value means that there's no threshold
                     mHighDisplayBrightnessThresholds[i] = thresholdNits;
                 } else {
-                    float thresholdBacklight = mNitsToBacklightSpline.interpolate(thresholdNits);
+                    float thresholdBacklight = getBacklightFromNits(thresholdNits);
                     mHighDisplayBrightnessThresholds[i] =
-                            mBacklightToBrightnessSpline.interpolate(thresholdBacklight);
+                            getBrightnessFromBacklight(thresholdBacklight);
                 }
 
                 mHighAmbientBrightnessThresholds[i] = higherThresholdDisplayBrightnessPoints
@@ -2658,7 +2709,7 @@
         loadAutoBrightnessBrighteningLightDebounceIdle(autoBrightness);
         loadAutoBrightnessDarkeningLightDebounceIdle(autoBrightness);
         mDisplayBrightnessMapping = new DisplayBrightnessMappingConfig(mContext, mFlags,
-                autoBrightness, mBacklightToBrightnessSpline);
+                autoBrightness, getBacklightToBrightnessSpline());
         loadEnableAutoBrightness(autoBrightness);
     }
 
@@ -2832,17 +2883,10 @@
     // These splines are used to convert from the system brightness value to the HAL backlight
     // value
     private void createBacklightConversionSplines() {
-        if (mLowBrightnessData != null) {
-            mBrightnessToBacklightSpline = mLowBrightnessData.mBrightnessToBacklight;
-            mBacklightToBrightnessSpline = mLowBrightnessData.mBacklightToBrightness;
-            mBacklightToNitsSpline = mLowBrightnessData.mBacklightToNits;
-            mNitsToBacklightSpline = mLowBrightnessData.mNitsToBacklight;
 
-            mNits = mLowBrightnessData.mNits;
-            mBrightness = mLowBrightnessData.mBrightness;
-            mBacklight = mLowBrightnessData.mBacklight;
-            return;
-        }
+
+        // Create original brightness splines - not using low brightness mode arrays - this is
+        // so that we can continue to log the original brightness splines.
 
         mBrightness = new float[mBacklight.length];
         for (int i = 0; i < mBrightness.length; i++) {
@@ -2884,7 +2928,7 @@
                         + mBacklightMaximum);
             }
             mHbmData.transitionPoint =
-                    mBacklightToBrightnessSpline.interpolate(transitionPointBacklightScale);
+                    getBrightnessFromBacklight(transitionPointBacklightScale);
             final HbmTiming hbmTiming = hbm.getTiming_all();
             mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
             mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
@@ -2953,7 +2997,7 @@
                         continue;
                     }
                     luxToTransitionPointMap.put(lux,
-                            mBacklightToBrightnessSpline.interpolate(maxBrightness));
+                            getBrightnessFromBacklight(maxBrightness));
                 }
                 if (!luxToTransitionPointMap.isEmpty()) {
                     mLuxThrottlingData.put(mappedType, luxToTransitionPointMap);
@@ -3048,7 +3092,7 @@
 
     private void loadAutoBrightnessConfigsFromConfigXml() {
         mDisplayBrightnessMapping = new DisplayBrightnessMappingConfig(mContext, mFlags,
-                /* autoBrightnessConfig= */ null, mBacklightToBrightnessSpline);
+                /* autoBrightnessConfig= */ null, getBacklightToBrightnessSpline());
     }
 
     private void loadBrightnessChangeThresholdsFromXml() {
diff --git a/services/core/java/com/android/server/feature/dropbox_flags.aconfig b/services/core/java/com/android/server/feature/dropbox_flags.aconfig
index fee4bf3..14e964b 100644
--- a/services/core/java/com/android/server/feature/dropbox_flags.aconfig
+++ b/services/core/java/com/android/server/feature/dropbox_flags.aconfig
@@ -2,6 +2,7 @@
 
 flag{
     name: "enable_read_dropbox_permission"
+    is_exported: true
     namespace: "preload_safety"
     description: "Feature flag for permission to Read dropbox data"
     bug: "287512663"
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index b2e01c5..c42ccea 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "power_monitor_api"
+    is_exported: true
     namespace: "backstage_power"
     description: "Feature flag for ODPM API"
     bug: "295027807"
diff --git a/services/core/java/com/android/server/webkit/flags.aconfig b/services/core/java/com/android/server/webkit/flags.aconfig
index 1411acc..2afbcd6 100644
--- a/services/core/java/com/android/server/webkit/flags.aconfig
+++ b/services/core/java/com/android/server/webkit/flags.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "update_service_v2"
+    is_exported: true
     namespace: "webview"
     description: "Using a new version of the WebView update service"
     bug: "308907090"
diff --git a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
index 5460e4e87..64dbe71 100644
--- a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
+++ b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
@@ -43,6 +43,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -392,6 +393,7 @@
     }
 
     @Test
+    @Ignore("Can be enabled only after b/330536267 is ready")
     public void testChoreographerDivisorRefreshRate() {
         for (int divisor : new int[]{2, 3}) {
             CountDownLatch continueLatch = new CountDownLatch(1);
@@ -420,6 +422,7 @@
     }
 
     @Test
+    @Ignore("Can be enabled only after b/330536267 is ready")
     public void testChoreographerAttachedAfterSetFrameRate() {
         Log.i(TAG, "starting testChoreographerAttachedAfterSetFrameRate");
 
diff --git a/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java b/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java
index df003b6..fb7a6ab 100644
--- a/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java
+++ b/tools/app_metadata_bundles/src/aslgen/java/com/android/aslgen/Main.java
@@ -18,6 +18,7 @@
 
 import com.android.asllib.AndroidSafetyLabel;
 import com.android.asllib.AndroidSafetyLabel.Format;
+import com.android.asllib.util.MalformedXmlException;
 
 import org.xml.sax.SAXException;
 
@@ -32,7 +33,11 @@
 
     /** Takes the options to make file conversion. */
     public static void main(String[] args)
-            throws IOException, ParserConfigurationException, SAXException, TransformerException {
+            throws IOException,
+                    ParserConfigurationException,
+                    SAXException,
+                    TransformerException,
+                    MalformedXmlException {
 
         String inFile = null;
         String outFile = null;
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java
index 0f7ce68..bc8063e 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabel.java
@@ -16,6 +16,8 @@
 
 package com.android.asllib;
 
+import com.android.asllib.util.MalformedXmlException;
+
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.xml.sax.SAXException;
@@ -53,7 +55,7 @@
     /** Reads a {@link AndroidSafetyLabel} from an {@link InputStream}. */
     // TODO(b/329902686): Support parsing from on-device.
     public static AndroidSafetyLabel readFromStream(InputStream in, Format format)
-            throws IOException, ParserConfigurationException, SAXException {
+            throws IOException, ParserConfigurationException, SAXException, MalformedXmlException {
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         factory.setNamespaceAware(true);
         Document document = factory.newDocumentBuilder().parse(in);
@@ -65,9 +67,9 @@
 
                 return new AndroidSafetyLabelFactory()
                         .createFromHrElements(
-                                XmlUtils.asElementList(
-                                        document.getElementsByTagName(
-                                                XmlUtils.HR_TAG_APP_METADATA_BUNDLES)));
+                                List.of(
+                                        XmlUtils.getSingleElement(
+                                                document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES)));
             case ON_DEVICE:
                 throw new IllegalArgumentException(
                         "Parsing from on-device format is not supported at this time.");
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java
index 9b0f05b..7e7fcf9 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AndroidSafetyLabelFactory.java
@@ -16,6 +16,8 @@
 
 package com.android.asllib;
 
+import com.android.asllib.util.MalformedXmlException;
+
 import org.w3c.dom.Element;
 
 import java.util.List;
@@ -24,7 +26,8 @@
 
     /** Creates an {@link AndroidSafetyLabel} from human-readable DOM element */
     @Override
-    public AndroidSafetyLabel createFromHrElements(List<Element> appMetadataBundles) {
+    public AndroidSafetyLabel createFromHrElements(List<Element> appMetadataBundles)
+            throws MalformedXmlException {
         Element appMetadataBundlesEle = XmlUtils.getSingleElement(appMetadataBundles);
         Element safetyLabelsEle =
                 XmlUtils.getSingleChildElement(
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallableFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallableFactory.java
index b607353..b8f9f0e 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallableFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslMarshallableFactory.java
@@ -16,6 +16,8 @@
 
 package com.android.asllib;
 
+import com.android.asllib.util.MalformedXmlException;
+
 import org.w3c.dom.Element;
 
 import java.util.List;
@@ -23,5 +25,5 @@
 public interface AslMarshallableFactory<T extends AslMarshallable> {
 
     /** Creates an {@link AslMarshallableFactory} from human-readable DOM element */
-    T createFromHrElements(List<Element> elements);
+    T createFromHrElements(List<Element> elements) throws MalformedXmlException;
 }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java
index 5a52591..d946345 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataCategoryFactory.java
@@ -16,6 +16,8 @@
 
 package com.android.asllib;
 
+import com.android.asllib.util.MalformedXmlException;
+
 import org.w3c.dom.Element;
 
 import java.util.HashMap;
@@ -24,12 +26,16 @@
 
 public class DataCategoryFactory implements AslMarshallableFactory<DataCategory> {
     @Override
-    public DataCategory createFromHrElements(List<Element> elements) {
+    public DataCategory createFromHrElements(List<Element> elements) throws MalformedXmlException {
         String categoryName = null;
         Map<String, DataType> dataTypeMap = new HashMap<String, DataType>();
         for (Element ele : elements) {
             categoryName = ele.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY);
             String dataTypeName = ele.getAttribute(XmlUtils.HR_ATTR_DATA_TYPE);
+            if (!DataTypeConstants.getValidDataTypes().contains(dataTypeName)) {
+                throw new MalformedXmlException(
+                        String.format("Unrecognized data type name: %s", dataTypeName));
+            }
             dataTypeMap.put(dataTypeName, new DataTypeFactory().createFromHrElements(List.of(ele)));
         }
 
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java
index c758ab9..1adb140 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataLabelsFactory.java
@@ -16,6 +16,8 @@
 
 package com.android.asllib;
 
+import com.android.asllib.util.MalformedXmlException;
+
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
@@ -29,7 +31,7 @@
 
     /** Creates a {@link DataLabels} from the human-readable DOM element. */
     @Override
-    public DataLabels createFromHrElements(List<Element> elements) {
+    public DataLabels createFromHrElements(List<Element> elements) throws MalformedXmlException {
         Element ele = XmlUtils.getSingleElement(elements);
         Map<String, DataCategory> dataAccessed =
                 getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_ACCESSED);
@@ -37,13 +39,54 @@
                 getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_COLLECTED);
         Map<String, DataCategory> dataShared =
                 getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_SHARED);
+
+        // Validate booleans such as isCollectionOptional, isSharingOptional.
+        for (DataCategory dataCategory : dataAccessed.values()) {
+            for (DataType dataType : dataCategory.getDataTypes().values()) {
+                if (dataType.getIsSharingOptional() != null) {
+                    throw new MalformedXmlException(
+                            String.format(
+                                    "isSharingOptional was unexpectedly defined on a DataType"
+                                            + " belonging to data accessed: %s",
+                                    dataType.getDataTypeName()));
+                }
+                if (dataType.getIsCollectionOptional() != null) {
+                    throw new MalformedXmlException(
+                            String.format(
+                                    "isCollectionOptional was unexpectedly defined on a DataType"
+                                            + " belonging to data accessed: %s",
+                                    dataType.getDataTypeName()));
+                }
+            }
+        }
+        for (DataCategory dataCategory : dataCollected.values()) {
+            for (DataType dataType : dataCategory.getDataTypes().values()) {
+                if (dataType.getIsSharingOptional() != null) {
+                    throw new MalformedXmlException(
+                            String.format(
+                                    "isSharingOptional was unexpectedly defined on a DataType"
+                                            + " belonging to data collected: %s",
+                                    dataType.getDataTypeName()));
+                }
+            }
+        }
+        for (DataCategory dataCategory : dataShared.values()) {
+            for (DataType dataType : dataCategory.getDataTypes().values()) {
+                if (dataType.getIsCollectionOptional() != null) {
+                    throw new MalformedXmlException(
+                            String.format(
+                                    "isCollectionOptional was unexpectedly defined on a DataType"
+                                            + " belonging to data shared: %s",
+                                    dataType.getDataTypeName()));
+                }
+            }
+        }
+
         return new DataLabels(dataAccessed, dataCollected, dataShared);
     }
 
     private static Map<String, DataCategory> getDataCategoriesWithTag(
-            Element dataLabelsEle, String dataCategoryUsageTypeTag) {
-        Map<String, Map<String, DataType>> dataTypeMap =
-                new HashMap<String, Map<String, DataType>>();
+            Element dataLabelsEle, String dataCategoryUsageTypeTag) throws MalformedXmlException {
         NodeList dataUsedNodeList = dataLabelsEle.getElementsByTagName(dataCategoryUsageTypeTag);
         Map<String, DataCategory> dataCategoryMap = new HashMap<String, DataCategory>();
 
@@ -51,6 +94,10 @@
         for (int i = 0; i < dataUsedNodeList.getLength(); i++) {
             Element dataUsedEle = (Element) dataUsedNodeList.item(i);
             String dataCategoryName = dataUsedEle.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY);
+            if (!DataCategoryConstants.getValidDataCategories().contains(dataCategoryName)) {
+                throw new MalformedXmlException(
+                        String.format("Unrecognized category name: %s", dataCategoryName));
+            }
             dataCategoryNames.add(dataCategoryName);
         }
         for (String dataCategoryName : dataCategoryNames) {
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java
index 99f8a8b..e3d1587 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/DataTypeFactory.java
@@ -35,10 +35,10 @@
                         .collect(Collectors.toUnmodifiableSet());
         Boolean isCollectionOptional =
                 XmlUtils.fromString(
-                        hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_IS_SHARING_OPTIONAL));
+                        hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_IS_COLLECTION_OPTIONAL));
         Boolean isSharingOptional =
                 XmlUtils.fromString(
-                        hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_IS_COLLECTION_OPTIONAL));
+                        hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_IS_SHARING_OPTIONAL));
         Boolean ephemeral =
                 XmlUtils.fromString(hrDataTypeEle.getAttribute(XmlUtils.HR_ATTR_EPHEMERAL));
         return new DataType(
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java
index 68e83fe..80b9f57 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/SafetyLabelsFactory.java
@@ -16,6 +16,8 @@
 
 package com.android.asllib;
 
+import com.android.asllib.util.MalformedXmlException;
+
 import org.w3c.dom.Element;
 
 import java.util.List;
@@ -24,7 +26,7 @@
 
     /** Creates a {@link SafetyLabels} from the human-readable DOM element. */
     @Override
-    public SafetyLabels createFromHrElements(List<Element> elements) {
+    public SafetyLabels createFromHrElements(List<Element> elements) throws MalformedXmlException {
         Element safetyLabelsEle = XmlUtils.getSingleElement(elements);
         Long version;
         try {
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java
index 3c89a30..3bc9ccc 100644
--- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/XmlUtils.java
@@ -16,6 +16,8 @@
 
 package com.android.asllib;
 
+import com.android.asllib.util.MalformedXmlException;
+
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
@@ -61,30 +63,34 @@
     public static final String FALSE_STR = "false";
 
     /** Gets the single top-level {@link Element} having the {@param tagName}. */
-    public static Element getSingleElement(Document doc, String tagName) {
+    public static Element getSingleElement(Document doc, String tagName)
+            throws MalformedXmlException {
         var elements = doc.getElementsByTagName(tagName);
-        return getSingleElement(elements);
+        return getSingleElement(elements, tagName);
     }
 
     /**
      * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}.
      */
-    public static Element getSingleChildElement(Element parentEle, String tagName) {
+    public static Element getSingleChildElement(Element parentEle, String tagName)
+            throws MalformedXmlException {
         var elements = parentEle.getElementsByTagName(tagName);
-        return getSingleElement(elements);
+        return getSingleElement(elements, tagName);
     }
 
     /** Gets the single {@link Element} from {@param elements} */
-    public static Element getSingleElement(NodeList elements) {
+    public static Element getSingleElement(NodeList elements, String tagName)
+            throws MalformedXmlException {
         if (elements.getLength() != 1) {
-            throw new IllegalArgumentException(
+            throw new MalformedXmlException(
                     String.format(
-                            "Expected 1 element in NodeList but got %s.", elements.getLength()));
+                            "Expected 1 element \"%s\" in NodeList but got %s.",
+                            tagName, elements.getLength()));
         }
         var elementAsNode = elements.item(0);
         if (!(elementAsNode instanceof Element)) {
-            throw new IllegalStateException(
-                    String.format("%s was not an element.", elementAsNode.getNodeName()));
+            throw new MalformedXmlException(
+                    String.format("%s was not a valid XML element.", tagName));
         }
         return ((Element) elementAsNode);
     }
diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/MalformedXmlException.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/MalformedXmlException.java
new file mode 100644
index 0000000..216df56
--- /dev/null
+++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/MalformedXmlException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.asllib.util;
+
+public class MalformedXmlException extends Exception {
+    /** Constructs an {@code MalformedXmlException} with no detail message. */
+    public MalformedXmlException() {
+        super();
+    }
+
+    /**
+     * Constructs an {@code MalformedXmlException} with the specified detail message.
+     *
+     * @param s the detail message.
+     */
+    public MalformedXmlException(String s) {
+        super(s);
+    }
+}
diff --git a/wifi/wifi.aconfig b/wifi/wifi.aconfig
index 6ac986e..6c4e4c3 100644
--- a/wifi/wifi.aconfig
+++ b/wifi/wifi.aconfig
@@ -2,6 +2,7 @@
 
 flag {
     name: "get_device_cross_akm_roaming_support"
+    is_exported: true
     namespace: "wifi"
     description: "Add new API to get the device support for CROSS-AKM roaming"
     bug: "313038031"